]> git.proxmox.com Git - mirror_ovs.git/blame - lib/stp.c
ofproto-dpif-sflow: Fix memory leak.
[mirror_ovs.git] / lib / stp.c
CommitLineData
829a7d02 1/*
ebc56baa 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
829a7d02
JP
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/* Based on sample implementation in 802.1D-1998. Above copyright and license
18 * applies to all modifications. */
19
20#include <config.h>
21
22#include "stp.h"
23#include <sys/types.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
829a7d02
JP
26#include <inttypes.h>
27#include <stdlib.h>
28#include "byte-order.h"
29#include "ofpbuf.h"
30#include "packets.h"
fe4a02e4 31#include "unixctl.h"
829a7d02
JP
32#include "util.h"
33#include "vlog.h"
34
35VLOG_DEFINE_THIS_MODULE(stp);
36
37#define STP_PROTOCOL_ID 0x0000
38#define STP_PROTOCOL_VERSION 0x00
39#define STP_TYPE_CONFIG 0x00
40#define STP_TYPE_TCN 0x80
41
13b6bae6 42OVS_PACKED(
829a7d02
JP
43struct stp_bpdu_header {
44 ovs_be16 protocol_id; /* STP_PROTOCOL_ID. */
45 uint8_t protocol_version; /* STP_PROTOCOL_VERSION. */
46 uint8_t bpdu_type; /* One of STP_TYPE_*. */
13b6bae6 47});
829a7d02
JP
48BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header) == 4);
49
50enum stp_config_bpdu_flags {
51 STP_CONFIG_TOPOLOGY_CHANGE_ACK = 0x80,
52 STP_CONFIG_TOPOLOGY_CHANGE = 0x01
53};
54
13b6bae6 55OVS_PACKED(
829a7d02
JP
56struct stp_config_bpdu {
57 struct stp_bpdu_header header; /* Type STP_TYPE_CONFIG. */
58 uint8_t flags; /* STP_CONFIG_* flags. */
59 ovs_be64 root_id; /* 8.5.1.1: Bridge believed to be root. */
60 ovs_be32 root_path_cost; /* 8.5.1.2: Cost of path to root. */
61 ovs_be64 bridge_id; /* 8.5.1.3: ID of transmitting bridge. */
62 ovs_be16 port_id; /* 8.5.1.4: Port transmitting the BPDU. */
63 ovs_be16 message_age; /* 8.5.1.5: Age of BPDU at tx time. */
64 ovs_be16 max_age; /* 8.5.1.6: Timeout for received data. */
65 ovs_be16 hello_time; /* 8.5.1.7: Time between BPDU generation. */
66 ovs_be16 forward_delay; /* 8.5.1.8: State progression delay. */
13b6bae6 67});
829a7d02
JP
68BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu) == 35);
69
13b6bae6 70OVS_PACKED(
829a7d02
JP
71struct stp_tcn_bpdu {
72 struct stp_bpdu_header header; /* Type STP_TYPE_TCN. */
13b6bae6 73});
829a7d02
JP
74BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu) == 4);
75
76struct stp_timer {
77 bool active; /* Timer in use? */
78 int value; /* Current value of timer, counting up. */
79};
80
81struct stp_port {
82 struct stp *stp;
3310b570 83 void *aux; /* Auxiliary data the user may retrieve. */
829a7d02
JP
84 int port_id; /* 8.5.5.1: Unique port identifier. */
85 enum stp_state state; /* 8.5.5.2: Current state. */
86 int path_cost; /* 8.5.5.3: Cost of tx/rx on this port. */
87 stp_identifier designated_root; /* 8.5.5.4. */
88 int designated_cost; /* 8.5.5.5: Path cost to root on port. */
89 stp_identifier designated_bridge; /* 8.5.5.6. */
90 int designated_port; /* 8.5.5.7: Port to send config msgs on. */
91 bool topology_change_ack; /* 8.5.5.8: Flag for next config BPDU. */
92 bool config_pending; /* 8.5.5.9: Send BPDU when hold expires? */
93 bool change_detection_enabled; /* 8.5.5.10: Detect topology changes? */
94
95 struct stp_timer message_age_timer; /* 8.5.6.1: Age of received info. */
96 struct stp_timer forward_delay_timer; /* 8.5.6.2: State change timer. */
97 struct stp_timer hold_timer; /* 8.5.6.3: BPDU rate limit timer. */
98
80740385
JP
99 int tx_count; /* Number of BPDUs transmitted. */
100 int rx_count; /* Number of valid BPDUs received. */
101 int error_count; /* Number of bad BPDUs received. */
102
829a7d02
JP
103 bool state_changed;
104};
105
106struct stp {
fe4a02e4
EJ
107 struct list node; /* Node in all_stps list. */
108
829a7d02
JP
109 /* Static bridge data. */
110 char *name; /* Human-readable name for log messages. */
111 stp_identifier bridge_id; /* 8.5.3.7: This bridge. */
112 int max_age; /* 8.5.3.4: Time to drop received data. */
113 int hello_time; /* 8.5.3.5: Time between sending BPDUs. */
114 int forward_delay; /* 8.5.3.6: Delay between state changes. */
115 int bridge_max_age; /* 8.5.3.8: max_age when we're root. */
116 int bridge_hello_time; /* 8.5.3.9: hello_time as root. */
117 int bridge_forward_delay; /* 8.5.3.10: forward_delay as root. */
118 int rq_max_age; /* User-requested max age, in ms. */
119 int rq_hello_time; /* User-requested hello time, in ms. */
120 int rq_forward_delay; /* User-requested forward delay, in ms. */
121 int elapsed_remainder; /* Left-over msecs from last stp_tick(). */
122
123 /* Dynamic bridge data. */
124 stp_identifier designated_root; /* 8.5.3.1: Bridge believed to be root. */
125 unsigned int root_path_cost; /* 8.5.3.2: Cost of path to root. */
126 struct stp_port *root_port; /* 8.5.3.3: Lowest cost port to root. */
127 bool topology_change_detected; /* 8.5.3.11: Detected a topology change? */
128 bool topology_change; /* 8.5.3.12: Received topology change? */
129
130 /* Bridge timers. */
131 struct stp_timer hello_timer; /* 8.5.4.1: Hello timer. */
132 struct stp_timer tcn_timer; /* 8.5.4.2: Topology change timer. */
133 struct stp_timer topology_change_timer; /* 8.5.4.3. */
134
135 /* Ports. */
136 struct stp_port ports[STP_MAX_PORTS];
137
138 /* Interface to client. */
6ae50723 139 bool fdb_needs_flush; /* MAC learning tables needs flushing. */
829a7d02
JP
140 struct stp_port *first_changed_port;
141 void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
142 void *aux;
bd54dbcd
EJ
143
144 atomic_int ref_cnt;
829a7d02
JP
145};
146
bd54dbcd
EJ
147static struct ovs_mutex mutex;
148static struct list all_stps__ = LIST_INITIALIZER(&all_stps__);
344e21d4 149static struct list *const all_stps OVS_GUARDED_BY(mutex) = &all_stps__;
fe4a02e4 150
829a7d02
JP
151#define FOR_EACH_ENABLED_PORT(PORT, STP) \
152 for ((PORT) = stp_next_enabled_port((STP), (STP)->ports); \
153 (PORT); \
154 (PORT) = stp_next_enabled_port((STP), (PORT) + 1))
155static struct stp_port *
156stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
bd3950dd 157 OVS_REQUIRES(mutex)
829a7d02
JP
158{
159 for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
160 if (port->state != STP_DISABLED) {
ebc56baa 161 return CONST_CAST(struct stp_port *, port);
829a7d02
JP
162 }
163 }
164 return NULL;
165}
166
167#define MESSAGE_AGE_INCREMENT 1
168
bd3950dd 169static void stp_transmit_config(struct stp_port *) OVS_REQUIRES(mutex);
829a7d02 170static bool stp_supersedes_port_info(const struct stp_port *,
bd54dbcd 171 const struct stp_config_bpdu *)
bd3950dd 172 OVS_REQUIRES(mutex);
829a7d02 173static void stp_record_config_information(struct stp_port *,
bd54dbcd 174 const struct stp_config_bpdu *)
bd3950dd 175 OVS_REQUIRES(mutex);
829a7d02 176static void stp_record_config_timeout_values(struct stp *,
bd54dbcd 177 const struct stp_config_bpdu *)
bd3950dd 178 OVS_REQUIRES(mutex);
bd54dbcd 179static bool stp_is_designated_port(const struct stp_port *)
bd3950dd
AW
180 OVS_REQUIRES(mutex);
181static void stp_config_bpdu_generation(struct stp *) OVS_REQUIRES(mutex);
182static void stp_transmit_tcn(struct stp *) OVS_REQUIRES(mutex);
183static void stp_configuration_update(struct stp *) OVS_REQUIRES(mutex);
829a7d02 184static bool stp_supersedes_root(const struct stp_port *root,
bd3950dd
AW
185 const struct stp_port *) OVS_REQUIRES(mutex);
186static void stp_root_selection(struct stp *) OVS_REQUIRES(mutex);
187static void stp_designated_port_selection(struct stp *) OVS_REQUIRES(mutex);
bd54dbcd 188static void stp_become_designated_port(struct stp_port *)
bd3950dd
AW
189 OVS_REQUIRES(mutex);
190static void stp_port_state_selection(struct stp *) OVS_REQUIRES(mutex);
191static void stp_make_forwarding(struct stp_port *) OVS_REQUIRES(mutex);
192static void stp_make_blocking(struct stp_port *) OVS_REQUIRES(mutex);
bd54dbcd 193static void stp_set_port_state(struct stp_port *, enum stp_state)
bd3950dd
AW
194 OVS_REQUIRES(mutex);
195static void stp_topology_change_detection(struct stp *) OVS_REQUIRES(mutex);
bd54dbcd 196static void stp_topology_change_acknowledged(struct stp *)
bd3950dd 197 OVS_REQUIRES(mutex);
bd54dbcd 198static void stp_acknowledge_topology_change(struct stp_port *)
bd3950dd 199 OVS_REQUIRES(mutex);
829a7d02 200static void stp_received_config_bpdu(struct stp *, struct stp_port *,
bd54dbcd 201 const struct stp_config_bpdu *)
bd3950dd 202 OVS_REQUIRES(mutex);
bd54dbcd 203static void stp_received_tcn_bpdu(struct stp *, struct stp_port *)
bd3950dd
AW
204 OVS_REQUIRES(mutex);
205static void stp_hello_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
bd54dbcd 206static void stp_message_age_timer_expiry(struct stp_port *)
bd3950dd 207 OVS_REQUIRES(mutex);
bd54dbcd 208static bool stp_is_designated_for_some_port(const struct stp *)
bd3950dd 209 OVS_REQUIRES(mutex);
bd54dbcd 210static void stp_forward_delay_timer_expiry(struct stp_port *)
bd3950dd
AW
211 OVS_REQUIRES(mutex);
212static void stp_tcn_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
bd54dbcd 213static void stp_topology_change_timer_expiry(struct stp *)
bd3950dd
AW
214 OVS_REQUIRES(mutex);
215static void stp_hold_timer_expiry(struct stp_port *) OVS_REQUIRES(mutex);
bd54dbcd 216static void stp_initialize_port(struct stp_port *, enum stp_state)
bd3950dd
AW
217 OVS_REQUIRES(mutex);
218static void stp_become_root_bridge(struct stp *) OVS_REQUIRES(mutex);
219static void stp_update_bridge_timers(struct stp *) OVS_REQUIRES(mutex);
829a7d02
JP
220
221static int clamp(int x, int min, int max);
222static int ms_to_timer(int ms);
829a7d02
JP
223static int timer_to_ms(int timer);
224static void stp_start_timer(struct stp_timer *, int value);
225static void stp_stop_timer(struct stp_timer *);
226static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
227
bd54dbcd 228static void stp_send_bpdu(struct stp_port *, const void *, size_t)
bd3950dd 229 OVS_REQUIRES(mutex);
fe4a02e4
EJ
230static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
231 const char *argv[], void *aux);
232
233void
234stp_init(void)
235{
236 unixctl_command_register("stp/tcn", "[bridge]", 0, 1, stp_unixctl_tcn,
237 NULL);
238}
829a7d02
JP
239
240/* Creates and returns a new STP instance that initially has no ports enabled.
241 *
242 * 'bridge_id' should be a 48-bit MAC address as returned by
243 * eth_addr_to_uint64(). 'bridge_id' may also have a priority value in its top
244 * 16 bits; if those bits are set to 0, STP_DEFAULT_BRIDGE_PRIORITY is used.
245 * (This priority may be changed with stp_set_bridge_priority().)
246 *
247 * When the bridge needs to send out a BPDU, it calls 'send_bpdu'. This
248 * callback may be called from stp_tick() or stp_received_bpdu(). The
249 * arguments to 'send_bpdu' are an STP BPDU encapsulated in 'bpdu',
250 * the spanning tree port number 'port_no' that should transmit the
251 * packet, and auxiliary data to be passed to the callback in 'aux'.
252 */
253struct stp *
254stp_create(const char *name, stp_identifier bridge_id,
255 void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux),
256 void *aux)
257{
bd54dbcd 258 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
829a7d02
JP
259 struct stp *stp;
260 struct stp_port *p;
261
bd54dbcd
EJ
262 if (ovsthread_once_start(&once)) {
263 /* We need a recursive mutex because stp_send_bpdu() could loop back
264 * into the stp module through a patch port. This happens
265 * intentionally as part of the unit tests. Ideally we'd ditch
266 * the call back function, but for now this is what we have. */
267 ovs_mutex_init(&mutex, PTHREAD_MUTEX_RECURSIVE);
268 ovsthread_once_done(&once);
269 }
270
271 ovs_mutex_lock(&mutex);
829a7d02
JP
272 stp = xzalloc(sizeof *stp);
273 stp->name = xstrdup(name);
274 stp->bridge_id = bridge_id;
275 if (!(stp->bridge_id >> 48)) {
276 stp->bridge_id |= (uint64_t) STP_DEFAULT_BRIDGE_PRIORITY << 48;
277 }
278
3310b570
JP
279 stp->rq_max_age = STP_DEFAULT_MAX_AGE;
280 stp->rq_hello_time = STP_DEFAULT_HELLO_TIME;
281 stp->rq_forward_delay = STP_DEFAULT_FWD_DELAY;
829a7d02
JP
282 stp_update_bridge_timers(stp);
283 stp->max_age = stp->bridge_max_age;
284 stp->hello_time = stp->bridge_hello_time;
285 stp->forward_delay = stp->bridge_forward_delay;
286
287 stp->designated_root = stp->bridge_id;
288 stp->root_path_cost = 0;
289 stp->root_port = NULL;
290 stp->topology_change_detected = false;
291 stp->topology_change = false;
292
293 stp_stop_timer(&stp->tcn_timer);
294 stp_stop_timer(&stp->topology_change_timer);
295 stp_start_timer(&stp->hello_timer, 0);
296
297 stp->send_bpdu = send_bpdu;
298 stp->aux = aux;
299
300 stp->first_changed_port = &stp->ports[ARRAY_SIZE(stp->ports)];
301 for (p = stp->ports; p < &stp->ports[ARRAY_SIZE(stp->ports)]; p++) {
302 p->stp = stp;
303 p->port_id = (stp_port_no(p) + 1) | (STP_DEFAULT_PORT_PRIORITY << 8);
304 p->path_cost = 19; /* Recommended default for 100 Mb/s link. */
305 stp_initialize_port(p, STP_DISABLED);
306 }
bd54dbcd
EJ
307 atomic_init(&stp->ref_cnt, 1);
308
309 list_push_back(all_stps, &stp->node);
310 ovs_mutex_unlock(&mutex);
311 return stp;
312}
313
314struct stp *
315stp_ref(const struct stp *stp_)
316{
317 struct stp *stp = CONST_CAST(struct stp *, stp_);
318 if (stp) {
319 int orig;
320 atomic_add(&stp->ref_cnt, 1, &orig);
321 ovs_assert(orig > 0);
322 }
829a7d02
JP
323 return stp;
324}
325
326/* Destroys 'stp'. */
327void
bd54dbcd 328stp_unref(struct stp *stp)
829a7d02 329{
bd54dbcd
EJ
330 int orig;
331
332 if (!stp) {
333 return;
334 }
335
336 atomic_sub(&stp->ref_cnt, 1, &orig);
337 ovs_assert(orig > 0);
338 if (orig == 1) {
339 ovs_mutex_lock(&mutex);
fe4a02e4 340 list_remove(&stp->node);
bd54dbcd 341 ovs_mutex_unlock(&mutex);
829a7d02
JP
342 free(stp->name);
343 free(stp);
344 }
345}
346
347/* Runs 'stp' given that 'ms' milliseconds have passed. */
348void
349stp_tick(struct stp *stp, int ms)
350{
351 struct stp_port *p;
352 int elapsed;
353
bd54dbcd 354 ovs_mutex_lock(&mutex);
829a7d02
JP
355 /* Convert 'ms' to STP timer ticks. Preserve any leftover milliseconds
356 * from previous stp_tick() calls so that we don't lose STP ticks when we
357 * are called too frequently. */
358 ms = clamp(ms, 0, INT_MAX - 1000) + stp->elapsed_remainder;
359 elapsed = ms_to_timer(ms);
ba25773f 360 stp->elapsed_remainder = ms - timer_to_ms(elapsed);
829a7d02 361 if (!elapsed) {
bd54dbcd 362 goto out;
829a7d02
JP
363 }
364
365 if (stp_timer_expired(&stp->hello_timer, elapsed, stp->hello_time)) {
366 stp_hello_timer_expiry(stp);
367 }
368 if (stp_timer_expired(&stp->tcn_timer, elapsed, stp->bridge_hello_time)) {
369 stp_tcn_timer_expiry(stp);
370 }
371 if (stp_timer_expired(&stp->topology_change_timer, elapsed,
372 stp->max_age + stp->forward_delay)) {
373 stp_topology_change_timer_expiry(stp);
374 }
375 FOR_EACH_ENABLED_PORT (p, stp) {
376 if (stp_timer_expired(&p->message_age_timer, elapsed, stp->max_age)) {
377 stp_message_age_timer_expiry(p);
378 }
379 }
380 FOR_EACH_ENABLED_PORT (p, stp) {
381 if (stp_timer_expired(&p->forward_delay_timer, elapsed,
382 stp->forward_delay)) {
383 stp_forward_delay_timer_expiry(p);
384 }
385 if (stp_timer_expired(&p->hold_timer, elapsed, ms_to_timer(1000))) {
386 stp_hold_timer_expiry(p);
387 }
388 }
bd54dbcd
EJ
389
390out:
391 ovs_mutex_unlock(&mutex);
829a7d02
JP
392}
393
394static void
395set_bridge_id(struct stp *stp, stp_identifier new_bridge_id)
bd3950dd 396 OVS_REQUIRES(mutex)
829a7d02
JP
397{
398 if (new_bridge_id != stp->bridge_id) {
399 bool root;
400 struct stp_port *p;
401
402 root = stp_is_root_bridge(stp);
403 FOR_EACH_ENABLED_PORT (p, stp) {
404 if (stp_is_designated_port(p)) {
405 p->designated_bridge = new_bridge_id;
406 }
407 }
408 stp->bridge_id = new_bridge_id;
409 stp_configuration_update(stp);
410 stp_port_state_selection(stp);
411 if (stp_is_root_bridge(stp) && !root) {
412 stp_become_root_bridge(stp);
413 }
414 }
415}
416
417void
418stp_set_bridge_id(struct stp *stp, stp_identifier bridge_id)
419{
420 const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
421 const uint64_t pri_bits = ~mac_bits;
bd54dbcd 422 ovs_mutex_lock(&mutex);
829a7d02 423 set_bridge_id(stp, (stp->bridge_id & pri_bits) | (bridge_id & mac_bits));
bd54dbcd 424 ovs_mutex_unlock(&mutex);
829a7d02
JP
425}
426
427void
428stp_set_bridge_priority(struct stp *stp, uint16_t new_priority)
429{
430 const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
bd54dbcd 431 ovs_mutex_lock(&mutex);
829a7d02
JP
432 set_bridge_id(stp, ((stp->bridge_id & mac_bits)
433 | ((uint64_t) new_priority << 48)));
bd54dbcd 434 ovs_mutex_unlock(&mutex);
829a7d02
JP
435}
436
437/* Sets the desired hello time for 'stp' to 'ms', in milliseconds. The actual
438 * hello time is clamped to the range of 1 to 10 seconds and subject to the
439 * relationship (bridge_max_age >= 2 * (bridge_hello_time + 1 s)). The bridge
440 * hello time is only used when 'stp' is the root bridge. */
441void
442stp_set_hello_time(struct stp *stp, int ms)
443{
bd54dbcd 444 ovs_mutex_lock(&mutex);
829a7d02
JP
445 stp->rq_hello_time = ms;
446 stp_update_bridge_timers(stp);
bd54dbcd 447 ovs_mutex_unlock(&mutex);
829a7d02
JP
448}
449
450/* Sets the desired max age for 'stp' to 'ms', in milliseconds. The actual max
451 * age is clamped to the range of 6 to 40 seconds and subject to the
452 * relationships (2 * (bridge_forward_delay - 1 s) >= bridge_max_age) and
453 * (bridge_max_age >= 2 * (bridge_hello_time + 1 s)). The bridge max age is
454 * only used when 'stp' is the root bridge. */
455void
456stp_set_max_age(struct stp *stp, int ms)
457{
bd54dbcd 458 ovs_mutex_lock(&mutex);
829a7d02
JP
459 stp->rq_max_age = ms;
460 stp_update_bridge_timers(stp);
bd54dbcd 461 ovs_mutex_unlock(&mutex);
829a7d02
JP
462}
463
464/* Sets the desired forward delay for 'stp' to 'ms', in milliseconds. The
465 * actual forward delay is clamped to the range of 4 to 30 seconds and subject
466 * to the relationship (2 * (bridge_forward_delay - 1 s) >= bridge_max_age).
467 * The bridge forward delay is only used when 'stp' is the root bridge. */
468void
469stp_set_forward_delay(struct stp *stp, int ms)
470{
bd54dbcd 471 ovs_mutex_lock(&mutex);
829a7d02
JP
472 stp->rq_forward_delay = ms;
473 stp_update_bridge_timers(stp);
bd54dbcd 474 ovs_mutex_unlock(&mutex);
829a7d02
JP
475}
476
477/* Returns the name given to 'stp' in the call to stp_create(). */
478const char *
479stp_get_name(const struct stp *stp)
480{
bd54dbcd
EJ
481 char *name;
482
483 ovs_mutex_lock(&mutex);
484 name = stp->name;
485 ovs_mutex_unlock(&mutex);
486 return name;
829a7d02
JP
487}
488
489/* Returns the bridge ID for 'stp'. */
490stp_identifier
491stp_get_bridge_id(const struct stp *stp)
492{
bd54dbcd
EJ
493 stp_identifier bridge_id;
494
495 ovs_mutex_lock(&mutex);
496 bridge_id = stp->bridge_id;
497 ovs_mutex_unlock(&mutex);
498 return bridge_id;
829a7d02
JP
499}
500
501/* Returns the bridge ID of the bridge currently believed to be the root. */
502stp_identifier
503stp_get_designated_root(const struct stp *stp)
504{
bd54dbcd
EJ
505 stp_identifier designated_root;
506
507 ovs_mutex_lock(&mutex);
508 designated_root = stp->designated_root;
509 ovs_mutex_unlock(&mutex);
510 return designated_root;
829a7d02
JP
511}
512
513/* Returns true if 'stp' believes itself to the be root of the spanning tree,
514 * false otherwise. */
515bool
516stp_is_root_bridge(const struct stp *stp)
517{
bd54dbcd
EJ
518 bool is_root;
519
520 ovs_mutex_lock(&mutex);
521 is_root = stp->bridge_id == stp->designated_root;
522 ovs_mutex_unlock(&mutex);
523 return is_root;
829a7d02
JP
524}
525
526/* Returns the cost of the path from 'stp' to the root of the spanning tree. */
527int
528stp_get_root_path_cost(const struct stp *stp)
529{
bd54dbcd
EJ
530 int cost;
531
532 ovs_mutex_lock(&mutex);
533 cost = stp->root_path_cost;
534 ovs_mutex_unlock(&mutex);
535 return cost;
829a7d02
JP
536}
537
538/* Returns the bridge hello time, in ms. The returned value is not necessarily
539 * the value passed to stp_set_hello_time(): it is clamped to the valid range
540 * and quantized to the STP timer resolution. */
541int
542stp_get_hello_time(const struct stp *stp)
543{
bd54dbcd
EJ
544 int time;
545
546 ovs_mutex_lock(&mutex);
547 time = timer_to_ms(stp->bridge_hello_time);
548 ovs_mutex_unlock(&mutex);
549 return time;
829a7d02
JP
550}
551
552/* Returns the bridge max age, in ms. The returned value is not necessarily
553 * the value passed to stp_set_max_age(): it is clamped to the valid range,
554 * quantized to the STP timer resolution, and adjusted to match the constraints
555 * due to the hello time. */
556int
557stp_get_max_age(const struct stp *stp)
558{
bd54dbcd
EJ
559 int time;
560
561 ovs_mutex_lock(&mutex);
562 time = timer_to_ms(stp->bridge_max_age);
563 ovs_mutex_unlock(&mutex);
564 return time;
829a7d02
JP
565}
566
567/* Returns the bridge forward delay, in ms. The returned value is not
568 * necessarily the value passed to stp_set_forward_delay(): it is clamped to
569 * the valid range, quantized to the STP timer resolution, and adjusted to
570 * match the constraints due to the forward delay. */
571int
572stp_get_forward_delay(const struct stp *stp)
573{
bd54dbcd
EJ
574 int time;
575
576 ovs_mutex_lock(&mutex);
577 time = timer_to_ms(stp->bridge_forward_delay);
578 ovs_mutex_unlock(&mutex);
579 return time;
829a7d02
JP
580}
581
6ae50723
EJ
582/* Returns true if something has happened to 'stp' which necessitates flushing
583 * the client's MAC learning table. Calling this function resets 'stp' so that
584 * future calls will return false until flushing is required again. */
585bool
586stp_check_and_reset_fdb_flush(struct stp *stp)
587{
bd54dbcd
EJ
588 bool needs_flush;
589
590 ovs_mutex_lock(&mutex);
591 needs_flush = stp->fdb_needs_flush;
6ae50723 592 stp->fdb_needs_flush = false;
bd54dbcd 593 ovs_mutex_unlock(&mutex);
6ae50723
EJ
594 return needs_flush;
595}
596
829a7d02
JP
597/* Returns the port in 'stp' with index 'port_no', which must be between 0 and
598 * STP_MAX_PORTS. */
599struct stp_port *
600stp_get_port(struct stp *stp, int port_no)
601{
bd54dbcd
EJ
602 struct stp_port *port;
603
604 ovs_mutex_lock(&mutex);
cb22974d 605 ovs_assert(port_no >= 0 && port_no < ARRAY_SIZE(stp->ports));
bd54dbcd
EJ
606 port = &stp->ports[port_no];
607 ovs_mutex_unlock(&mutex);
608 return port;
829a7d02
JP
609}
610
611/* Returns the port connecting 'stp' to the root bridge, or a null pointer if
612 * there is no such port. */
613struct stp_port *
614stp_get_root_port(struct stp *stp)
615{
bd54dbcd
EJ
616 struct stp_port *port;
617
618 ovs_mutex_lock(&mutex);
619 port = stp->root_port;
620 ovs_mutex_unlock(&mutex);
621 return port;
829a7d02
JP
622}
623
624/* Finds a port whose state has changed. If successful, stores the port whose
625 * state changed in '*portp' and returns true. If no port has changed, stores
626 * NULL in '*portp' and returns false. */
627bool
628stp_get_changed_port(struct stp *stp, struct stp_port **portp)
629{
bd54dbcd
EJ
630 struct stp_port *end, *p;
631 bool changed = false;
829a7d02 632
bd54dbcd
EJ
633 ovs_mutex_lock(&mutex);
634 end = &stp->ports[ARRAY_SIZE(stp->ports)];
829a7d02
JP
635 for (p = stp->first_changed_port; p < end; p++) {
636 if (p->state_changed) {
637 p->state_changed = false;
638 stp->first_changed_port = p + 1;
639 *portp = p;
bd54dbcd
EJ
640 changed = true;
641 goto out;
829a7d02
JP
642 }
643 }
644 stp->first_changed_port = end;
645 *portp = NULL;
bd54dbcd
EJ
646
647out:
648 ovs_mutex_unlock(&mutex);
649 return changed;
829a7d02
JP
650}
651
652/* Returns the name for the given 'state' (for use in debugging and log
653 * messages). */
654const char *
655stp_state_name(enum stp_state state)
656{
657 switch (state) {
658 case STP_DISABLED:
659 return "disabled";
660 case STP_LISTENING:
661 return "listening";
662 case STP_LEARNING:
663 return "learning";
664 case STP_FORWARDING:
665 return "forwarding";
666 case STP_BLOCKING:
667 return "blocking";
668 default:
669 NOT_REACHED();
670 }
671}
672
673/* Returns true if 'state' is one in which packets received on a port should
674 * be forwarded, false otherwise.
675 *
676 * Returns true if 'state' is STP_DISABLED, since presumably in that case the
677 * port should still work, just not have STP applied to it. */
678bool
679stp_forward_in_state(enum stp_state state)
680{
681 return (state & (STP_DISABLED | STP_FORWARDING)) != 0;
682}
683
684/* Returns true if 'state' is one in which MAC learning should be done on
685 * packets received on a port, false otherwise.
686 *
687 * Returns true if 'state' is STP_DISABLED, since presumably in that case the
688 * port should still work, just not have STP applied to it. */
689bool
690stp_learn_in_state(enum stp_state state)
691{
692 return (state & (STP_DISABLED | STP_LEARNING | STP_FORWARDING)) != 0;
693}
694
3310b570
JP
695/* Returns the name for the given 'role' (for use in debugging and log
696 * messages). */
697const char *
698stp_role_name(enum stp_role role)
699{
700 switch (role) {
701 case STP_ROLE_ROOT:
702 return "root";
703 case STP_ROLE_DESIGNATED:
704 return "designated";
705 case STP_ROLE_ALTERNATE:
706 return "alternate";
707 case STP_ROLE_DISABLED:
708 return "disabled";
709 default:
710 NOT_REACHED();
711 }
712}
713
829a7d02
JP
714/* Notifies the STP entity that bridge protocol data unit 'bpdu', which is
715 * 'bpdu_size' bytes in length, was received on port 'p'.
716 *
717 * This function may call the 'send_bpdu' function provided to stp_create(). */
718void
719stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
720{
721 struct stp *stp = p->stp;
722 const struct stp_bpdu_header *header;
723
bd54dbcd 724 ovs_mutex_lock(&mutex);
829a7d02 725 if (p->state == STP_DISABLED) {
bd54dbcd 726 goto out;
829a7d02
JP
727 }
728
729 if (bpdu_size < sizeof(struct stp_bpdu_header)) {
730 VLOG_WARN("%s: received runt %zu-byte BPDU", stp->name, bpdu_size);
80740385 731 p->error_count++;
bd54dbcd 732 goto out;
829a7d02
JP
733 }
734
735 header = bpdu;
736 if (header->protocol_id != htons(STP_PROTOCOL_ID)) {
737 VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16,
738 stp->name, ntohs(header->protocol_id));
80740385 739 p->error_count++;
bd54dbcd 740 goto out;
829a7d02
JP
741 }
742 if (header->protocol_version != STP_PROTOCOL_VERSION) {
743 VLOG_DBG("%s: received BPDU with unexpected protocol version %"PRIu8,
744 stp->name, header->protocol_version);
745 }
746
747 switch (header->bpdu_type) {
748 case STP_TYPE_CONFIG:
749 if (bpdu_size < sizeof(struct stp_config_bpdu)) {
750 VLOG_WARN("%s: received config BPDU with invalid size %zu",
751 stp->name, bpdu_size);
80740385 752 p->error_count++;
bd54dbcd 753 goto out;
829a7d02
JP
754 }
755 stp_received_config_bpdu(stp, p, bpdu);
756 break;
757
758 case STP_TYPE_TCN:
759 if (bpdu_size != sizeof(struct stp_tcn_bpdu)) {
760 VLOG_WARN("%s: received TCN BPDU with invalid size %zu",
761 stp->name, bpdu_size);
80740385 762 p->error_count++;
bd54dbcd 763 goto out;
829a7d02
JP
764 }
765 stp_received_tcn_bpdu(stp, p);
766 break;
767
768 default:
769 VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8,
770 stp->name, header->bpdu_type);
80740385 771 p->error_count++;
bd54dbcd 772 goto out;
829a7d02 773 }
80740385 774 p->rx_count++;
bd54dbcd
EJ
775
776out:
777 ovs_mutex_unlock(&mutex);
829a7d02
JP
778}
779
780/* Returns the STP entity in which 'p' is nested. */
781struct stp *
782stp_port_get_stp(struct stp_port *p)
783{
bd54dbcd
EJ
784 struct stp *stp;
785
786 ovs_mutex_lock(&mutex);
787 stp = p->stp;
788 ovs_mutex_unlock(&mutex);
789 return stp;
829a7d02
JP
790}
791
3310b570
JP
792/* Sets the 'aux' member of 'p'.
793 *
794 * The 'aux' member will be reset to NULL when stp_port_disable() is
795 * called or stp_port_enable() is called when the port is in a Disabled
796 * state. */
797void
798stp_port_set_aux(struct stp_port *p, void *aux)
799{
bd54dbcd 800 ovs_mutex_lock(&mutex);
3310b570 801 p->aux = aux;
bd54dbcd 802 ovs_mutex_unlock(&mutex);
3310b570
JP
803}
804
805/* Returns the 'aux' member of 'p'. */
806void *
807stp_port_get_aux(struct stp_port *p)
808{
bd54dbcd
EJ
809 void *aux;
810
811 ovs_mutex_lock(&mutex);
812 aux = p->aux;
813 ovs_mutex_unlock(&mutex);
814 return aux;
3310b570
JP
815}
816
829a7d02
JP
817/* Returns the index of port 'p' within its bridge. */
818int
819stp_port_no(const struct stp_port *p)
820{
bd54dbcd
EJ
821 struct stp *stp;
822 int index;
823
824 ovs_mutex_lock(&mutex);
825 stp = p->stp;
cb22974d 826 ovs_assert(p >= stp->ports && p < &stp->ports[ARRAY_SIZE(stp->ports)]);
bd54dbcd
EJ
827 index = p - p->stp->ports;
828 ovs_mutex_unlock(&mutex);
829 return index;
829a7d02
JP
830}
831
3310b570
JP
832/* Returns the port ID for 'p'. */
833int
834stp_port_get_id(const struct stp_port *p)
835{
bd54dbcd
EJ
836 int port_id;
837
838 ovs_mutex_lock(&mutex);
839 port_id = p->port_id;
840 ovs_mutex_unlock(&mutex);
841 return port_id;
3310b570
JP
842}
843
829a7d02
JP
844/* Returns the state of port 'p'. */
845enum stp_state
846stp_port_get_state(const struct stp_port *p)
847{
bd54dbcd
EJ
848 enum stp_state state;
849
850 ovs_mutex_lock(&mutex);
851 state = p->state;
852 ovs_mutex_unlock(&mutex);
853 return state;
829a7d02
JP
854}
855
3310b570
JP
856/* Returns the role of port 'p'. */
857enum stp_role
858stp_port_get_role(const struct stp_port *p)
859{
bd54dbcd
EJ
860 struct stp_port *root_port;
861 enum stp_role role;
3310b570 862
bd54dbcd
EJ
863 ovs_mutex_lock(&mutex);
864 root_port = p->stp->root_port;
3310b570 865 if (root_port && root_port->port_id == p->port_id) {
bd54dbcd 866 role = STP_ROLE_ROOT;
3310b570 867 } else if (stp_is_designated_port(p)) {
bd54dbcd 868 role = STP_ROLE_DESIGNATED;
3310b570 869 } else if (p->state == STP_DISABLED) {
bd54dbcd 870 role = STP_ROLE_DISABLED;
3310b570 871 } else {
bd54dbcd 872 role = STP_ROLE_ALTERNATE;
3310b570 873 }
bd54dbcd
EJ
874 ovs_mutex_unlock(&mutex);
875 return role;
3310b570
JP
876}
877
80740385 878/* Retrieves BPDU transmit and receive counts for 'p'. */
bd54dbcd
EJ
879void
880stp_port_get_counts(const struct stp_port *p,
881 int *tx_count, int *rx_count, int *error_count)
80740385 882{
bd54dbcd 883 ovs_mutex_lock(&mutex);
80740385
JP
884 *tx_count = p->tx_count;
885 *rx_count = p->rx_count;
886 *error_count = p->error_count;
bd54dbcd 887 ovs_mutex_unlock(&mutex);
80740385
JP
888}
889
829a7d02
JP
890/* Disables STP on port 'p'. */
891void
892stp_port_disable(struct stp_port *p)
893{
bd54dbcd
EJ
894 struct stp *stp;
895
896 ovs_mutex_lock(&mutex);
897 stp = p->stp;
829a7d02
JP
898 if (p->state != STP_DISABLED) {
899 bool root = stp_is_root_bridge(stp);
900 stp_become_designated_port(p);
901 stp_set_port_state(p, STP_DISABLED);
902 p->topology_change_ack = false;
903 p->config_pending = false;
904 stp_stop_timer(&p->message_age_timer);
905 stp_stop_timer(&p->forward_delay_timer);
906 stp_configuration_update(stp);
907 stp_port_state_selection(stp);
908 if (stp_is_root_bridge(stp) && !root) {
909 stp_become_root_bridge(stp);
910 }
3310b570 911 p->aux = NULL;
829a7d02 912 }
bd54dbcd 913 ovs_mutex_unlock(&mutex);
829a7d02
JP
914}
915
916/* Enables STP on port 'p'. The port will initially be in "blocking" state. */
917void
918stp_port_enable(struct stp_port *p)
919{
bd54dbcd 920 ovs_mutex_lock(&mutex);
829a7d02
JP
921 if (p->state == STP_DISABLED) {
922 stp_initialize_port(p, STP_BLOCKING);
923 stp_port_state_selection(p->stp);
924 }
bd54dbcd 925 ovs_mutex_unlock(&mutex);
829a7d02
JP
926}
927
928/* Sets the priority of port 'p' to 'new_priority'. Lower numerical values
929 * are interpreted as higher priorities. */
930void
931stp_port_set_priority(struct stp_port *p, uint8_t new_priority)
932{
bd54dbcd
EJ
933 uint16_t new_port_id;
934
935 ovs_mutex_lock(&mutex);
936 new_port_id = (p->port_id & 0xff) | (new_priority << 8);
829a7d02
JP
937 if (p->port_id != new_port_id) {
938 struct stp *stp = p->stp;
939 if (stp_is_designated_port(p)) {
940 p->designated_port = new_port_id;
941 }
942 p->port_id = new_port_id;
943 if (stp->bridge_id == p->designated_bridge
944 && p->port_id < p->designated_port) {
945 stp_become_designated_port(p);
946 stp_port_state_selection(stp);
947 }
948 }
bd54dbcd 949 ovs_mutex_unlock(&mutex);
829a7d02
JP
950}
951
3310b570
JP
952/* Convert 'speed' (measured in Mb/s) into the path cost. */
953uint16_t
954stp_convert_speed_to_cost(unsigned int speed)
955{
bd54dbcd
EJ
956 uint16_t ret;
957
958 ovs_mutex_lock(&mutex);
959 ret = speed >= 10000 ? 2 /* 10 Gb/s. */
960 : speed >= 1000 ? 4 /* 1 Gb/s. */
961 : speed >= 100 ? 19 /* 100 Mb/s. */
962 : speed >= 16 ? 62 /* 16 Mb/s. */
963 : speed >= 10 ? 100 /* 10 Mb/s. */
964 : speed >= 4 ? 250 /* 4 Mb/s. */
965 : 19; /* 100 Mb/s (guess). */
966 ovs_mutex_unlock(&mutex);
967 return ret;
3310b570
JP
968}
969
829a7d02
JP
970/* Sets the path cost of port 'p' to 'path_cost'. Lower values are generally
971 * used to indicate faster links. Use stp_port_set_speed() to automatically
972 * generate a default path cost from a link speed. */
973void
974stp_port_set_path_cost(struct stp_port *p, uint16_t path_cost)
975{
bd54dbcd 976 ovs_mutex_lock(&mutex);
829a7d02
JP
977 if (p->path_cost != path_cost) {
978 struct stp *stp = p->stp;
979 p->path_cost = path_cost;
980 stp_configuration_update(stp);
981 stp_port_state_selection(stp);
982 }
bd54dbcd 983 ovs_mutex_unlock(&mutex);
829a7d02
JP
984}
985
986/* Sets the path cost of port 'p' based on 'speed' (measured in Mb/s). */
987void
988stp_port_set_speed(struct stp_port *p, unsigned int speed)
989{
3310b570 990 stp_port_set_path_cost(p, stp_convert_speed_to_cost(speed));
829a7d02
JP
991}
992
993/* Enables topology change detection on port 'p'. */
994void
995stp_port_enable_change_detection(struct stp_port *p)
996{
997 p->change_detection_enabled = true;
998}
999
1000/* Disables topology change detection on port 'p'. */
1001void
1002stp_port_disable_change_detection(struct stp_port *p)
1003{
1004 p->change_detection_enabled = false;
1005}
1006\f
1007static void
bd3950dd 1008stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1009{
1010 struct stp *stp = p->stp;
1011 bool root = stp_is_root_bridge(stp);
1012 if (!root && !stp->root_port) {
1013 return;
1014 }
1015 if (p->hold_timer.active) {
1016 p->config_pending = true;
1017 } else {
1018 struct stp_config_bpdu config;
1019 memset(&config, 0, sizeof config);
1020 config.header.protocol_id = htons(STP_PROTOCOL_ID);
1021 config.header.protocol_version = STP_PROTOCOL_VERSION;
1022 config.header.bpdu_type = STP_TYPE_CONFIG;
1023 config.flags = 0;
1024 if (p->topology_change_ack) {
3310b570 1025 config.flags |= STP_CONFIG_TOPOLOGY_CHANGE_ACK;
829a7d02
JP
1026 }
1027 if (stp->topology_change) {
3310b570 1028 config.flags |= STP_CONFIG_TOPOLOGY_CHANGE;
829a7d02
JP
1029 }
1030 config.root_id = htonll(stp->designated_root);
1031 config.root_path_cost = htonl(stp->root_path_cost);
1032 config.bridge_id = htonll(stp->bridge_id);
1033 config.port_id = htons(p->port_id);
1034 if (root) {
1035 config.message_age = htons(0);
1036 } else {
1037 config.message_age = htons(stp->root_port->message_age_timer.value
1038 + MESSAGE_AGE_INCREMENT);
1039 }
1040 config.max_age = htons(stp->max_age);
1041 config.hello_time = htons(stp->hello_time);
1042 config.forward_delay = htons(stp->forward_delay);
1043 if (ntohs(config.message_age) < stp->max_age) {
1044 p->topology_change_ack = false;
1045 p->config_pending = false;
1046 stp_send_bpdu(p, &config, sizeof config);
1047 stp_start_timer(&p->hold_timer, 0);
1048 }
1049 }
1050}
1051
1052static bool
1053stp_supersedes_port_info(const struct stp_port *p,
1054 const struct stp_config_bpdu *config)
bd3950dd 1055 OVS_REQUIRES(mutex)
829a7d02
JP
1056{
1057 if (ntohll(config->root_id) != p->designated_root) {
1058 return ntohll(config->root_id) < p->designated_root;
1059 } else if (ntohl(config->root_path_cost) != p->designated_cost) {
1060 return ntohl(config->root_path_cost) < p->designated_cost;
1061 } else if (ntohll(config->bridge_id) != p->designated_bridge) {
1062 return ntohll(config->bridge_id) < p->designated_bridge;
1063 } else {
1064 return (ntohll(config->bridge_id) != p->stp->bridge_id
1065 || ntohs(config->port_id) <= p->designated_port);
1066 }
1067}
1068
1069static void
1070stp_record_config_information(struct stp_port *p,
1071 const struct stp_config_bpdu *config)
bd3950dd 1072 OVS_REQUIRES(mutex)
829a7d02
JP
1073{
1074 p->designated_root = ntohll(config->root_id);
1075 p->designated_cost = ntohl(config->root_path_cost);
1076 p->designated_bridge = ntohll(config->bridge_id);
1077 p->designated_port = ntohs(config->port_id);
1078 stp_start_timer(&p->message_age_timer, ntohs(config->message_age));
1079}
1080
1081static void
1082stp_record_config_timeout_values(struct stp *stp,
1083 const struct stp_config_bpdu *config)
bd3950dd 1084 OVS_REQUIRES(mutex)
829a7d02
JP
1085{
1086 stp->max_age = ntohs(config->max_age);
1087 stp->hello_time = ntohs(config->hello_time);
1088 stp->forward_delay = ntohs(config->forward_delay);
3310b570 1089 stp->topology_change = config->flags & STP_CONFIG_TOPOLOGY_CHANGE;
829a7d02
JP
1090}
1091
1092static bool
bd3950dd 1093stp_is_designated_port(const struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1094{
1095 return (p->designated_bridge == p->stp->bridge_id
1096 && p->designated_port == p->port_id);
1097}
1098
1099static void
bd3950dd 1100stp_config_bpdu_generation(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1101{
1102 struct stp_port *p;
1103
1104 FOR_EACH_ENABLED_PORT (p, stp) {
1105 if (stp_is_designated_port(p)) {
1106 stp_transmit_config(p);
1107 }
1108 }
1109}
1110
1111static void
bd3950dd 1112stp_transmit_tcn(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1113{
1114 struct stp_port *p = stp->root_port;
1115 struct stp_tcn_bpdu tcn_bpdu;
1116 if (!p) {
1117 return;
1118 }
1119 tcn_bpdu.header.protocol_id = htons(STP_PROTOCOL_ID);
1120 tcn_bpdu.header.protocol_version = STP_PROTOCOL_VERSION;
1121 tcn_bpdu.header.bpdu_type = STP_TYPE_TCN;
1122 stp_send_bpdu(p, &tcn_bpdu, sizeof tcn_bpdu);
1123}
1124
1125static void
bd3950dd 1126stp_configuration_update(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1127{
1128 stp_root_selection(stp);
1129 stp_designated_port_selection(stp);
1130}
1131
1132static bool
1133stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
bd3950dd 1134 OVS_REQUIRES(mutex)
829a7d02
JP
1135{
1136 int p_cost = p->designated_cost + p->path_cost;
1137 int root_cost = root->designated_cost + root->path_cost;
1138
1139 if (p->designated_root != root->designated_root) {
1140 return p->designated_root < root->designated_root;
1141 } else if (p_cost != root_cost) {
1142 return p_cost < root_cost;
1143 } else if (p->designated_bridge != root->designated_bridge) {
1144 return p->designated_bridge < root->designated_bridge;
1145 } else if (p->designated_port != root->designated_port) {
1146 return p->designated_port < root->designated_port;
1147 } else {
1148 return p->port_id < root->port_id;
1149 }
1150}
1151
1152static void
bd3950dd 1153stp_root_selection(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1154{
1155 struct stp_port *p, *root;
1156
1157 root = NULL;
1158 FOR_EACH_ENABLED_PORT (p, stp) {
1159 if (stp_is_designated_port(p)
1160 || p->designated_root >= stp->bridge_id) {
1161 continue;
1162 }
1163 if (root && !stp_supersedes_root(root, p)) {
1164 continue;
1165 }
1166 root = p;
1167 }
1168 stp->root_port = root;
1169 if (!root) {
1170 stp->designated_root = stp->bridge_id;
1171 stp->root_path_cost = 0;
1172 } else {
1173 stp->designated_root = root->designated_root;
1174 stp->root_path_cost = root->designated_cost + root->path_cost;
1175 }
1176}
1177
1178static void
bd3950dd 1179stp_designated_port_selection(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1180{
1181 struct stp_port *p;
1182
1183 FOR_EACH_ENABLED_PORT (p, stp) {
1184 if (stp_is_designated_port(p)
1185 || p->designated_root != stp->designated_root
1186 || stp->root_path_cost < p->designated_cost
1187 || (stp->root_path_cost == p->designated_cost
1188 && (stp->bridge_id < p->designated_bridge
1189 || (stp->bridge_id == p->designated_bridge
1190 && p->port_id <= p->designated_port))))
1191 {
1192 stp_become_designated_port(p);
1193 }
1194 }
1195}
1196
1197static void
bd3950dd 1198stp_become_designated_port(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1199{
1200 struct stp *stp = p->stp;
1201 p->designated_root = stp->designated_root;
1202 p->designated_cost = stp->root_path_cost;
1203 p->designated_bridge = stp->bridge_id;
1204 p->designated_port = p->port_id;
1205}
1206
1207static void
bd3950dd 1208stp_port_state_selection(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1209{
1210 struct stp_port *p;
1211
1212 FOR_EACH_ENABLED_PORT (p, stp) {
1213 if (p == stp->root_port) {
1214 p->config_pending = false;
1215 p->topology_change_ack = false;
1216 stp_make_forwarding(p);
1217 } else if (stp_is_designated_port(p)) {
1218 stp_stop_timer(&p->message_age_timer);
1219 stp_make_forwarding(p);
1220 } else {
1221 p->config_pending = false;
1222 p->topology_change_ack = false;
1223 stp_make_blocking(p);
1224 }
1225 }
1226}
1227
1228static void
bd3950dd 1229stp_make_forwarding(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1230{
1231 if (p->state == STP_BLOCKING) {
1232 stp_set_port_state(p, STP_LISTENING);
1233 stp_start_timer(&p->forward_delay_timer, 0);
1234 }
1235}
1236
1237static void
bd3950dd 1238stp_make_blocking(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1239{
1240 if (!(p->state & (STP_DISABLED | STP_BLOCKING))) {
1241 if (p->state & (STP_FORWARDING | STP_LEARNING)) {
1242 if (p->change_detection_enabled) {
1243 stp_topology_change_detection(p->stp);
1244 }
1245 }
1246 stp_set_port_state(p, STP_BLOCKING);
1247 stp_stop_timer(&p->forward_delay_timer);
1248 }
1249}
1250
1251static void
1252stp_set_port_state(struct stp_port *p, enum stp_state state)
bd3950dd 1253 OVS_REQUIRES(mutex)
829a7d02
JP
1254{
1255 if (state != p->state && !p->state_changed) {
1256 p->state_changed = true;
1257 if (p < p->stp->first_changed_port) {
1258 p->stp->first_changed_port = p;
1259 }
1260 }
1261 p->state = state;
1262}
1263
1264static void
bd3950dd 1265stp_topology_change_detection(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02 1266{
634408e0
EJ
1267 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
1268
829a7d02
JP
1269 if (stp_is_root_bridge(stp)) {
1270 stp->topology_change = true;
1271 stp_start_timer(&stp->topology_change_timer, 0);
1272 } else if (!stp->topology_change_detected) {
1273 stp_transmit_tcn(stp);
1274 stp_start_timer(&stp->tcn_timer, 0);
1275 }
6ae50723 1276 stp->fdb_needs_flush = true;
829a7d02 1277 stp->topology_change_detected = true;
634408e0 1278 VLOG_INFO_RL(&rl, "%s: detected topology change.", stp->name);
829a7d02
JP
1279}
1280
1281static void
bd3950dd 1282stp_topology_change_acknowledged(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1283{
1284 stp->topology_change_detected = false;
1285 stp_stop_timer(&stp->tcn_timer);
1286}
1287
1288static void
bd3950dd 1289stp_acknowledge_topology_change(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1290{
1291 p->topology_change_ack = true;
1292 stp_transmit_config(p);
1293}
1294
1295static void
1296stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
1297 const struct stp_config_bpdu *config)
bd3950dd 1298 OVS_REQUIRES(mutex)
829a7d02
JP
1299{
1300 if (ntohs(config->message_age) >= ntohs(config->max_age)) {
1301 VLOG_WARN("%s: received config BPDU with message age (%u) greater "
1302 "than max age (%u)",
1303 stp->name,
1304 ntohs(config->message_age), ntohs(config->max_age));
1305 return;
1306 }
1307 if (p->state != STP_DISABLED) {
1308 bool root = stp_is_root_bridge(stp);
1309 if (stp_supersedes_port_info(p, config)) {
1310 stp_record_config_information(p, config);
1311 stp_configuration_update(stp);
1312 stp_port_state_selection(stp);
1313 if (!stp_is_root_bridge(stp) && root) {
1314 stp_stop_timer(&stp->hello_timer);
1315 if (stp->topology_change_detected) {
1316 stp_stop_timer(&stp->topology_change_timer);
1317 stp_transmit_tcn(stp);
1318 stp_start_timer(&stp->tcn_timer, 0);
1319 }
1320 }
1321 if (p == stp->root_port) {
1322 stp_record_config_timeout_values(stp, config);
1323 stp_config_bpdu_generation(stp);
3310b570 1324 if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE_ACK) {
829a7d02
JP
1325 stp_topology_change_acknowledged(stp);
1326 }
6ae50723
EJ
1327 if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE) {
1328 stp->fdb_needs_flush = true;
1329 }
829a7d02
JP
1330 }
1331 } else if (stp_is_designated_port(p)) {
1332 stp_transmit_config(p);
1333 }
1334 }
1335}
1336
1337static void
1338stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
bd3950dd 1339 OVS_REQUIRES(mutex)
829a7d02
JP
1340{
1341 if (p->state != STP_DISABLED) {
1342 if (stp_is_designated_port(p)) {
1343 stp_topology_change_detection(stp);
1344 stp_acknowledge_topology_change(p);
1345 }
1346 }
1347}
1348
1349static void
bd3950dd 1350stp_hello_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1351{
1352 stp_config_bpdu_generation(stp);
1353 stp_start_timer(&stp->hello_timer, 0);
1354}
1355
1356static void
bd3950dd 1357stp_message_age_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1358{
1359 struct stp *stp = p->stp;
1360 bool root = stp_is_root_bridge(stp);
1361 stp_become_designated_port(p);
1362 stp_configuration_update(stp);
1363 stp_port_state_selection(stp);
1364 if (stp_is_root_bridge(stp) && !root) {
1365 stp->max_age = stp->bridge_max_age;
1366 stp->hello_time = stp->bridge_hello_time;
1367 stp->forward_delay = stp->bridge_forward_delay;
1368 stp_topology_change_detection(stp);
1369 stp_stop_timer(&stp->tcn_timer);
1370 stp_config_bpdu_generation(stp);
1371 stp_start_timer(&stp->hello_timer, 0);
1372 }
1373}
1374
1375static bool
bd3950dd 1376stp_is_designated_for_some_port(const struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1377{
1378 const struct stp_port *p;
1379
1380 FOR_EACH_ENABLED_PORT (p, stp) {
1381 if (p->designated_bridge == stp->bridge_id) {
1382 return true;
1383 }
1384 }
1385 return false;
1386}
1387
1388static void
bd3950dd 1389stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1390{
1391 if (p->state == STP_LISTENING) {
1392 stp_set_port_state(p, STP_LEARNING);
1393 stp_start_timer(&p->forward_delay_timer, 0);
1394 } else if (p->state == STP_LEARNING) {
1395 stp_set_port_state(p, STP_FORWARDING);
1396 if (stp_is_designated_for_some_port(p->stp)) {
1397 if (p->change_detection_enabled) {
1398 stp_topology_change_detection(p->stp);
1399 }
1400 }
1401 }
1402}
1403
1404static void
bd3950dd 1405stp_tcn_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1406{
1407 stp_transmit_tcn(stp);
1408 stp_start_timer(&stp->tcn_timer, 0);
1409}
1410
1411static void
bd3950dd 1412stp_topology_change_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1413{
1414 stp->topology_change_detected = false;
1415 stp->topology_change = false;
1416}
1417
1418static void
bd3950dd 1419stp_hold_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
829a7d02
JP
1420{
1421 if (p->config_pending) {
1422 stp_transmit_config(p);
1423 }
1424}
1425
1426static void
1427stp_initialize_port(struct stp_port *p, enum stp_state state)
bd3950dd 1428 OVS_REQUIRES(mutex)
829a7d02 1429{
cb22974d 1430 ovs_assert(state & (STP_DISABLED | STP_BLOCKING));
829a7d02
JP
1431 stp_become_designated_port(p);
1432 stp_set_port_state(p, state);
1433 p->topology_change_ack = false;
1434 p->config_pending = false;
1435 p->change_detection_enabled = true;
3310b570 1436 p->aux = NULL;
829a7d02
JP
1437 stp_stop_timer(&p->message_age_timer);
1438 stp_stop_timer(&p->forward_delay_timer);
1439 stp_stop_timer(&p->hold_timer);
80740385 1440 p->tx_count = p->rx_count = p->error_count = 0;
829a7d02
JP
1441}
1442
1443static void
bd3950dd 1444stp_become_root_bridge(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1445{
1446 stp->max_age = stp->bridge_max_age;
1447 stp->hello_time = stp->bridge_hello_time;
1448 stp->forward_delay = stp->bridge_forward_delay;
1449 stp_topology_change_detection(stp);
1450 stp_stop_timer(&stp->tcn_timer);
1451 stp_config_bpdu_generation(stp);
1452 stp_start_timer(&stp->hello_timer, 0);
1453}
1454
1455static void
bd3950dd 1456stp_start_timer(struct stp_timer *timer, int value) OVS_REQUIRES(mutex)
829a7d02
JP
1457{
1458 timer->value = value;
1459 timer->active = true;
1460}
1461
1462static void
bd3950dd 1463stp_stop_timer(struct stp_timer *timer) OVS_REQUIRES(mutex)
829a7d02
JP
1464{
1465 timer->active = false;
1466}
1467
1468static bool
1469stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
bd3950dd 1470 OVS_REQUIRES(mutex)
829a7d02
JP
1471{
1472 if (timer->active) {
1473 timer->value += elapsed;
1474 if (timer->value >= timeout) {
1475 timer->active = false;
1476 return true;
1477 }
1478 }
1479 return false;
1480}
1481
1482/* Returns the number of whole STP timer ticks in 'ms' milliseconds. There
1483 * are 256 STP timer ticks per second. */
1484static int
1485ms_to_timer(int ms)
1486{
1487 return ms * 0x100 / 1000;
1488}
1489
829a7d02
JP
1490/* Returns the number of whole milliseconds in 'timer' STP timer ticks. There
1491 * are 256 STP timer ticks per second. */
1492static int
1493timer_to_ms(int timer)
1494{
1495 return timer * 1000 / 0x100;
1496}
1497
1498static int
1499clamp(int x, int min, int max)
1500{
1501 return x < min ? min : x > max ? max : x;
1502}
1503
1504static void
bd3950dd 1505stp_update_bridge_timers(struct stp *stp) OVS_REQUIRES(mutex)
829a7d02
JP
1506{
1507 int ht, ma, fd;
1508
1509 ht = clamp(stp->rq_hello_time, 1000, 10000);
1510 ma = clamp(stp->rq_max_age, MAX(2 * (ht + 1000), 6000), 40000);
1511 fd = clamp(stp->rq_forward_delay, ma / 2 + 1000, 30000);
1512
1513 stp->bridge_hello_time = ms_to_timer(ht);
1514 stp->bridge_max_age = ms_to_timer(ma);
1515 stp->bridge_forward_delay = ms_to_timer(fd);
1516
1517 if (stp_is_root_bridge(stp)) {
1518 stp->max_age = stp->bridge_max_age;
1519 stp->hello_time = stp->bridge_hello_time;
1520 stp->forward_delay = stp->bridge_forward_delay;
1521 }
1522}
1523
1524static void
1525stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
bd3950dd 1526 OVS_REQUIRES(mutex)
829a7d02
JP
1527{
1528 struct eth_header *eth;
1529 struct llc_header *llc;
1530 struct ofpbuf *pkt;
1531
1532 /* Skeleton. */
1533 pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
1534 pkt->l2 = eth = ofpbuf_put_zeros(pkt, sizeof *eth);
1535 llc = ofpbuf_put_zeros(pkt, sizeof *llc);
1536 pkt->l3 = ofpbuf_put(pkt, bpdu, bpdu_size);
1537
1538 /* 802.2 header. */
1539 memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
1540 /* p->stp->send_bpdu() must fill in source address. */
1541 eth->eth_type = htons(pkt->size - ETH_HEADER_LEN);
1542
1543 /* LLC header. */
1544 llc->llc_dsap = STP_LLC_DSAP;
1545 llc->llc_ssap = STP_LLC_SSAP;
1546 llc->llc_cntl = STP_LLC_CNTL;
1547
1548 p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux);
80740385 1549 p->tx_count++;
829a7d02 1550}
fe4a02e4
EJ
1551\f
1552/* Unixctl. */
1553
1554static struct stp *
bd3950dd 1555stp_find(const char *name) OVS_REQUIRES(mutex)
fe4a02e4
EJ
1556{
1557 struct stp *stp;
1558
bd54dbcd 1559 LIST_FOR_EACH (stp, node, all_stps) {
fe4a02e4
EJ
1560 if (!strcmp(stp->name, name)) {
1561 return stp;
1562 }
1563 }
1564 return NULL;
1565}
1566
1567static void
1568stp_unixctl_tcn(struct unixctl_conn *conn, int argc,
1569 const char *argv[], void *aux OVS_UNUSED)
1570{
bd54dbcd 1571 ovs_mutex_lock(&mutex);
fe4a02e4
EJ
1572 if (argc > 1) {
1573 struct stp *stp = stp_find(argv[1]);
1574
1575 if (!stp) {
bde9f75d 1576 unixctl_command_reply_error(conn, "no such stp object");
bd54dbcd 1577 goto out;
fe4a02e4
EJ
1578 }
1579 stp_topology_change_detection(stp);
1580 } else {
1581 struct stp *stp;
1582
bd54dbcd 1583 LIST_FOR_EACH (stp, node, all_stps) {
fe4a02e4
EJ
1584 stp_topology_change_detection(stp);
1585 }
1586 }
1587
bde9f75d 1588 unixctl_command_reply(conn, "OK");
bd54dbcd
EJ
1589
1590out:
1591 ovs_mutex_unlock(&mutex);
fe4a02e4 1592}