Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2011-2015 M3S, Srl - Italy
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 : : /*
18 : : * Rapid Spanning Tree Protocol (IEEE 802.1D-2004) public interface.
19 : : *
20 : : * Authors:
21 : : * Martino Fornasa <mf@fornasa.it>
22 : : * Daniele Venturino <daniele.venturino@m3s.it>
23 : : * Carlo Andreotti <c.andreotti@m3s.it>
24 : : *
25 : : * References to IEEE 802.1D-2004 standard are enclosed in square brackets.
26 : : * E.g. [17.3], [Table 17-1], etc.
27 : : *
28 : : */
29 : :
30 : : #include <config.h>
31 : :
32 : : #include "rstp.h"
33 : : #include "rstp-common.h"
34 : : #include "rstp-state-machines.h"
35 : : #include <arpa/inet.h>
36 : : #include <inttypes.h>
37 : : #include <netinet/in.h>
38 : : #include <stdlib.h>
39 : : #include <sys/types.h>
40 : : #include "byte-order.h"
41 : : #include "connectivity.h"
42 : : #include "openvswitch/ofpbuf.h"
43 : : #include "ofproto/ofproto.h"
44 : : #include "dp-packet.h"
45 : : #include "packets.h"
46 : : #include "seq.h"
47 : : #include "unixctl.h"
48 : : #include "util.h"
49 : : #include "openvswitch/vlog.h"
50 : :
51 : 2462 : VLOG_DEFINE_THIS_MODULE(rstp);
52 : :
53 : : struct ovs_mutex rstp_mutex = OVS_MUTEX_INITIALIZER;
54 : :
55 : : static struct ovs_list all_rstps__ = OVS_LIST_INITIALIZER(&all_rstps__);
56 : : static struct ovs_list *const all_rstps OVS_GUARDED_BY(rstp_mutex) = &all_rstps__;
57 : :
58 : : /* Internal use only. */
59 : : static void rstp_set_bridge_address__(struct rstp *, rstp_identifier)
60 : : OVS_REQUIRES(rstp_mutex);
61 : : static void rstp_set_bridge_priority__(struct rstp *, int new_priority)
62 : : OVS_REQUIRES(rstp_mutex);
63 : : static void rstp_set_bridge_ageing_time__(struct rstp *, int new_ageing_time)
64 : : OVS_REQUIRES(rstp_mutex);
65 : : static void rstp_set_bridge_force_protocol_version__(struct rstp *,
66 : : enum rstp_force_protocol_version)
67 : : OVS_REQUIRES(rstp_mutex);
68 : : static void rstp_set_bridge_hello_time__(struct rstp *)
69 : : OVS_REQUIRES(rstp_mutex);
70 : : static void rstp_set_bridge_max_age__(struct rstp *, int new_max_age)
71 : : OVS_REQUIRES(rstp_mutex);
72 : : static void rstp_set_bridge_forward_delay__(struct rstp *, int new_forward_delay)
73 : : OVS_REQUIRES(rstp_mutex);
74 : : static void rstp_set_bridge_transmit_hold_count__(struct rstp *,
75 : : int new_transmit_hold_count)
76 : : OVS_REQUIRES(rstp_mutex);
77 : : static void rstp_set_bridge_migrate_time__(struct rstp *)
78 : : OVS_REQUIRES(rstp_mutex);
79 : : static void rstp_set_bridge_times__(struct rstp *, int new_forward_delay,
80 : : int new_hello_time, int new_max_age,
81 : : int new_message_age)
82 : : OVS_REQUIRES(rstp_mutex);
83 : :
84 : : static struct rstp_port *rstp_get_port__(struct rstp *rstp,
85 : : uint16_t port_number)
86 : : OVS_REQUIRES(rstp_mutex);
87 : : static void set_port_id__(struct rstp_port *)
88 : : OVS_REQUIRES(rstp_mutex);
89 : : static void update_port_enabled__(struct rstp_port *)
90 : : OVS_REQUIRES(rstp_mutex);
91 : : static void set_bridge_priority__(struct rstp *)
92 : : OVS_REQUIRES(rstp_mutex);
93 : : static void reinitialize_rstp__(struct rstp *)
94 : : OVS_REQUIRES(rstp_mutex);
95 : : static bool is_port_number_available__(struct rstp *, int, struct rstp_port *)
96 : : OVS_REQUIRES(rstp_mutex);
97 : : static uint16_t rstp_first_free_number__(struct rstp *, struct rstp_port *)
98 : : OVS_REQUIRES(rstp_mutex);
99 : : static void rstp_initialize_port_defaults__(struct rstp_port *)
100 : : OVS_REQUIRES(rstp_mutex);
101 : : static void rstp_port_set_priority__(struct rstp_port *, int priority)
102 : : OVS_REQUIRES(rstp_mutex);
103 : : static void rstp_port_set_port_number__(struct rstp_port *,
104 : : uint16_t port_number)
105 : : OVS_REQUIRES(rstp_mutex);
106 : : static void rstp_port_set_path_cost__(struct rstp_port *, uint32_t path_cost)
107 : : OVS_REQUIRES(rstp_mutex);
108 : : static void rstp_port_set_administrative_bridge_port__(struct rstp_port *,
109 : : uint8_t admin_port_state,
110 : : bool initializing)
111 : : OVS_REQUIRES(rstp_mutex);
112 : : static void rstp_port_set_admin_edge__(struct rstp_port *, bool admin_edge)
113 : : OVS_REQUIRES(rstp_mutex);
114 : : static void rstp_port_set_auto_edge__(struct rstp_port *, bool auto_edge)
115 : : OVS_REQUIRES(rstp_mutex);
116 : : static void rstp_port_set_admin_point_to_point_mac__(struct rstp_port *,
117 : : enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state)
118 : : OVS_REQUIRES(rstp_mutex);
119 : : static void rstp_port_set_mcheck__(struct rstp_port *, bool mcheck)
120 : : OVS_REQUIRES(rstp_mutex);
121 : : static void reinitialize_port__(struct rstp_port *p)
122 : : OVS_REQUIRES(rstp_mutex);
123 : :
124 : : const char *
125 : 34 : rstp_state_name(enum rstp_state state)
126 : : {
127 [ + - + + : 34 : switch (state) {
- ]
128 : : case RSTP_DISABLED:
129 : 4 : return "Disabled";
130 : : case RSTP_LEARNING:
131 : 0 : return "Learning";
132 : : case RSTP_FORWARDING:
133 : 9 : return "Forwarding";
134 : : case RSTP_DISCARDING:
135 : 21 : return "Discarding";
136 : : default:
137 : 0 : return "Unknown";
138 : : }
139 : : }
140 : :
141 : : const char *
142 : 22 : rstp_port_role_name(enum rstp_port_role role)
143 : : {
144 [ + + - - : 22 : switch (role) {
+ - ]
145 : : case ROLE_ROOT:
146 : 2 : return "Root";
147 : : case ROLE_DESIGNATED:
148 : 15 : return "Designated";
149 : : case ROLE_ALTERNATE:
150 : 0 : return "Alternate";
151 : : case ROLE_BACKUP:
152 : 0 : return "Backup";
153 : : case ROLE_DISABLED:
154 : 5 : return "Disabled";
155 : : default:
156 : 0 : return "Unknown";
157 : : }
158 : : }
159 : :
160 : : /* Caller has to hold a reference to prevent 'rstp' from being deleted
161 : : * while taking a new reference. */
162 : : struct rstp *
163 : 77 : rstp_ref(struct rstp *rstp)
164 : : OVS_EXCLUDED(rstp_mutex)
165 : : {
166 [ + - ]: 77 : if (rstp) {
167 : 77 : ovs_refcount_ref(&rstp->ref_cnt);
168 : : }
169 : 77 : return rstp;
170 : : }
171 : :
172 : : /* Frees RSTP struct when reference count reaches zero. */
173 : : void
174 : 46565 : rstp_unref(struct rstp *rstp)
175 : : OVS_EXCLUDED(rstp_mutex)
176 : : {
177 [ + + ][ + + ]: 46565 : if (rstp && ovs_refcount_unref_relaxed(&rstp->ref_cnt) == 1) {
178 : 26 : ovs_mutex_lock(&rstp_mutex);
179 : :
180 : : /* Each RSTP port points back to struct rstp without holding a
181 : : * reference for that pointer. This is OK as we never move
182 : : * ports from one bridge to another, and holders always
183 : : * release their ports before releasing the bridge. This
184 : : * means that there should be not ports at this time. */
185 [ - + ]: 26 : ovs_assert(hmap_is_empty(&rstp->ports));
186 : :
187 : 26 : ovs_list_remove(&rstp->node);
188 : 26 : ovs_mutex_unlock(&rstp_mutex);
189 : 26 : hmap_destroy(&rstp->ports);
190 : 26 : free(rstp->name);
191 : 26 : free(rstp);
192 : : }
193 : 46565 : }
194 : :
195 : : /* Returns the port number. Mutex is needed to guard against
196 : : * concurrent reinitialization (which can temporarily clear the
197 : : * port_number). */
198 : : int
199 : 0 : rstp_port_get_number(const struct rstp_port *p)
200 : : OVS_EXCLUDED(rstp_mutex)
201 : : {
202 : : int number;
203 : :
204 : 0 : ovs_mutex_lock(&rstp_mutex);
205 : 0 : number = p->port_number;
206 : 0 : ovs_mutex_unlock(&rstp_mutex);
207 : :
208 : 0 : return number;
209 : : }
210 : :
211 : : static void rstp_unixctl_tcn(struct unixctl_conn *, int argc,
212 : : const char *argv[], void *aux);
213 : :
214 : : /* Decrements the State Machines' timers. */
215 : : void
216 : 10804 : rstp_tick_timers(struct rstp *rstp)
217 : : OVS_EXCLUDED(rstp_mutex)
218 : : {
219 : 10804 : ovs_mutex_lock(&rstp_mutex);
220 : 10804 : decrease_rstp_port_timers__(rstp);
221 : 10804 : ovs_mutex_unlock(&rstp_mutex);
222 : 10804 : }
223 : :
224 : : /* Processes an incoming BPDU. */
225 : : void
226 : 7069 : rstp_port_received_bpdu(struct rstp_port *rp, const void *bpdu,
227 : : size_t bpdu_size)
228 : : OVS_EXCLUDED(rstp_mutex)
229 : : {
230 : 7069 : ovs_mutex_lock(&rstp_mutex);
231 : : /* Only process packets on ports that have RSTP enabled. */
232 [ + - ][ + + ]: 7069 : if (rp && rp->rstp_state != RSTP_DISABLED) {
233 : 6349 : process_received_bpdu__(rp, bpdu, bpdu_size);
234 : : }
235 : 7069 : ovs_mutex_unlock(&rstp_mutex);
236 : 7069 : }
237 : :
238 : : void
239 : 617 : rstp_init(void)
240 : : OVS_EXCLUDED(rstp_mutex)
241 : : {
242 : 617 : unixctl_command_register("rstp/tcn", "[bridge]", 0, 1, rstp_unixctl_tcn,
243 : : NULL);
244 : 617 : }
245 : :
246 : : /* Creates and returns a new RSTP instance that initially has no ports. */
247 : : struct rstp *
248 : 28 : rstp_create(const char *name, rstp_identifier bridge_address,
249 : : void (*send_bpdu)(struct dp_packet *bpdu, void *port_aux,
250 : : void *rstp_aux),
251 : : void *aux)
252 : : OVS_EXCLUDED(rstp_mutex)
253 : : {
254 : : struct rstp *rstp;
255 : :
256 [ - + ]: 28 : VLOG_DBG("Creating RSTP instance");
257 : :
258 : 28 : rstp = xzalloc(sizeof *rstp);
259 : 28 : rstp->name = xstrdup(name);
260 : :
261 : : /* Initialize the ports map before calling any setters,
262 : : * so that the state machines will see an empty ports map. */
263 : 28 : hmap_init(&rstp->ports);
264 : :
265 : 28 : ovs_mutex_lock(&rstp_mutex);
266 : : /* Set bridge address. */
267 : 28 : rstp_set_bridge_address__(rstp, bridge_address);
268 : : /* Set default parameters values. */
269 : 28 : rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
270 : 28 : rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
271 : 28 : rstp_set_bridge_force_protocol_version__(rstp, FPV_DEFAULT);
272 : 28 : rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
273 : 28 : rstp_set_bridge_hello_time__(rstp);
274 : 28 : rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
275 : 28 : rstp_set_bridge_migrate_time__(rstp);
276 : 28 : rstp_set_bridge_transmit_hold_count__(rstp,
277 : : RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
278 : 28 : rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
279 : : RSTP_BRIDGE_HELLO_TIME,
280 : : RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
281 : 28 : rstp->send_bpdu = send_bpdu;
282 : 28 : rstp->aux = aux;
283 : 28 : rstp->changes = false;
284 : 28 : rstp->begin = true;
285 : 28 : rstp->old_root_aux = NULL;
286 : 28 : rstp->new_root_aux = NULL;
287 : :
288 : 28 : ovs_refcount_init(&rstp->ref_cnt);
289 : :
290 : 28 : ovs_list_push_back(all_rstps, &rstp->node);
291 : 28 : ovs_mutex_unlock(&rstp_mutex);
292 : :
293 [ - + ]: 28 : VLOG_DBG("RSTP instance creation done");
294 : 28 : return rstp;
295 : : }
296 : :
297 : : /* Called by rstp_set_bridge_address() and rstp_set_bridge_priority(),
298 : : * it updates the bridge priority vector according to the values passed by
299 : : * those setters.
300 : : */
301 : : static void
302 : 111 : set_bridge_priority__(struct rstp *rstp)
303 : : OVS_REQUIRES(rstp_mutex)
304 : : {
305 : : struct rstp_port *p;
306 : :
307 : 111 : rstp->bridge_priority.root_bridge_id = rstp->bridge_identifier;
308 : 111 : rstp->bridge_priority.designated_bridge_id = rstp->bridge_identifier;
309 [ - + ]: 111 : VLOG_DBG("%s: new bridge identifier: "RSTP_ID_FMT"", rstp->name,
310 : : RSTP_ID_ARGS(rstp->bridge_identifier));
311 : :
312 : : /* [17.13] When the bridge address changes, recalculates all priority
313 : : * vectors.
314 : : */
315 [ + + ][ - + ]: 120 : HMAP_FOR_EACH (p, node, &rstp->ports) {
316 : 9 : p->selected = false;
317 : 9 : p->reselect = true;
318 : : }
319 : 111 : rstp->changes = true;
320 : 111 : updt_roles_tree__(rstp);
321 : 111 : }
322 : :
323 : : /* Sets the bridge address. */
324 : : static void
325 : 68 : rstp_set_bridge_address__(struct rstp *rstp, rstp_identifier bridge_address)
326 : : OVS_REQUIRES(rstp_mutex)
327 : : {
328 [ - + ]: 68 : VLOG_DBG("%s: set bridge address to: "RSTP_ID_FMT"", rstp->name,
329 : : RSTP_ID_ARGS(bridge_address));
330 [ + + ]: 68 : if (rstp->address != bridge_address) {
331 : 54 : rstp->address = bridge_address;
332 : 54 : rstp->bridge_identifier &= 0xffff000000000000ULL;
333 : 54 : rstp->bridge_identifier |= bridge_address;
334 : 54 : set_bridge_priority__(rstp);
335 : : }
336 : 68 : }
337 : :
338 : : /* Sets the bridge address. */
339 : : void
340 : 12 : rstp_set_bridge_address(struct rstp *rstp, rstp_identifier bridge_address)
341 : : OVS_EXCLUDED(rstp_mutex)
342 : : {
343 : 12 : ovs_mutex_lock(&rstp_mutex);
344 : 12 : rstp_set_bridge_address__(rstp, bridge_address);
345 : 12 : ovs_mutex_unlock(&rstp_mutex);
346 : 12 : }
347 : :
348 : : const char *
349 : 0 : rstp_get_name(const struct rstp *rstp)
350 : : OVS_EXCLUDED(rstp_mutex)
351 : : {
352 : : char *name;
353 : :
354 : 0 : ovs_mutex_lock(&rstp_mutex);
355 : 0 : name = rstp->name;
356 : 0 : ovs_mutex_unlock(&rstp_mutex);
357 : 0 : return name;
358 : : }
359 : :
360 : : rstp_identifier
361 : 25 : rstp_get_bridge_id(const struct rstp *rstp)
362 : : OVS_EXCLUDED(rstp_mutex)
363 : : {
364 : : rstp_identifier bridge_id;
365 : :
366 : 25 : ovs_mutex_lock(&rstp_mutex);
367 : 25 : bridge_id = rstp->bridge_identifier;
368 : 25 : ovs_mutex_unlock(&rstp_mutex);
369 : :
370 : 25 : return bridge_id;
371 : : }
372 : :
373 : : /* Sets the bridge priority. */
374 : : static void
375 : 69 : rstp_set_bridge_priority__(struct rstp *rstp, int new_priority)
376 : : OVS_REQUIRES(rstp_mutex)
377 : : {
378 : 69 : new_priority = ROUND_DOWN(new_priority, RSTP_PRIORITY_STEP);
379 : :
380 [ + + ]: 69 : if (rstp->priority != new_priority
381 [ + - ]: 57 : && new_priority >= RSTP_MIN_PRIORITY
382 [ + - ]: 57 : && new_priority <= RSTP_MAX_PRIORITY) {
383 [ - + ]: 57 : VLOG_DBG("%s: set bridge priority to %d", rstp->name, new_priority);
384 : :
385 : 57 : rstp->priority = new_priority;
386 : 57 : rstp->bridge_identifier &= 0x0000ffffffffffffULL;
387 : 57 : rstp->bridge_identifier |= (uint64_t)new_priority << 48;
388 : 57 : set_bridge_priority__(rstp);
389 : : }
390 : 69 : }
391 : :
392 : : void
393 : 13 : rstp_set_bridge_priority(struct rstp *rstp, int new_priority)
394 : : OVS_EXCLUDED(rstp_mutex)
395 : : {
396 : 13 : ovs_mutex_lock(&rstp_mutex);
397 : 13 : rstp_set_bridge_priority__(rstp, new_priority);
398 : 13 : ovs_mutex_unlock(&rstp_mutex);
399 : 13 : }
400 : :
401 : : /* Sets the bridge ageing time. */
402 : : static void
403 : 68 : rstp_set_bridge_ageing_time__(struct rstp *rstp, int new_ageing_time)
404 : : OVS_REQUIRES(rstp_mutex)
405 : : {
406 [ + - ]: 68 : if (new_ageing_time >= RSTP_MIN_AGEING_TIME
407 [ + - ]: 68 : && new_ageing_time <= RSTP_MAX_AGEING_TIME) {
408 [ - + ]: 68 : VLOG_DBG("%s: set ageing time to %d", rstp->name, new_ageing_time);
409 : :
410 : 68 : rstp->ageing_time = new_ageing_time;
411 : : }
412 : 68 : }
413 : :
414 : : void
415 : 12 : rstp_set_bridge_ageing_time(struct rstp *rstp, int new_ageing_time)
416 : : OVS_EXCLUDED(rstp_mutex)
417 : : {
418 : 12 : ovs_mutex_lock(&rstp_mutex);
419 : 12 : rstp_set_bridge_ageing_time__(rstp, new_ageing_time);
420 : 12 : ovs_mutex_unlock(&rstp_mutex);
421 : 12 : }
422 : :
423 : : /* Reinitializes RSTP when switching from RSTP mode to STP mode
424 : : * or vice versa.
425 : : */
426 : : static void
427 : 28 : reinitialize_rstp__(struct rstp *rstp)
428 : : OVS_REQUIRES(rstp_mutex)
429 : : {
430 : : struct rstp temp;
431 : : static struct hmap ports;
432 : : struct rstp_port *p;
433 : :
434 : : /* Copy rstp in temp */
435 : 28 : temp = *rstp;
436 : 28 : ports = rstp->ports;
437 : :
438 : : /* stop and clear rstp */
439 : 28 : memset(rstp, 0, sizeof(struct rstp));
440 : :
441 : : /* Initialize rstp. */
442 : 28 : rstp->name = temp.name;
443 : :
444 : : /* Initialize the ports hmap before calling any setters,
445 : : * so that the state machines will see an empty ports list. */
446 : 28 : hmap_init(&rstp->ports);
447 : :
448 : : /* Set bridge address. */
449 : 28 : rstp_set_bridge_address__(rstp, temp.address);
450 : : /* Set default parameters values. */
451 : 28 : rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
452 : 28 : rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
453 : 28 : rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
454 : 28 : rstp_set_bridge_hello_time__(rstp);
455 : 28 : rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
456 : 28 : rstp_set_bridge_migrate_time__(rstp);
457 : 28 : rstp_set_bridge_transmit_hold_count__(rstp,
458 : : RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
459 : 28 : rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
460 : : RSTP_BRIDGE_HELLO_TIME,
461 : : RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
462 : :
463 : 28 : rstp->send_bpdu = temp.send_bpdu;
464 : 28 : rstp->aux = temp.aux;
465 : 28 : rstp->node = temp.node;
466 : 28 : rstp->changes = false;
467 : 28 : rstp->begin = true;
468 : :
469 : : /* Restore ports. */
470 : 28 : rstp->ports = ports;
471 : :
472 [ - + ][ - + ]: 28 : HMAP_FOR_EACH (p, node, &rstp->ports) {
473 : 0 : reinitialize_port__(p);
474 : : }
475 : :
476 : 28 : rstp->ref_cnt = temp.ref_cnt;
477 : 28 : }
478 : :
479 : : /* Sets the force protocol version parameter. */
480 : : static void
481 : 40 : rstp_set_bridge_force_protocol_version__(struct rstp *rstp,
482 : : enum rstp_force_protocol_version new_force_protocol_version)
483 : : OVS_REQUIRES(rstp_mutex)
484 : : {
485 [ + + ][ + - ]: 40 : if (new_force_protocol_version != rstp->force_protocol_version &&
486 [ + - ]: 28 : (new_force_protocol_version == FPV_STP_COMPATIBILITY ||
487 : : new_force_protocol_version == FPV_DEFAULT)) {
488 [ - + ]: 28 : VLOG_DBG("%s: set bridge Force Protocol Version to %d", rstp->name,
489 : : new_force_protocol_version);
490 : :
491 : : /* [17.13] The Spanning Tree Protocol Entity shall be reinitialized,
492 : : * as specified by the assertion of BEGIN (17.18.1) in the state
493 : : * machine specification.
494 : : */
495 : 28 : reinitialize_rstp__(rstp);
496 : 28 : rstp->force_protocol_version = new_force_protocol_version;
497 [ - + ]: 28 : if (rstp->force_protocol_version < 2) {
498 : 0 : rstp->stp_version = true;
499 : 0 : rstp->rstp_version = false;
500 : : } else {
501 : 28 : rstp->stp_version = false;
502 : 28 : rstp->rstp_version = true;
503 : : }
504 : 28 : rstp->changes = true;
505 : 28 : move_rstp__(rstp);
506 : : }
507 : 40 : }
508 : :
509 : : void
510 : 12 : rstp_set_bridge_force_protocol_version(struct rstp *rstp,
511 : : enum rstp_force_protocol_version new_force_protocol_version)
512 : : OVS_EXCLUDED(rstp_mutex)
513 : : {
514 : 12 : ovs_mutex_lock(&rstp_mutex);
515 : 12 : rstp_set_bridge_force_protocol_version__(rstp, new_force_protocol_version);
516 : 12 : ovs_mutex_unlock(&rstp_mutex);
517 : 12 : }
518 : :
519 : : /* Sets the bridge Hello Time parameter. */
520 : : static void
521 : 56 : rstp_set_bridge_hello_time__(struct rstp *rstp)
522 : : OVS_REQUIRES(rstp_mutex)
523 : : {
524 [ - + ]: 56 : VLOG_DBG("%s: set RSTP Hello Time to %d", rstp->name,
525 : : RSTP_BRIDGE_HELLO_TIME);
526 : : /* 2 is the only acceptable value. */
527 : 56 : rstp->bridge_hello_time = RSTP_BRIDGE_HELLO_TIME;
528 : 56 : }
529 : :
530 : : /* Sets the bridge max age parameter. */
531 : : static void
532 : 68 : rstp_set_bridge_max_age__(struct rstp *rstp, int new_max_age)
533 : : OVS_REQUIRES(rstp_mutex)
534 : : {
535 [ + + ]: 68 : if (rstp->bridge_max_age != new_max_age
536 [ + - ]: 28 : && new_max_age >= RSTP_MIN_BRIDGE_MAX_AGE
537 [ + - ]: 28 : && new_max_age <= RSTP_MAX_BRIDGE_MAX_AGE) {
538 : : /* [17.13] */
539 [ + - ]: 28 : if ((2 * (rstp->bridge_forward_delay - 1) >= new_max_age)
540 [ + - ]: 28 : && (new_max_age >= 2 * rstp->bridge_hello_time)) {
541 [ - + ]: 28 : VLOG_DBG("%s: set RSTP bridge Max Age to %d", rstp->name,
542 : : new_max_age);
543 : :
544 : 28 : rstp->bridge_max_age = new_max_age;
545 : 28 : rstp->bridge_times.max_age = new_max_age;
546 : 28 : rstp->changes = true;
547 : 28 : updt_roles_tree__(rstp);
548 : : }
549 : : }
550 : 68 : }
551 : :
552 : : void
553 : 12 : rstp_set_bridge_max_age(struct rstp *rstp, int new_max_age)
554 : : OVS_EXCLUDED(rstp_mutex)
555 : : {
556 : 12 : ovs_mutex_lock(&rstp_mutex);
557 : 12 : rstp_set_bridge_max_age__(rstp, new_max_age);
558 : 12 : ovs_mutex_unlock(&rstp_mutex);
559 : 12 : }
560 : :
561 : : /* Sets the bridge forward delay parameter. */
562 : : static void
563 : 68 : rstp_set_bridge_forward_delay__(struct rstp *rstp, int new_forward_delay)
564 : : OVS_REQUIRES(rstp_mutex)
565 : : {
566 [ + + ]: 68 : if (rstp->bridge_forward_delay != new_forward_delay
567 [ + - ]: 28 : && new_forward_delay >= RSTP_MIN_BRIDGE_FORWARD_DELAY
568 [ + - ]: 28 : && new_forward_delay <= RSTP_MAX_BRIDGE_FORWARD_DELAY) {
569 [ + - ]: 28 : if (2 * (new_forward_delay - 1) >= rstp->bridge_max_age) {
570 [ - + ]: 28 : VLOG_DBG("%s: set RSTP Forward Delay to %d", rstp->name,
571 : : new_forward_delay);
572 : 28 : rstp->bridge_forward_delay = new_forward_delay;
573 : 28 : rstp->bridge_times.forward_delay = new_forward_delay;
574 : 28 : rstp->changes = true;
575 : 28 : updt_roles_tree__(rstp);
576 : : }
577 : : }
578 : 68 : }
579 : :
580 : : void
581 : 12 : rstp_set_bridge_forward_delay(struct rstp *rstp, int new_forward_delay)
582 : : OVS_EXCLUDED(rstp_mutex)
583 : : {
584 : 12 : ovs_mutex_lock(&rstp_mutex);
585 : 12 : rstp_set_bridge_forward_delay__(rstp, new_forward_delay);
586 : 12 : ovs_mutex_unlock(&rstp_mutex);
587 : 12 : }
588 : :
589 : : /* Sets the bridge transmit hold count parameter. */
590 : : static void
591 : 68 : rstp_set_bridge_transmit_hold_count__(struct rstp *rstp,
592 : : int new_transmit_hold_count)
593 : : OVS_REQUIRES(rstp_mutex)
594 : : {
595 [ + + ]: 68 : if (rstp->transmit_hold_count != new_transmit_hold_count
596 [ + - ]: 28 : && new_transmit_hold_count >= RSTP_MIN_TRANSMIT_HOLD_COUNT
597 [ + - ]: 28 : && new_transmit_hold_count <= RSTP_MAX_TRANSMIT_HOLD_COUNT) {
598 : : struct rstp_port *p;
599 : :
600 [ - + ]: 28 : VLOG_DBG("%s: set RSTP Transmit Hold Count to %d", rstp->name,
601 : : new_transmit_hold_count);
602 : : /* Resetting txCount on all ports [17.13]. */
603 : :
604 : 28 : rstp->transmit_hold_count = new_transmit_hold_count;
605 [ - + ][ - + ]: 28 : HMAP_FOR_EACH (p, node, &rstp->ports) {
606 : 0 : p->tx_count = 0;
607 : : }
608 : : }
609 : 68 : }
610 : :
611 : : void
612 : 12 : rstp_set_bridge_transmit_hold_count(struct rstp *rstp,
613 : : int new_transmit_hold_count)
614 : : OVS_EXCLUDED(rstp_mutex)
615 : : {
616 : 12 : ovs_mutex_lock(&rstp_mutex);
617 : 12 : rstp_set_bridge_transmit_hold_count__(rstp, new_transmit_hold_count);
618 : 12 : ovs_mutex_unlock(&rstp_mutex);
619 : 12 : }
620 : :
621 : : /* Sets the bridge migrate time parameter. */
622 : : static void
623 : 56 : rstp_set_bridge_migrate_time__(struct rstp *rstp)
624 : : OVS_REQUIRES(rstp_mutex)
625 : : {
626 [ - + ]: 56 : VLOG_DBG("%s: set RSTP Migrate Time to %d", rstp->name,
627 : : RSTP_MIGRATE_TIME);
628 : : /* 3 is the only acceptable value */
629 : 56 : rstp->migrate_time = RSTP_MIGRATE_TIME;
630 : 56 : }
631 : :
632 : : /* Sets the bridge times. */
633 : : static void
634 : 56 : rstp_set_bridge_times__(struct rstp *rstp, int new_forward_delay,
635 : : int new_hello_time, int new_max_age,
636 : : int new_message_age)
637 : : OVS_REQUIRES(rstp_mutex)
638 : : {
639 [ - + ]: 56 : VLOG_DBG("%s: set RSTP times to (%d, %d, %d, %d)", rstp->name,
640 : : new_forward_delay, new_hello_time, new_max_age, new_message_age);
641 [ + - ]: 56 : if (new_forward_delay >= RSTP_MIN_BRIDGE_FORWARD_DELAY
642 [ + - ]: 56 : && new_forward_delay <= RSTP_MAX_BRIDGE_FORWARD_DELAY) {
643 : 56 : rstp->bridge_times.forward_delay = new_forward_delay;
644 : : }
645 [ + - ]: 56 : if (new_hello_time == RSTP_BRIDGE_HELLO_TIME) {
646 : 56 : rstp->bridge_times.hello_time = new_hello_time;
647 : : }
648 [ + - ]: 56 : if (new_max_age >= RSTP_MIN_BRIDGE_MAX_AGE
649 [ + - ]: 56 : && new_max_age <= RSTP_MAX_BRIDGE_MAX_AGE) {
650 : 56 : rstp->bridge_times.max_age = new_max_age;
651 : : }
652 : 56 : rstp->bridge_times.message_age = new_message_age;
653 : 56 : }
654 : :
655 : : /* Sets the port id, it is called by rstp_port_set_port_number__() or
656 : : * rstp_port_set_priority__().
657 : : */
658 : : static void
659 : 473 : set_port_id__(struct rstp_port *p)
660 : : OVS_REQUIRES(rstp_mutex)
661 : : {
662 : : struct rstp *rstp;
663 : :
664 : 473 : rstp = p->rstp;
665 : : /* [9.2.7] Port identifier. */
666 : 473 : p->port_id = p->port_number | (p->priority << 8);
667 [ - + ]: 473 : VLOG_DBG("%s: new RSTP port id "RSTP_PORT_ID_FMT"", rstp->name,
668 : : p->port_id);
669 : 473 : }
670 : :
671 : : /* Sets the port priority. */
672 : : static void
673 : 246 : rstp_port_set_priority__(struct rstp_port *port, int priority)
674 : : OVS_REQUIRES(rstp_mutex)
675 : : {
676 [ + + ]: 246 : if (port->priority != priority
677 [ + - ]: 237 : && priority >= RSTP_MIN_PORT_PRIORITY
678 [ + - ]: 237 : && priority <= RSTP_MAX_PORT_PRIORITY) {
679 [ - + ]: 237 : VLOG_DBG("%s, port %u: set RSTP port priority to %d", port->rstp->name,
680 : : port->port_number, priority);
681 : :
682 : 237 : priority -= priority % RSTP_STEP_PORT_PRIORITY;
683 : 237 : port->priority = priority;
684 : 237 : set_port_id__(port);
685 : 237 : port->selected = false;
686 : 237 : port->reselect = true;
687 : : }
688 : 246 : }
689 : :
690 : : /* Checks if a port number is available. */
691 : : static bool
692 : 1426 : is_port_number_available__(struct rstp *rstp, int n, struct rstp_port *port)
693 : : OVS_REQUIRES(rstp_mutex)
694 : : {
695 [ + + ][ + - ]: 1426 : if (n >= 1 && n <= RSTP_MAX_PORTS) {
696 : 1181 : struct rstp_port *p = rstp_get_port__(rstp, n);
697 : :
698 [ + + ][ + + ]: 1181 : return p == NULL || p == port;
699 : : }
700 : 245 : return false;
701 : : }
702 : :
703 : : static uint16_t
704 : 245 : rstp_first_free_number__(struct rstp *rstp, struct rstp_port *rstp_port)
705 : : OVS_REQUIRES(rstp_mutex)
706 : : {
707 : 245 : int free_number = 1;
708 : :
709 [ + - ]: 1181 : while (free_number <= RSTP_MAX_PORTS) {
710 [ + + ]: 1181 : if (is_port_number_available__(rstp, free_number, rstp_port)) {
711 : 245 : return free_number;
712 : : }
713 : 936 : free_number++;
714 : : }
715 [ # # ]: 0 : VLOG_DBG("%s, No free port number available.", rstp->name);
716 : 0 : return 0;
717 : : }
718 : :
719 : : /* Sets the port number. */
720 : : static void
721 : 245 : rstp_port_set_port_number__(struct rstp_port *port, uint16_t port_number)
722 : : OVS_REQUIRES(rstp_mutex)
723 : : {
724 : 245 : int old_port_number = port->port_number;
725 : :
726 : : /* If new_port_number is available, use it, otherwise use the first free
727 : : * available port number. */
728 [ + + ][ + - ]: 245 : if (port->port_number != port_number || port_number == 0) {
729 [ - + ]: 245 : port->port_number =
730 : 245 : is_port_number_available__(port->rstp, port_number, port)
731 : : ? port_number
732 : 245 : : rstp_first_free_number__(port->rstp, port);
733 : :
734 [ + + ]: 245 : if (port->port_number != old_port_number) {
735 : 236 : set_port_id__(port);
736 : : /* [17.13] is not clear. I suppose that a port number change
737 : : * should trigger reselection like a port priority change. */
738 : 236 : port->selected = false;
739 : 236 : port->reselect = true;
740 : :
741 : : /* Adjust the ports hmap. */
742 [ - + ]: 236 : if (!hmap_node_is_null(&port->node)) {
743 : 0 : hmap_remove(&port->rstp->ports, &port->node);
744 : : }
745 : 236 : hmap_insert(&port->rstp->ports, &port->node,
746 : : hash_int(port->port_number, 0));
747 : :
748 [ - + ]: 236 : VLOG_DBG("%s: set new RSTP port number %d", port->rstp->name,
749 : : port->port_number);
750 : : }
751 : : }
752 : 245 : }
753 : :
754 : : /* Converts the link speed to a port path cost [Table 17-3]. */
755 : : uint32_t
756 : 9 : rstp_convert_speed_to_cost(unsigned int speed)
757 : : {
758 : : uint32_t value;
759 : :
760 [ + - ][ + - ]: 9 : value = speed >= 10000000 ? 2 /* 10 Tb/s. */
[ + - ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
761 : : : speed >= 1000000 ? 20 /* 1 Tb/s. */
762 : : : speed >= 100000 ? 200 /* 100 Gb/s. */
763 : : : speed >= 10000 ? 2000 /* 10 Gb/s. */
764 : : : speed >= 1000 ? 20000 /* 1 Gb/s. */
765 : : : speed >= 100 ? 200000 /* 100 Mb/s. */
766 : : : speed >= 10 ? 2000000 /* 10 Mb/s. */
767 : : : speed >= 1 ? 20000000 /* 1 Mb/s. */
768 : : : RSTP_DEFAULT_PORT_PATH_COST; /* 100 Mb/s. */
769 : :
770 : 9 : return value;
771 : : }
772 : :
773 : : /* Sets the port path cost. */
774 : : static void
775 : 641 : rstp_port_set_path_cost__(struct rstp_port *port, uint32_t path_cost)
776 : : OVS_REQUIRES(rstp_mutex)
777 : : {
778 [ + + ]: 641 : if (port->port_path_cost != path_cost
779 [ + - ]: 525 : && path_cost >= RSTP_MIN_PORT_PATH_COST
780 [ + - ]: 525 : && path_cost <= RSTP_MAX_PORT_PATH_COST) {
781 [ - + ]: 525 : VLOG_DBG("%s, port %u, set RSTP port path cost to %d",
782 : : port->rstp->name, port->port_number, path_cost);
783 : :
784 : 525 : port->port_path_cost = path_cost;
785 : 525 : port->selected = false;
786 : 525 : port->reselect = true;
787 : : }
788 : 641 : }
789 : :
790 : : /* Gets the root path cost. */
791 : : uint32_t
792 : 76 : rstp_get_root_path_cost(const struct rstp *rstp)
793 : : OVS_EXCLUDED(rstp_mutex)
794 : : {
795 : : uint32_t cost;
796 : :
797 : 76 : ovs_mutex_lock(&rstp_mutex);
798 : 76 : cost = rstp->root_priority.root_path_cost;
799 : 76 : ovs_mutex_unlock(&rstp_mutex);
800 : 76 : return cost;
801 : : }
802 : :
803 : : /* Finds a port which needs to flush its own MAC learning table. A NULL
804 : : * pointer is returned if no port needs to flush its MAC learning table.
805 : : * '*port' needs to be NULL in the first call to start the iteration. If
806 : : * '*port' is passed as non-NULL, it must be the value set by the last
807 : : * invocation of this function.
808 : : *
809 : : * This function may only be called by the thread that creates and deletes
810 : : * ports. Otherwise this function is not thread safe, as the returned
811 : : * '*port' could become stale before it is used in the next invocation. */
812 : : void *
813 : 188 : rstp_check_and_reset_fdb_flush(struct rstp *rstp, struct rstp_port **port)
814 : : OVS_EXCLUDED(rstp_mutex)
815 : : {
816 : 188 : void *aux = NULL;
817 : :
818 : 188 : ovs_mutex_lock(&rstp_mutex);
819 [ + + ]: 188 : if (*port == NULL) {
820 : : struct rstp_port *p;
821 : :
822 [ + + ][ - + ]: 328 : HMAP_FOR_EACH (p, node, &rstp->ports) {
823 [ + + ]: 144 : if (p->fdb_flush) {
824 : 2 : aux = p->aux;
825 : 2 : *port = p;
826 : 2 : goto out;
827 : : }
828 : : }
829 : : } else { /* continue */
830 : 2 : struct rstp_port *p = *port;
831 : :
832 [ - + ][ - + ]: 2 : HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
833 [ # # ]: 0 : if (p->fdb_flush) {
834 : 0 : aux = p->aux;
835 : 0 : *port = p;
836 : 0 : goto out;
837 : : }
838 : : }
839 : : }
840 : : /* No port needs flushing. */
841 : 186 : *port = NULL;
842 : : out:
843 : : /* fdb_flush should be reset by the filtering database
844 : : * once the entries are removed if rstp_version is TRUE, and
845 : : * immediately if stp_version is TRUE.*/
846 [ + + ]: 188 : if (*port != NULL) {
847 : 2 : (*port)->fdb_flush = false;
848 : : }
849 : 188 : ovs_mutex_unlock(&rstp_mutex);
850 : :
851 : 188 : return aux;
852 : : }
853 : :
854 : : /* Finds a port whose state has changed, and returns the aux pointer set for
855 : : * the port. A NULL pointer is returned when no changed port is found. On
856 : : * return '*portp' contains the pointer to the rstp port that changed, or NULL
857 : : * if no changed port can be found.
858 : : *
859 : : * If '*portp' is passed as non-NULL, it must be the value set by the last
860 : : * invocation of this function.
861 : : *
862 : : * This function may only be called by the thread that creates and deletes
863 : : * ports. Otherwise this function is not thread safe, as the returned
864 : : * '*portp' could become stale before it is used in the next invocation. */
865 : : void *
866 : 190 : rstp_get_next_changed_port_aux(struct rstp *rstp, struct rstp_port **portp)
867 : : {
868 : 190 : void *aux = NULL;
869 : :
870 : 190 : ovs_mutex_lock(&rstp_mutex);
871 [ + + ]: 190 : if (*portp == NULL) {
872 : : struct rstp_port *p;
873 : :
874 [ + + ][ - + ]: 326 : HMAP_FOR_EACH (p, node, &rstp->ports) {
875 [ + + ]: 144 : if (p->state_changed) {
876 : 4 : p->state_changed = false;
877 : 4 : aux = p->aux;
878 : 4 : *portp = p;
879 : 4 : goto out;
880 : : }
881 : : }
882 : : } else { /* continue */
883 : 4 : struct rstp_port *p = *portp;
884 : :
885 [ - + ][ - + ]: 4 : HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
886 [ # # ]: 0 : if (p->state_changed) {
887 : 0 : p->state_changed = false;
888 : 0 : aux = p->aux;
889 : 0 : *portp = p;
890 : 0 : goto out;
891 : : }
892 : : }
893 : : }
894 : : /* No changed port found. */
895 : 186 : *portp = NULL;
896 : : out:
897 : 190 : ovs_mutex_unlock(&rstp_mutex);
898 : :
899 : 190 : return aux;
900 : : }
901 : :
902 : : bool
903 : 190 : rstp_shift_root_learned_address(struct rstp *rstp)
904 : : {
905 : : bool ret;
906 : :
907 : 190 : ovs_mutex_lock(&rstp_mutex);
908 : 190 : ret = rstp->root_changed;
909 : 190 : ovs_mutex_unlock(&rstp_mutex);
910 : :
911 : 190 : return ret;
912 : : }
913 : :
914 : : void *
915 : 0 : rstp_get_old_root_aux(struct rstp *rstp)
916 : : {
917 : : void *aux;
918 : :
919 : 0 : ovs_mutex_lock(&rstp_mutex);
920 : 0 : aux = rstp->old_root_aux;
921 : 0 : ovs_mutex_unlock(&rstp_mutex);
922 : :
923 : 0 : return aux;
924 : : }
925 : :
926 : : void *
927 : 0 : rstp_get_new_root_aux(struct rstp *rstp)
928 : : {
929 : : void *aux;
930 : :
931 : 0 : ovs_mutex_lock(&rstp_mutex);
932 : 0 : aux = rstp->new_root_aux;
933 : 0 : ovs_mutex_unlock(&rstp_mutex);
934 : :
935 : 0 : return aux;
936 : : }
937 : :
938 : : void
939 : 0 : rstp_reset_root_changed(struct rstp *rstp)
940 : : {
941 : 0 : ovs_mutex_lock(&rstp_mutex);
942 : 0 : rstp->root_changed = false;
943 : 0 : ovs_mutex_unlock(&rstp_mutex);
944 : 0 : }
945 : :
946 : : /* Returns the port in 'rstp' with number 'port_number'.
947 : : *
948 : : * XXX: May only be called while concurrent deletion of ports is excluded. */
949 : : static struct rstp_port *
950 : 9174 : rstp_get_port__(struct rstp *rstp, uint16_t port_number)
951 : : OVS_REQUIRES(rstp_mutex)
952 : : {
953 : : struct rstp_port *port;
954 : :
955 [ + - ][ + - ]: 9174 : ovs_assert(rstp && port_number > 0 && port_number <= RSTP_MAX_PORTS);
[ + - ][ - + ]
956 : :
957 [ + + ][ - + ]: 9174 : HMAP_FOR_EACH_WITH_HASH (port, node, hash_int(port_number, 0),
958 : : &rstp->ports) {
959 [ + - ]: 8938 : if (port->port_number == port_number) {
960 : 8938 : return port;
961 : : }
962 : : }
963 : 236 : return NULL;
964 : : }
965 : :
966 : : struct rstp_port *
967 : 7852 : rstp_get_port(struct rstp *rstp, uint16_t port_number)
968 : : OVS_EXCLUDED(rstp_mutex)
969 : : {
970 : : struct rstp_port *p;
971 : :
972 : 7852 : ovs_mutex_lock(&rstp_mutex);
973 : 7852 : p = rstp_get_port__(rstp, port_number);
974 : 7852 : ovs_mutex_unlock(&rstp_mutex);
975 : 7852 : return p;
976 : : }
977 : :
978 : : void *
979 : 141 : rstp_get_port_aux__(struct rstp *rstp, uint16_t port_number)
980 : : OVS_REQUIRES(rstp_mutex)
981 : : {
982 : : struct rstp_port *p;
983 : 141 : p = rstp_get_port__(rstp, port_number);
984 [ + - ]: 141 : if (p) {
985 : 141 : return p->aux;
986 : : }
987 : 0 : return NULL;
988 : : }
989 : :
990 : : /* Updates the port_enabled parameter. */
991 : : static void
992 : 1394 : update_port_enabled__(struct rstp_port *p)
993 : : OVS_REQUIRES(rstp_mutex)
994 : : {
995 [ + + ][ + - ]: 1394 : if (p->mac_operational && p->is_administrative_bridge_port
996 : : == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED) {
997 : 344 : p->port_enabled = true;
998 : : } else {
999 : 1050 : p->port_enabled = false;
1000 : : }
1001 : 1394 : }
1002 : :
1003 : : /* Sets the port MAC_Operational parameter [6.4.2]. */
1004 : : void
1005 : 535 : rstp_port_set_mac_operational(struct rstp_port *p, bool new_mac_operational)
1006 : : OVS_EXCLUDED(rstp_mutex)
1007 : : {
1008 : : struct rstp *rstp;
1009 : :
1010 : 535 : ovs_mutex_lock(&rstp_mutex);
1011 : 535 : rstp = p->rstp;
1012 [ + + ]: 535 : if (p->mac_operational != new_mac_operational) {
1013 : 346 : p->mac_operational = new_mac_operational;
1014 : 346 : update_port_enabled__(p);
1015 : 346 : rstp->changes = true;
1016 : 346 : move_rstp__(rstp);
1017 : : }
1018 : 535 : ovs_mutex_unlock(&rstp_mutex);
1019 : 535 : }
1020 : :
1021 : : /* Sets the port Administrative Bridge Port parameter. */
1022 : : static void
1023 : 533 : rstp_port_set_administrative_bridge_port__(struct rstp_port *p,
1024 : : uint8_t admin_port_state,
1025 : : bool initializing)
1026 : : OVS_REQUIRES(rstp_mutex)
1027 : : {
1028 [ - + ]: 533 : VLOG_DBG("%s, port %u: set RSTP port admin-port-state to %d",
1029 : : p->rstp->name, p->port_number, admin_port_state);
1030 : :
1031 [ + + ]: 533 : if (p->is_administrative_bridge_port != admin_port_state
1032 [ + - ]: 524 : && (admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED
1033 [ + - ]: 524 : || admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED)) {
1034 : 524 : p->is_administrative_bridge_port = admin_port_state;
1035 : 524 : update_port_enabled__(p);
1036 : :
1037 [ - + ]: 524 : if (!initializing) {
1038 : 0 : struct rstp *rstp = p->rstp;
1039 : :
1040 : 0 : rstp->changes = true;
1041 : 0 : move_rstp__(rstp);
1042 : : }
1043 : : }
1044 : 533 : }
1045 : :
1046 : : /* Sets the port oper_point_to_point_mac parameter. */
1047 : : static void
1048 : 526 : rstp_port_set_oper_point_to_point_mac__(struct rstp_port *p,
1049 : : uint8_t new_oper_p2p_mac)
1050 : : OVS_REQUIRES(rstp_mutex)
1051 : : {
1052 [ + + ]: 526 : if (p->oper_point_to_point_mac != new_oper_p2p_mac
1053 [ + - ]: 524 : && (new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_DISABLED
1054 [ + - ]: 524 : || new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_ENABLED)) {
1055 : :
1056 : 524 : p->oper_point_to_point_mac = new_oper_p2p_mac;
1057 : 524 : update_port_enabled__(p);
1058 : : }
1059 : 526 : }
1060 : :
1061 : : /* Initializes a port with the defaults values for its parameters. */
1062 : : static void
1063 : 524 : rstp_initialize_port_defaults__(struct rstp_port *p)
1064 : : OVS_REQUIRES(rstp_mutex)
1065 : : {
1066 : 524 : rstp_port_set_administrative_bridge_port__(p,
1067 : : RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED,
1068 : : true);
1069 : 524 : rstp_port_set_oper_point_to_point_mac__(p,
1070 : : RSTP_OPER_P2P_MAC_STATE_ENABLED);
1071 : 524 : rstp_port_set_path_cost__(p, RSTP_DEFAULT_PORT_PATH_COST);
1072 : 524 : rstp_port_set_admin_edge__(p, false);
1073 : 524 : rstp_port_set_auto_edge__(p, true);
1074 : 524 : rstp_port_set_mcheck__(p, false);
1075 : :
1076 : : /* Initialize state machines. */
1077 : 524 : p->port_receive_sm_state = PORT_RECEIVE_SM_INIT;
1078 : 524 : p->port_protocol_migration_sm_state = PORT_PROTOCOL_MIGRATION_SM_INIT;
1079 : 524 : p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_INIT;
1080 : 524 : p->port_transmit_sm_state = PORT_TRANSMIT_SM_INIT;
1081 : 524 : p->port_information_sm_state = PORT_INFORMATION_SM_INIT;
1082 : 524 : p->port_role_transition_sm_state = PORT_ROLE_TRANSITION_SM_INIT;
1083 : 524 : p->port_state_transition_sm_state = PORT_STATE_TRANSITION_SM_INIT;
1084 : 524 : p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_INIT;
1085 : 524 : p->uptime = 0;
1086 : :
1087 : 524 : }
1088 : :
1089 : : static void
1090 : 288 : reinitialize_port__(struct rstp_port *p)
1091 : : OVS_REQUIRES(rstp_mutex)
1092 : : {
1093 : : struct rstp_port temp_port;
1094 : : struct rstp *rstp;
1095 : :
1096 : 288 : rstp = p->rstp;
1097 : 288 : temp_port = *p;
1098 : 288 : memset(p, 0, sizeof(struct rstp_port));
1099 : :
1100 : 288 : p->ref_cnt = temp_port.ref_cnt;
1101 : 288 : p->rstp = rstp;
1102 : 288 : p->node = temp_port.node;
1103 : 288 : p->aux = temp_port.aux;
1104 : 288 : p->port_number = temp_port.port_number;
1105 : 288 : p->port_priority = temp_port.port_priority;
1106 : 288 : p->port_id = temp_port.port_id;
1107 : 288 : p->rstp_state = RSTP_DISCARDING;
1108 : :
1109 : 288 : rstp_initialize_port_defaults__(p);
1110 : :
1111 [ - + ]: 288 : VLOG_DBG("%s: RSTP port "RSTP_PORT_ID_FMT" reinitialized.", rstp->name,
1112 : : p->port_id);
1113 : 288 : }
1114 : :
1115 : : void
1116 : 288 : reinitialize_port(struct rstp_port *p)
1117 : : OVS_EXCLUDED(rstp_mutex)
1118 : : {
1119 : 288 : ovs_mutex_lock(&rstp_mutex);
1120 : 288 : reinitialize_port__(p);
1121 : 288 : ovs_mutex_unlock(&rstp_mutex);
1122 : 288 : }
1123 : :
1124 : : /* Sets the port state. */
1125 : : void
1126 : 1934 : rstp_port_set_state__(struct rstp_port *p, enum rstp_state state)
1127 : : OVS_REQUIRES(rstp_mutex)
1128 : : {
1129 : : struct rstp *rstp;
1130 : :
1131 : 1934 : rstp = p->rstp;
1132 [ - + ]: 1934 : VLOG_DBG("%s, port %u: set RSTP port state %s -> %s", rstp->name,
1133 : : p->port_number,
1134 : : rstp_state_name(p->rstp_state), rstp_state_name(state));
1135 : :
1136 [ + + ][ + + ]: 1934 : if (state != p->rstp_state && !p->state_changed) {
1137 : 526 : p->state_changed = true;
1138 : 526 : seq_change(connectivity_seq_get());
1139 : : }
1140 : 1934 : p->rstp_state = state;
1141 : 1934 : }
1142 : :
1143 : : void
1144 : 524 : rstp_port_set_state(struct rstp_port *p, enum rstp_state state)
1145 : : OVS_EXCLUDED(rstp_mutex)
1146 : : {
1147 : 524 : ovs_mutex_lock(&rstp_mutex);
1148 : 524 : rstp_port_set_state__(p, state);
1149 : 524 : ovs_mutex_unlock(&rstp_mutex);
1150 : 524 : }
1151 : :
1152 : : /* Adds a RSTP port. */
1153 : : struct rstp_port *
1154 : 236 : rstp_add_port(struct rstp *rstp)
1155 : : OVS_EXCLUDED(rstp_mutex)
1156 : : {
1157 : 236 : struct rstp_port *p = xzalloc(sizeof *p);
1158 : :
1159 : 236 : ovs_refcount_init(&p->ref_cnt);
1160 : 236 : hmap_node_nullify(&p->node);
1161 : :
1162 : 236 : ovs_mutex_lock(&rstp_mutex);
1163 : 236 : p->rstp = rstp;
1164 : 236 : rstp_port_set_priority__(p, RSTP_DEFAULT_PORT_PRIORITY);
1165 : 236 : rstp_port_set_port_number__(p, 0);
1166 : 236 : p->aux = NULL;
1167 : 236 : rstp_initialize_port_defaults__(p);
1168 [ - + ]: 236 : VLOG_DBG("%s: RSTP port "RSTP_PORT_ID_FMT" initialized.", rstp->name,
1169 : : p->port_id);
1170 : :
1171 : 236 : rstp_port_set_state__(p, RSTP_DISCARDING);
1172 : 236 : rstp->changes = true;
1173 : 236 : move_rstp__(rstp);
1174 [ - + ]: 236 : VLOG_DBG("%s: added port "RSTP_PORT_ID_FMT"", rstp->name, p->port_id);
1175 : 236 : ovs_mutex_unlock(&rstp_mutex);
1176 : 236 : return p;
1177 : : }
1178 : :
1179 : : /* Caller has to hold a reference to prevent 'rstp_port' from being deleted
1180 : : * while taking a new reference. */
1181 : : struct rstp_port *
1182 : 60 : rstp_port_ref(const struct rstp_port *rp_)
1183 : : OVS_EXCLUDED(rstp_mutex)
1184 : : {
1185 : 60 : struct rstp_port *rp = CONST_CAST(struct rstp_port *, rp_);
1186 : :
1187 [ + - ]: 60 : if (rp) {
1188 : 60 : ovs_refcount_ref(&rp->ref_cnt);
1189 : : }
1190 : 60 : return rp;
1191 : : }
1192 : :
1193 : : /* Frees RSTP struct. This can be caller by any thread. */
1194 : : void
1195 : 246793 : rstp_port_unref(struct rstp_port *rp)
1196 : : OVS_EXCLUDED(rstp_mutex)
1197 : : {
1198 [ + + ][ + + ]: 246793 : if (rp && ovs_refcount_unref_relaxed(&rp->ref_cnt) == 1) {
1199 : : struct rstp *rstp;
1200 : :
1201 : 236 : ovs_mutex_lock(&rstp_mutex);
1202 : 236 : rstp = rp->rstp;
1203 : 236 : rstp_port_set_state__(rp, RSTP_DISABLED);
1204 : 236 : hmap_remove(&rstp->ports, &rp->node);
1205 [ - + ]: 236 : VLOG_DBG("%s: removed port "RSTP_PORT_ID_FMT"", rstp->name,
1206 : : rp->port_id);
1207 : 236 : ovs_mutex_unlock(&rstp_mutex);
1208 : 236 : free(rp);
1209 : : }
1210 : 246793 : }
1211 : :
1212 : : /* Sets the port Admin Edge parameter. */
1213 : : static void
1214 : 533 : rstp_port_set_admin_edge__(struct rstp_port *port, bool admin_edge)
1215 : : OVS_REQUIRES(rstp_mutex)
1216 : : {
1217 [ - + ]: 533 : if (port->admin_edge != admin_edge) {
1218 [ # # ]: 0 : VLOG_DBG("%s, port %u: set RSTP Admin Edge to %d", port->rstp->name,
1219 : : port->port_number, admin_edge);
1220 : :
1221 : 0 : port->admin_edge = admin_edge;
1222 : : }
1223 : 533 : }
1224 : :
1225 : : /* Sets the port Auto Edge parameter. */
1226 : : static void
1227 : 533 : rstp_port_set_auto_edge__(struct rstp_port *port, bool auto_edge)
1228 : : OVS_REQUIRES(rstp_mutex)
1229 : : {
1230 [ + + ]: 533 : if (port->auto_edge != auto_edge) {
1231 [ - + ]: 524 : VLOG_DBG("%s, port %u: set RSTP Auto Edge to %d", port->rstp->name,
1232 : : port->port_number, auto_edge);
1233 : :
1234 : 524 : port->auto_edge = auto_edge;
1235 : : }
1236 : 533 : }
1237 : :
1238 : : /* Sets the port admin_point_to_point_mac parameter. */
1239 : 9 : static void rstp_port_set_admin_point_to_point_mac__(struct rstp_port *port,
1240 : : enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state)
1241 : : OVS_REQUIRES(rstp_mutex)
1242 : : {
1243 [ - + ]: 9 : VLOG_DBG("%s, port %u: set RSTP port admin-point-to-point-mac to %d",
1244 : : port->rstp->name, port->port_number, admin_p2p_mac_state);
1245 [ + + ]: 9 : if (port->admin_point_to_point_mac != admin_p2p_mac_state) {
1246 [ + - ]: 2 : if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_FORCE_TRUE) {
1247 : 2 : port->admin_point_to_point_mac = admin_p2p_mac_state;
1248 : 2 : rstp_port_set_oper_point_to_point_mac__(
1249 : : port, RSTP_OPER_P2P_MAC_STATE_ENABLED);
1250 [ # # ]: 0 : } else if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_FORCE_FALSE) {
1251 : 0 : port->admin_point_to_point_mac = admin_p2p_mac_state;
1252 : 0 : rstp_port_set_oper_point_to_point_mac__(
1253 : : port, RSTP_OPER_P2P_MAC_STATE_DISABLED);
1254 [ # # ]: 0 : } else if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_AUTO) {
1255 : : /* If adminPointToPointMAC is set to Auto, then the value of
1256 : : * operPointToPointMAC is determined in accordance with the
1257 : : * specific procedures defined for the MAC entity concerned, as
1258 : : * defined in 6.5. If these procedures determine that the MAC
1259 : : * entity is connected to a point-to-point LAN, then
1260 : : * operPointToPointMAC is set TRUE; otherwise it is set FALSE.
1261 : : * In the absence of a specific definition of how to determine
1262 : : * whether the MAC is connected to a point-to-point LAN or not,
1263 : : * the value of operPointToPointMAC shall be FALSE. */
1264 : 0 : port->admin_point_to_point_mac = admin_p2p_mac_state;
1265 : 0 : rstp_port_set_oper_point_to_point_mac__(
1266 : : port, RSTP_OPER_P2P_MAC_STATE_DISABLED);
1267 : : }
1268 : : }
1269 : 9 : }
1270 : :
1271 : : /* Sets the port mcheck parameter.
1272 : : * [17.19.13] May be set by management to force the Port Protocol Migration
1273 : : * state machine to transmit RST BPDUs for a MigrateTime (17.13.9) period, to
1274 : : * test whether all STP Bridges (17.4) on the attached LAN have been removed
1275 : : * and the Port can continue to transmit RSTP BPDUs. Setting mcheck has no
1276 : : * effect if stpVersion (17.20.12) is TRUE, i.e., the Bridge is operating in
1277 : : * STP Compatibility mode.
1278 : : */
1279 : : static void
1280 : 533 : rstp_port_set_mcheck__(struct rstp_port *port, bool mcheck)
1281 : : OVS_REQUIRES(rstp_mutex)
1282 : : {
1283 [ - + ][ # # ]: 533 : if (mcheck == true && port->rstp->force_protocol_version >= 2) {
1284 : 0 : port->mcheck = true;
1285 : :
1286 [ # # ]: 0 : VLOG_DBG("%s, port %u: set RSTP mcheck to %d", port->rstp->name,
1287 : : port->port_number, mcheck);
1288 : : }
1289 : 533 : }
1290 : :
1291 : : /* Returns the designated bridge id. */
1292 : : rstp_identifier
1293 : 25 : rstp_get_designated_id(const struct rstp *rstp)
1294 : : OVS_EXCLUDED(rstp_mutex)
1295 : : {
1296 : : rstp_identifier designated_id;
1297 : :
1298 : 25 : ovs_mutex_lock(&rstp_mutex);
1299 : 25 : designated_id = rstp->root_priority.designated_bridge_id;
1300 : 25 : ovs_mutex_unlock(&rstp_mutex);
1301 : :
1302 : 25 : return designated_id;
1303 : : }
1304 : :
1305 : : /* Returns the root bridge id. */
1306 : : rstp_identifier
1307 : 25 : rstp_get_root_id(const struct rstp *rstp)
1308 : : OVS_EXCLUDED(rstp_mutex)
1309 : : {
1310 : : rstp_identifier root_id;
1311 : :
1312 : 25 : ovs_mutex_lock(&rstp_mutex);
1313 : 25 : root_id = rstp->root_priority.root_bridge_id;
1314 : 25 : ovs_mutex_unlock(&rstp_mutex);
1315 : :
1316 : 25 : return root_id;
1317 : : }
1318 : :
1319 : : /* Returns the designated port id. */
1320 : : uint16_t
1321 : 25 : rstp_get_designated_port_id(const struct rstp *rstp)
1322 : : OVS_EXCLUDED(rstp_mutex)
1323 : : {
1324 : : uint16_t designated_port_id;
1325 : :
1326 : 25 : ovs_mutex_lock(&rstp_mutex);
1327 : 25 : designated_port_id = rstp->root_priority.designated_port_id;
1328 : 25 : ovs_mutex_unlock(&rstp_mutex);
1329 : :
1330 : 25 : return designated_port_id;
1331 : : }
1332 : :
1333 : : /* Return the bridge port id. */
1334 : : uint16_t
1335 : 25 : rstp_get_bridge_port_id(const struct rstp *rstp)
1336 : : OVS_EXCLUDED(rstp_mutex)
1337 : : {
1338 : : uint16_t bridge_port_id;
1339 : :
1340 : 25 : ovs_mutex_lock(&rstp_mutex);
1341 : 25 : bridge_port_id = rstp->root_priority.bridge_port_id;
1342 : 25 : ovs_mutex_unlock(&rstp_mutex);
1343 : :
1344 : 25 : return bridge_port_id;
1345 : : }
1346 : :
1347 : : /* Returns true if the bridge believes to the be root of the spanning tree,
1348 : : * false otherwise.
1349 : : */
1350 : : bool
1351 : 11 : rstp_is_root_bridge(const struct rstp *rstp)
1352 : : OVS_EXCLUDED(rstp_mutex)
1353 : : {
1354 : : bool is_root;
1355 : :
1356 : 11 : ovs_mutex_lock(&rstp_mutex);
1357 : 22 : is_root = rstp->bridge_identifier ==
1358 : 11 : rstp->root_priority.designated_bridge_id;
1359 : 11 : ovs_mutex_unlock(&rstp_mutex);
1360 : :
1361 : 11 : return is_root;
1362 : : }
1363 : :
1364 : : /* Returns the bridge ID of the bridge currently believed to be the root. */
1365 : : rstp_identifier
1366 : 0 : rstp_get_designated_root(const struct rstp *rstp)
1367 : : OVS_EXCLUDED(rstp_mutex)
1368 : : {
1369 : : rstp_identifier designated_root;
1370 : :
1371 : 0 : ovs_mutex_lock(&rstp_mutex);
1372 : 0 : designated_root = rstp->root_priority.designated_bridge_id;
1373 : 0 : ovs_mutex_unlock(&rstp_mutex);
1374 : :
1375 : 0 : return designated_root;
1376 : : }
1377 : :
1378 : : /* Returns the port connecting 'rstp' to the root bridge, or a null pointer if
1379 : : * there is no such port.
1380 : : */
1381 : : struct rstp_port *
1382 : 124 : rstp_get_root_port(struct rstp *rstp)
1383 : : OVS_EXCLUDED(rstp_mutex)
1384 : : {
1385 : : struct rstp_port *p;
1386 : :
1387 : 124 : ovs_mutex_lock(&rstp_mutex);
1388 [ + - ][ # # ]: 616 : HMAP_FOR_EACH (p, node, &rstp->ports) {
1389 [ + + ]: 616 : if (p->port_id == rstp->root_port_id) {
1390 : 124 : ovs_mutex_unlock(&rstp_mutex);
1391 : 124 : return p;
1392 : : }
1393 : : }
1394 : 0 : ovs_mutex_unlock(&rstp_mutex);
1395 : 0 : return NULL;
1396 : : }
1397 : :
1398 : : /* Returns the state of port 'p'. */
1399 : : enum rstp_state
1400 : 193 : rstp_port_get_state(const struct rstp_port *p)
1401 : : OVS_EXCLUDED(rstp_mutex)
1402 : : {
1403 : : enum rstp_state state;
1404 : :
1405 : 193 : ovs_mutex_lock(&rstp_mutex);
1406 : 193 : state = p->rstp_state;
1407 : 193 : ovs_mutex_unlock(&rstp_mutex);
1408 : :
1409 : 193 : return state;
1410 : : }
1411 : :
1412 : : /* Retrieves port status. */
1413 : : void
1414 : 22 : rstp_port_get_status(const struct rstp_port *p, uint16_t *id,
1415 : : enum rstp_state *state, enum rstp_port_role *role,
1416 : : rstp_identifier *designated_bridge_id,
1417 : : uint16_t *designated_port_id,
1418 : : uint32_t *designated_path_cost, int *tx_count,
1419 : : int *rx_count, int *error_count, int *uptime)
1420 : : OVS_EXCLUDED(rstp_mutex)
1421 : : {
1422 : 22 : ovs_mutex_lock(&rstp_mutex);
1423 : 22 : *id = p->port_id;
1424 : 22 : *state = p->rstp_state;
1425 : 22 : *role = p->role;
1426 : :
1427 : 22 : *designated_bridge_id = p->port_priority.designated_bridge_id;
1428 : 22 : *designated_port_id = p->port_priority.designated_port_id;
1429 : 22 : *designated_path_cost = p->port_priority.root_path_cost;
1430 : :
1431 : 22 : *tx_count = p->tx_count;
1432 : 22 : *rx_count = p->rx_rstp_bpdu_cnt;
1433 : 22 : *error_count = p->error_count;
1434 : 22 : *uptime = p->uptime;
1435 : 22 : ovs_mutex_unlock(&rstp_mutex);
1436 : 22 : }
1437 : :
1438 : : void
1439 : 9 : rstp_port_set(struct rstp_port *port, uint16_t port_num, int priority,
1440 : : uint32_t path_cost, bool is_admin_edge, bool is_auto_edge,
1441 : : enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state,
1442 : : bool admin_port_state, bool do_mcheck, void *aux)
1443 : : OVS_EXCLUDED(rstp_mutex)
1444 : : {
1445 : 9 : ovs_mutex_lock(&rstp_mutex);
1446 : 9 : port->aux = aux;
1447 : 9 : rstp_port_set_priority__(port, priority);
1448 : 9 : rstp_port_set_port_number__(port, port_num);
1449 : 9 : rstp_port_set_path_cost__(port, path_cost);
1450 : 9 : rstp_port_set_admin_edge__(port, is_admin_edge);
1451 : 9 : rstp_port_set_auto_edge__(port, is_auto_edge);
1452 : 9 : rstp_port_set_admin_point_to_point_mac__(port, admin_p2p_mac_state);
1453 : 9 : rstp_port_set_administrative_bridge_port__(port, admin_port_state, false);
1454 : 9 : rstp_port_set_mcheck__(port, do_mcheck);
1455 : 9 : ovs_mutex_unlock(&rstp_mutex);
1456 : 9 : }
1457 : :
1458 : : /* Individual setters only used by test-rstp.c. */
1459 : : void
1460 : 1 : rstp_port_set_priority(struct rstp_port *port, int priority)
1461 : : OVS_EXCLUDED(rstp_mutex)
1462 : : {
1463 : 1 : ovs_mutex_lock(&rstp_mutex);
1464 : 1 : rstp_port_set_priority__(port, priority);
1465 : 1 : ovs_mutex_unlock(&rstp_mutex);
1466 : 1 : }
1467 : :
1468 : : void
1469 : 108 : rstp_port_set_path_cost(struct rstp_port *port, uint32_t path_cost)
1470 : : OVS_EXCLUDED(rstp_mutex)
1471 : : {
1472 : 108 : ovs_mutex_lock(&rstp_mutex);
1473 : 108 : rstp_port_set_path_cost__(port, path_cost);
1474 : 108 : ovs_mutex_unlock(&rstp_mutex);
1475 : 108 : }
1476 : :
1477 : : void
1478 : 236 : rstp_port_set_aux(struct rstp_port *port, void *aux)
1479 : : OVS_EXCLUDED(rstp_mutex)
1480 : : {
1481 : 236 : ovs_mutex_lock(&rstp_mutex);
1482 : 236 : port->aux = aux;
1483 : 236 : ovs_mutex_unlock(&rstp_mutex);
1484 : 236 : }
1485 : :
1486 : : /* Unixctl. */
1487 : : static struct rstp *
1488 : 0 : rstp_find(const char *name)
1489 : : OVS_REQUIRES(rstp_mutex)
1490 : : {
1491 : : struct rstp *rstp;
1492 : :
1493 [ # # ]: 0 : LIST_FOR_EACH (rstp, node, all_rstps) {
1494 [ # # ]: 0 : if (!strcmp(rstp->name, name)) {
1495 : 0 : return rstp;
1496 : : }
1497 : : }
1498 : 0 : return NULL;
1499 : : }
1500 : :
1501 : : static void
1502 : 0 : rstp_unixctl_tcn(struct unixctl_conn *conn, int argc,
1503 : : const char *argv[], void *aux OVS_UNUSED)
1504 : : OVS_EXCLUDED(rstp_mutex)
1505 : : {
1506 : 0 : ovs_mutex_lock(&rstp_mutex);
1507 [ # # ]: 0 : if (argc > 1) {
1508 : 0 : struct rstp *rstp = rstp_find(argv[1]);
1509 [ # # ]: 0 : if (!rstp) {
1510 : 0 : unixctl_command_reply_error(conn, "No such RSTP object");
1511 : 0 : goto out;
1512 : : }
1513 : 0 : rstp->changes = true;
1514 : 0 : move_rstp__(rstp);
1515 : : } else {
1516 : : struct rstp *rstp;
1517 [ # # ]: 0 : LIST_FOR_EACH (rstp, node, all_rstps) {
1518 : 0 : rstp->changes = true;
1519 : 0 : move_rstp__(rstp);
1520 : : }
1521 : : }
1522 : 0 : unixctl_command_reply(conn, "OK");
1523 : :
1524 : : out:
1525 : 0 : ovs_mutex_unlock(&rstp_mutex);
1526 : 0 : }
|