Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : : #undef NDEBUG
19 : : #include "stp.h"
20 : : #include <assert.h>
21 : : #include <ctype.h>
22 : : #include <errno.h>
23 : : #include <inttypes.h>
24 : : #include <stdarg.h>
25 : : #include <stdlib.h>
26 : : #include "dp-packet.h"
27 : : #include "openvswitch/ofpbuf.h"
28 : : #include "ovstest.h"
29 : : #include "packets.h"
30 : : #include "openvswitch/vlog.h"
31 : :
32 : : struct bpdu {
33 : : int port_no;
34 : : void *data;
35 : : size_t size;
36 : : };
37 : :
38 : : struct bridge {
39 : : struct test_case *tc;
40 : : int id;
41 : : bool reached;
42 : :
43 : : struct stp *stp;
44 : :
45 : : struct lan *ports[STP_MAX_PORTS];
46 : : int n_ports;
47 : :
48 : : #define RXQ_SIZE 16
49 : : struct bpdu rxq[RXQ_SIZE];
50 : : int rxq_head, rxq_tail;
51 : : };
52 : :
53 : : struct lan_conn {
54 : : struct bridge *bridge;
55 : : int port_no;
56 : : };
57 : :
58 : : struct lan {
59 : : struct test_case *tc;
60 : : const char *name;
61 : : bool reached;
62 : : struct lan_conn conns[16];
63 : : int n_conns;
64 : : };
65 : :
66 : : struct test_case {
67 : : struct bridge *bridges[16];
68 : : int n_bridges;
69 : : struct lan *lans[26];
70 : : int n_lans;
71 : : };
72 : :
73 : : static const char *file_name;
74 : : static int line_number;
75 : : static char line[128];
76 : : static char *pos, *token;
77 : : static int n_warnings;
78 : :
79 : : static struct test_case *
80 : 13 : new_test_case(void)
81 : : {
82 : 13 : struct test_case *tc = xmalloc(sizeof *tc);
83 : 13 : tc->n_bridges = 0;
84 : 13 : tc->n_lans = 0;
85 : 13 : return tc;
86 : : }
87 : :
88 : : static void
89 : 15236 : send_bpdu(struct dp_packet *pkt, int port_no, void *b_)
90 : : {
91 : 15236 : struct bridge *b = b_;
92 : : struct lan *lan;
93 : :
94 [ - + ]: 15236 : assert(port_no < b->n_ports);
95 : 15236 : lan = b->ports[port_no];
96 [ + + ]: 15236 : if (lan) {
97 : 13774 : const void *data = dp_packet_l3(pkt);
98 : 13774 : size_t size = (char *) dp_packet_tail(pkt) - (char *) data;
99 : : int i;
100 : :
101 [ + + ]: 38130 : for (i = 0; i < lan->n_conns; i++) {
102 : 24356 : struct lan_conn *conn = &lan->conns[i];
103 [ + + ][ + + ]: 24356 : if (conn->bridge != b || conn->port_no != port_no) {
104 : 10582 : struct bridge *dst = conn->bridge;
105 : 10582 : struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE];
106 [ - + ]: 10582 : assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE);
107 : 10582 : bpdu->data = xmemdup(data, size);
108 : 10582 : bpdu->size = size;
109 : 10582 : bpdu->port_no = conn->port_no;
110 : : }
111 : : }
112 : : }
113 : 15236 : dp_packet_delete(pkt);
114 : 15236 : }
115 : :
116 : : static struct bridge *
117 : 44 : new_bridge(struct test_case *tc, int id)
118 : : {
119 : 44 : struct bridge *b = xmalloc(sizeof *b);
120 : : char name[16];
121 : 44 : b->tc = tc;
122 : 44 : b->id = id;
123 : 44 : snprintf(name, sizeof name, "stp%x", id);
124 : 44 : b->stp = stp_create(name, id, send_bpdu, b);
125 [ - + ]: 44 : assert(tc->n_bridges < ARRAY_SIZE(tc->bridges));
126 : 44 : b->n_ports = 0;
127 : 44 : b->rxq_head = b->rxq_tail = 0;
128 : 44 : tc->bridges[tc->n_bridges++] = b;
129 : 44 : return b;
130 : : }
131 : :
132 : : static struct lan *
133 : 338 : new_lan(struct test_case *tc, const char *name)
134 : : {
135 : 338 : struct lan *lan = xmalloc(sizeof *lan);
136 : 338 : lan->tc = tc;
137 : 338 : lan->name = xstrdup(name);
138 : 338 : lan->n_conns = 0;
139 [ - + ]: 338 : assert(tc->n_lans < ARRAY_SIZE(tc->lans));
140 : 338 : tc->lans[tc->n_lans++] = lan;
141 : 338 : return lan;
142 : : }
143 : :
144 : : static void
145 : 150 : reconnect_port(struct bridge *b, int port_no, struct lan *new_lan)
146 : : {
147 : : struct lan *old_lan;
148 : : int j;
149 : :
150 [ - + ]: 150 : assert(port_no < b->n_ports);
151 : 150 : old_lan = b->ports[port_no];
152 [ + + ]: 150 : if (old_lan == new_lan) {
153 : 18 : return;
154 : : }
155 : :
156 : : /* Disconnect from old_lan. */
157 [ + + ]: 132 : if (old_lan) {
158 [ + - ]: 4 : for (j = 0; j < old_lan->n_conns; j++) {
159 : 4 : struct lan_conn *c = &old_lan->conns[j];
160 [ + + ][ + - ]: 4 : if (c->bridge == b && c->port_no == port_no) {
161 : 2 : memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1));
162 : 2 : old_lan->n_conns--;
163 : 2 : break;
164 : : }
165 : : }
166 : : }
167 : :
168 : : /* Connect to new_lan. */
169 : 132 : b->ports[port_no] = new_lan;
170 [ + + ]: 132 : if (new_lan) {
171 : 130 : int conn_no = new_lan->n_conns++;
172 [ - + ]: 130 : assert(conn_no < ARRAY_SIZE(new_lan->conns));
173 : 130 : new_lan->conns[conn_no].bridge = b;
174 : 130 : new_lan->conns[conn_no].port_no = port_no;
175 : : }
176 : : }
177 : :
178 : : static void
179 : 136 : new_port(struct bridge *b, struct lan *lan, int path_cost)
180 : : {
181 : 136 : int port_no = b->n_ports++;
182 : 136 : struct stp_port *p = stp_get_port(b->stp, port_no);
183 [ - + ]: 136 : assert(port_no < ARRAY_SIZE(b->ports));
184 : 136 : b->ports[port_no] = NULL;
185 : 136 : stp_port_set_path_cost(p, path_cost);
186 : 136 : stp_port_enable(p);
187 : 136 : reconnect_port(b, port_no, lan);
188 : 136 : }
189 : :
190 : : static void
191 : 0 : dump(struct test_case *tc)
192 : : {
193 : : int i;
194 : :
195 [ # # ]: 0 : for (i = 0; i < tc->n_bridges; i++) {
196 : 0 : struct bridge *b = tc->bridges[i];
197 : 0 : struct stp *stp = b->stp;
198 : : int j;
199 : :
200 : 0 : printf("%s:", stp_get_name(stp));
201 [ # # ]: 0 : if (stp_is_root_bridge(stp)) {
202 : 0 : printf(" root");
203 : : }
204 : 0 : printf("\n");
205 [ # # ]: 0 : for (j = 0; j < b->n_ports; j++) {
206 : 0 : struct stp_port *p = stp_get_port(stp, j);
207 : 0 : enum stp_state state = stp_port_get_state(p);
208 : :
209 : 0 : printf("\tport %d", j);
210 [ # # ]: 0 : if (b->ports[j]) {
211 : 0 : printf(" (lan %s)", b->ports[j]->name);
212 : : } else {
213 : 0 : printf(" (disconnected)");
214 : : }
215 : 0 : printf(": %s", stp_state_name(state));
216 [ # # ]: 0 : if (p == stp_get_root_port(stp)) {
217 : 0 : printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp));
218 : : }
219 : 0 : printf("\n");
220 : : }
221 : : }
222 : 0 : }
223 : :
224 : : static void dump_lan_tree(struct test_case *, struct lan *, int level);
225 : :
226 : : static void
227 : 0 : dump_bridge_tree(struct test_case *tc, struct bridge *b, int level)
228 : : {
229 : : int i;
230 : :
231 [ # # ]: 0 : if (b->reached) {
232 : 0 : return;
233 : : }
234 : 0 : b->reached = true;
235 [ # # ]: 0 : for (i = 0; i < level; i++) {
236 : 0 : printf("\t");
237 : : }
238 : 0 : printf("%s\n", stp_get_name(b->stp));
239 [ # # ]: 0 : for (i = 0; i < b->n_ports; i++) {
240 : 0 : struct lan *lan = b->ports[i];
241 : 0 : struct stp_port *p = stp_get_port(b->stp, i);
242 [ # # ][ # # ]: 0 : if (stp_port_get_state(p) == STP_FORWARDING && lan) {
243 : 0 : dump_lan_tree(tc, lan, level + 1);
244 : : }
245 : : }
246 : : }
247 : :
248 : : static void
249 : 0 : dump_lan_tree(struct test_case *tc, struct lan *lan, int level)
250 : : {
251 : : int i;
252 : :
253 [ # # ]: 0 : if (lan->reached) {
254 : 0 : return;
255 : : }
256 : 0 : lan->reached = true;
257 [ # # ]: 0 : for (i = 0; i < level; i++) {
258 : 0 : printf("\t");
259 : : }
260 : 0 : printf("%s\n", lan->name);
261 [ # # ]: 0 : for (i = 0; i < lan->n_conns; i++) {
262 : 0 : struct bridge *b = lan->conns[i].bridge;
263 : 0 : dump_bridge_tree(tc, b, level + 1);
264 : : }
265 : : }
266 : :
267 : : static void
268 : 0 : tree(struct test_case *tc)
269 : : {
270 : : int i;
271 : :
272 [ # # ]: 0 : for (i = 0; i < tc->n_bridges; i++) {
273 : 0 : struct bridge *b = tc->bridges[i];
274 : 0 : b->reached = false;
275 : : }
276 [ # # ]: 0 : for (i = 0; i < tc->n_lans; i++) {
277 : 0 : struct lan *lan = tc->lans[i];
278 : 0 : lan->reached = false;
279 : : }
280 [ # # ]: 0 : for (i = 0; i < tc->n_bridges; i++) {
281 : 0 : struct bridge *b = tc->bridges[i];
282 : 0 : struct stp *stp = b->stp;
283 [ # # ]: 0 : if (stp_is_root_bridge(stp)) {
284 : 0 : dump_bridge_tree(tc, b, 0);
285 : : }
286 : : }
287 : 0 : }
288 : :
289 : : static void
290 : 23 : simulate(struct test_case *tc, int granularity)
291 : : {
292 : : int time;
293 : :
294 [ + + ]: 4163 : for (time = 0; time < 1000 * 180; time += granularity) {
295 : : int round_trips;
296 : : int i;
297 : :
298 [ + + ]: 18540 : for (i = 0; i < tc->n_bridges; i++) {
299 : 14400 : stp_tick(tc->bridges[i]->stp, granularity);
300 : : }
301 [ + - ]: 6898 : for (round_trips = 0; round_trips < granularity; round_trips++) {
302 : 6898 : bool any = false;
303 [ + + ]: 31811 : for (i = 0; i < tc->n_bridges; i++) {
304 : 24913 : struct bridge *b = tc->bridges[i];
305 [ + + ]: 35495 : for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) {
306 : 10582 : struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE];
307 : 10582 : stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no),
308 : 10582 : bpdu->data, bpdu->size);
309 : 10582 : free(bpdu->data);
310 : 10582 : any = true;
311 : : }
312 : : }
313 [ + + ]: 6898 : if (!any) {
314 : 4140 : break;
315 : : }
316 : : }
317 : : }
318 : 23 : }
319 : :
320 : : OVS_NO_RETURN static void
321 : : err(const char *message, ...)
322 : : OVS_PRINTF_FORMAT(1, 2);
323 : :
324 : : static void
325 : 0 : err(const char *message, ...)
326 : : {
327 : : va_list args;
328 : :
329 : 0 : fprintf(stderr, "%s:%d:%"PRIdPTR": ", file_name, line_number, pos - line);
330 : 0 : va_start(args, message);
331 : 0 : vfprintf(stderr, message, args);
332 : 0 : va_end(args);
333 : 0 : putc('\n', stderr);
334 : :
335 : 0 : exit(EXIT_FAILURE);
336 : : }
337 : :
338 : : static void
339 : : warn(const char *message, ...)
340 : : OVS_PRINTF_FORMAT(1, 2);
341 : :
342 : : static void
343 : 0 : warn(const char *message, ...)
344 : : {
345 : : va_list args;
346 : :
347 : 0 : fprintf(stderr, "%s:%d: ", file_name, line_number);
348 : 0 : va_start(args, message);
349 : 0 : vfprintf(stderr, message, args);
350 : 0 : va_end(args);
351 : 0 : putc('\n', stderr);
352 : :
353 : 0 : n_warnings++;
354 : 0 : }
355 : :
356 : : static bool
357 : 1504 : get_token(void)
358 : : {
359 : : char *start;
360 : :
361 [ + + ]: 2278 : while (isspace((unsigned char) *pos)) {
362 : 774 : pos++;
363 : : }
364 [ + + ]: 1504 : if (*pos == '\0') {
365 : 375 : free(token);
366 : 375 : token = NULL;
367 : 375 : return false;
368 : : }
369 : :
370 : 1129 : start = pos;
371 [ + + ]: 1129 : if (isalpha((unsigned char) *pos)) {
372 [ + + ]: 1389 : while (isalpha((unsigned char) *++pos)) {
373 : 813 : continue;
374 : : }
375 [ + + ]: 553 : } else if (isdigit((unsigned char) *pos)) {
376 [ + + ][ + + ]: 390 : if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) {
[ - + ]
377 : 76 : pos += 2;
378 [ + + ]: 314 : while (isxdigit((unsigned char) *pos)) {
379 : 238 : pos++;
380 : : }
381 : : } else {
382 [ + + ]: 438 : while (isdigit((unsigned char) *++pos)) {
383 : 124 : continue;
384 : : }
385 : : }
386 : : } else {
387 : 239 : pos++;
388 : : }
389 : :
390 : 1129 : free(token);
391 : 1129 : token = xmemdup0(start, pos - start);
392 : 1129 : return true;
393 : : }
394 : :
395 : : static bool
396 : 304 : get_int(int *intp)
397 : : {
398 : 304 : char *save_pos = pos;
399 [ + - ][ + - ]: 304 : if (token && isdigit((unsigned char) *token)) {
400 : 304 : *intp = strtol(token, NULL, 0);
401 : 304 : get_token();
402 : 304 : return true;
403 : : } else {
404 : 0 : pos = save_pos;
405 : 0 : return false;
406 : : }
407 : : }
408 : :
409 : : static bool
410 : 2670 : match(const char *want)
411 : : {
412 [ + + ][ + + ]: 2670 : if (token && !strcmp(want, token)) {
413 : 675 : get_token();
414 : 675 : return true;
415 : : } else {
416 : 1995 : return false;
417 : : }
418 : : }
419 : :
420 : : static int
421 : 304 : must_get_int(void)
422 : : {
423 : : int x;
424 [ - + ]: 304 : if (!get_int(&x)) {
425 : 0 : err("expected integer");
426 : : }
427 : 304 : return x;
428 : : }
429 : :
430 : : static void
431 : 98 : must_match(const char *want)
432 : : {
433 [ - + ]: 98 : if (!match(want)) {
434 : 0 : err("expected \"%s\"", want);
435 : : }
436 : 98 : }
437 : :
438 : : static void
439 : 13 : test_stp_main(int argc, char *argv[])
440 : : {
441 : : struct test_case *tc;
442 : : FILE *input_file;
443 : : int i;
444 : :
445 : 13 : vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m");
446 : 13 : vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF);
447 : :
448 [ - + ]: 13 : if (argc != 2) {
449 : 0 : ovs_fatal(0, "usage: test-stp INPUT.STP\n");
450 : : }
451 : 13 : file_name = argv[1];
452 : :
453 : 13 : input_file = fopen(file_name, "r");
454 [ - + ]: 13 : if (!input_file) {
455 : 0 : ovs_fatal(errno, "error opening \"%s\"", file_name);
456 : : }
457 : :
458 : 13 : tc = new_test_case();
459 [ + + ]: 351 : for (i = 0; i < 26; i++) {
460 : : char name[2];
461 : 338 : name[0] = 'a' + i;
462 : 338 : name[1] = '\0';
463 : 338 : new_lan(tc, name);
464 : : }
465 : :
466 [ + + ]: 223 : for (line_number = 1; fgets(line, sizeof line, input_file);
467 : 210 : line_number++)
468 : : {
469 : : char *newline, *hash;
470 : :
471 : 210 : newline = strchr(line, '\n');
472 [ + - ]: 210 : if (newline) {
473 : 210 : *newline = '\0';
474 : : }
475 : 210 : hash = strchr(line, '#');
476 [ + + ]: 210 : if (hash) {
477 : 43 : *hash = '\0';
478 : : }
479 : :
480 : 210 : pos = line;
481 [ + + ]: 210 : if (!get_token()) {
482 : 45 : continue;
483 : : }
484 [ + + ]: 165 : if (match("bridge")) {
485 : : struct bridge *bridge;
486 : : int bridge_no, port_no;
487 : :
488 : 58 : bridge_no = must_get_int();
489 [ + + ]: 58 : if (bridge_no < tc->n_bridges) {
490 : 14 : bridge = tc->bridges[bridge_no];
491 [ + - ]: 44 : } else if (bridge_no == tc->n_bridges) {
492 : 44 : bridge = new_bridge(tc, must_get_int());
493 : : } else {
494 : 0 : err("bridges must be numbered consecutively from 0");
495 : : }
496 [ + + ]: 58 : if (match("^")) {
497 : 11 : stp_set_bridge_priority(bridge->stp, must_get_int());
498 : : }
499 : :
500 [ + + ]: 58 : if (match("=")) {
501 [ + + ]: 13063 : for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) {
502 : 13005 : struct stp_port *p = stp_get_port(bridge->stp, port_no);
503 [ + + ][ + + ]: 13005 : if (!token || match("X")) {
504 : 12846 : stp_port_disable(p);
505 [ + + ]: 159 : } else if (match("_")) {
506 : : /* Nothing to do. */
507 : : } else {
508 : : struct lan *lan;
509 : : int path_cost;
510 : :
511 [ + + ]: 150 : if (!strcmp(token, "0")) {
512 : 10 : lan = NULL;
513 [ + - ]: 140 : } else if (strlen(token) == 1
514 [ + - ]: 140 : && islower((unsigned char)*token)) {
515 : 140 : lan = tc->lans[*token - 'a'];
516 : : } else {
517 : 0 : err("%s is not a valid LAN name "
518 : : "(0 or a lowercase letter)", token);
519 : : }
520 : 150 : get_token();
521 : :
522 [ + + ]: 150 : path_cost = match(":") ? must_get_int() : 10;
523 [ + + ]: 150 : if (port_no < bridge->n_ports) {
524 : 14 : stp_port_set_path_cost(p, path_cost);
525 : 14 : stp_port_enable(p);
526 : 14 : reconnect_port(bridge, port_no, lan);
527 [ + - ]: 136 : } else if (port_no == bridge->n_ports) {
528 : 136 : new_port(bridge, lan, path_cost);
529 : : } else {
530 : 0 : err("ports must be numbered consecutively");
531 : : }
532 [ + + ]: 150 : if (match("^")) {
533 : 1 : stp_port_set_priority(p, must_get_int());
534 : : }
535 : : }
536 : : }
537 : : }
538 [ + + ]: 107 : } else if (match("run")) {
539 : 23 : simulate(tc, must_get_int());
540 [ - + ]: 84 : } else if (match("dump")) {
541 : 0 : dump(tc);
542 [ - + ]: 84 : } else if (match("tree")) {
543 : 0 : tree(tc);
544 [ + - ]: 84 : } else if (match("check")) {
545 : : struct bridge *b;
546 : : struct stp *stp;
547 : : int bridge_no, port_no;
548 : :
549 : 84 : bridge_no = must_get_int();
550 [ - + ]: 84 : if (bridge_no >= tc->n_bridges) {
551 : 0 : err("no bridge numbered %d", bridge_no);
552 : : }
553 : 84 : b = tc->bridges[bridge_no];
554 : 84 : stp = b->stp;
555 : :
556 : 84 : must_match("=");
557 : :
558 [ + + ]: 84 : if (match("rootid")) {
559 : : uint64_t rootid;
560 : 14 : must_match(":");
561 : 14 : rootid = must_get_int();
562 [ + + ]: 14 : if (match("^")) {
563 : 6 : rootid |= (uint64_t) must_get_int() << 48;
564 : : } else {
565 : 8 : rootid |= UINT64_C(0x8000) << 48;
566 : : }
567 [ - + ]: 14 : if (stp_get_designated_root(stp) != rootid) {
568 : 0 : warn("%s: root %"PRIx64", not %"PRIx64,
569 : : stp_get_name(stp), stp_get_designated_root(stp),
570 : : rootid);
571 : : }
572 : : }
573 : :
574 [ + + ]: 84 : if (match("root")) {
575 [ - + ]: 21 : if (stp_get_root_path_cost(stp)) {
576 : 0 : warn("%s: root path cost of root is %u but should be 0",
577 : : stp_get_name(stp), stp_get_root_path_cost(stp));
578 : : }
579 [ - + ]: 21 : if (!stp_is_root_bridge(stp)) {
580 : 0 : warn("%s: root is %"PRIx64", not %"PRIx64,
581 : : stp_get_name(stp),
582 : : stp_get_designated_root(stp), stp_get_bridge_id(stp));
583 : : }
584 [ + + ]: 77 : for (port_no = 0; port_no < b->n_ports; port_no++) {
585 : 56 : struct stp_port *p = stp_get_port(stp, port_no);
586 : 56 : enum stp_state state = stp_port_get_state(p);
587 [ - + ]: 56 : if (!(state & (STP_DISABLED | STP_FORWARDING))) {
588 : 0 : warn("%s: root port %d in state %s",
589 : 0 : stp_get_name(b->stp), port_no,
590 : : stp_state_name(state));
591 : : }
592 : : }
593 : : } else {
594 [ + + ]: 16128 : for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) {
595 : 16065 : struct stp_port *p = stp_get_port(stp, port_no);
596 : : enum stp_state state;
597 [ + + ][ + + ]: 16065 : if (token == NULL || match("D")) {
598 : 15837 : state = STP_DISABLED;
599 [ + + ]: 228 : } else if (match("B")) {
600 : 55 : state = STP_BLOCKING;
601 [ + + ]: 173 : } else if (match("Li")) {
602 : 8 : state = STP_LISTENING;
603 [ - + ]: 165 : } else if (match("Le")) {
604 : 0 : state = STP_LEARNING;
605 [ + - ]: 165 : } else if (match("F")) {
606 : 165 : state = STP_FORWARDING;
607 [ # # ]: 0 : } else if (match("_")) {
608 : 0 : continue;
609 : : } else {
610 : 0 : err("unknown port state %s", token);
611 : : }
612 [ - + ]: 16065 : if (stp_port_get_state(p) != state) {
613 : 0 : warn("%s port %d: state is %s but should be %s",
614 : : stp_get_name(stp), port_no,
615 : : stp_state_name(stp_port_get_state(p)),
616 : : stp_state_name(state));
617 : : }
618 [ + + ]: 16065 : if (state == STP_FORWARDING) {
619 : 165 : struct stp_port *root_port = stp_get_root_port(stp);
620 [ + + ]: 165 : if (match(":")) {
621 : 57 : int root_path_cost = must_get_int();
622 [ - + ]: 57 : if (p != root_port) {
623 : 0 : warn("%s: port %d is not the root port",
624 : : stp_get_name(stp), port_no);
625 [ # # ]: 0 : if (!root_port) {
626 : 0 : warn("%s: (there is no root port)",
627 : : stp_get_name(stp));
628 : : } else {
629 : 0 : warn("%s: (port %d is the root port)",
630 : : stp_get_name(stp),
631 : : stp_port_no(root_port));
632 : : }
633 [ - + ]: 57 : } else if (root_path_cost
634 : 57 : != stp_get_root_path_cost(stp)) {
635 : 57 : warn("%s: root path cost is %u, should be %d",
636 : : stp_get_name(stp),
637 : : stp_get_root_path_cost(stp),
638 : : root_path_cost);
639 : : }
640 [ - + ]: 108 : } else if (p == root_port) {
641 : 0 : warn("%s: port %d is the root port but "
642 : : "not expected to be",
643 : : stp_get_name(stp), port_no);
644 : : }
645 : : }
646 : : }
647 : : }
648 [ - + ]: 84 : if (n_warnings) {
649 : 0 : exit(EXIT_FAILURE);
650 : : }
651 : : }
652 [ - + ]: 165 : if (get_token()) {
653 : 0 : err("trailing garbage on line");
654 : : }
655 : : }
656 : 13 : free(token);
657 : :
658 [ + + ]: 351 : for (i = 0; i < tc->n_lans; i++) {
659 : 338 : struct lan *lan = tc->lans[i];
660 : 338 : free(CONST_CAST(char *, lan->name));
661 : 338 : free(lan);
662 : : }
663 [ + + ]: 57 : for (i = 0; i < tc->n_bridges; i++) {
664 : 44 : struct bridge *bridge = tc->bridges[i];
665 : 44 : stp_unref(bridge->stp);
666 : 44 : free(bridge);
667 : : }
668 : 13 : free(tc);
669 : 13 : fclose(input_file);
670 : 13 : }
671 : :
672 : 1200 : OVSTEST_REGISTER("test-stp", test_stp_main);
|