1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/kernel.h>
17#include <linux/if_bridge.h>
18#include <linux/smp_lock.h>
19#include <asm/uaccess.h>
20#include "br_private.h"
21#include "br_private_stp.h"
22
23
24
25
26#define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256))
27
28
29int br_is_root_bridge(struct net_bridge *br)
30{
31 return !memcmp(&br->bridge_id, &br->designated_root, 8);
32}
33
34
35int br_is_designated_port(struct net_bridge_port *p)
36{
37 return !memcmp(&p->designated_bridge, &p->br->bridge_id, 8) &&
38 (p->designated_port == p->port_id);
39}
40
41
42struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no)
43{
44 struct net_bridge_port *p;
45
46 p = br->port_list;
47 while (p != NULL) {
48 if (p->port_no == port_no)
49 return p;
50
51 p = p->next;
52 }
53
54 return NULL;
55}
56
57
58static int br_should_become_root_port(struct net_bridge_port *p, int root_port)
59{
60 struct net_bridge *br;
61 struct net_bridge_port *rp;
62 int t;
63
64 br = p->br;
65 if (p->state == BR_STATE_DISABLED ||
66 br_is_designated_port(p))
67 return 0;
68
69 if (memcmp(&br->bridge_id, &p->designated_root, 8) <= 0)
70 return 0;
71
72 if (!root_port)
73 return 1;
74
75 rp = br_get_port(br, root_port);
76
77 t = memcmp(&p->designated_root, &rp->designated_root, 8);
78 if (t < 0)
79 return 1;
80 else if (t > 0)
81 return 0;
82
83 if (p->designated_cost + p->path_cost <
84 rp->designated_cost + rp->path_cost)
85 return 1;
86 else if (p->designated_cost + p->path_cost >
87 rp->designated_cost + rp->path_cost)
88 return 0;
89
90 t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8);
91 if (t < 0)
92 return 1;
93 else if (t > 0)
94 return 0;
95
96 if (p->designated_port < rp->designated_port)
97 return 1;
98 else if (p->designated_port > rp->designated_port)
99 return 0;
100
101 if (p->port_id < rp->port_id)
102 return 1;
103
104 return 0;
105}
106
107
108static void br_root_selection(struct net_bridge *br)
109{
110 struct net_bridge_port *p;
111 int root_port;
112
113 root_port = 0;
114
115 p = br->port_list;
116 while (p != NULL) {
117 if (br_should_become_root_port(p, root_port))
118 root_port = p->port_no;
119
120 p = p->next;
121 }
122
123 br->root_port = root_port;
124
125 if (!root_port) {
126 br->designated_root = br->bridge_id;
127 br->root_path_cost = 0;
128 } else {
129 p = br_get_port(br, root_port);
130 br->designated_root = p->designated_root;
131 br->root_path_cost = p->designated_cost + p->path_cost;
132 }
133}
134
135
136void br_become_root_bridge(struct net_bridge *br)
137{
138 br->max_age = br->bridge_max_age;
139 br->hello_time = br->bridge_hello_time;
140 br->forward_delay = br->bridge_forward_delay;
141 br_topology_change_detection(br);
142 br_timer_clear(&br->tcn_timer);
143 br_config_bpdu_generation(br);
144 br_timer_set(&br->hello_timer, jiffies);
145}
146
147
148void br_transmit_config(struct net_bridge_port *p)
149{
150 struct br_config_bpdu bpdu;
151 struct net_bridge *br;
152
153 if (br_timer_is_running(&p->hold_timer)) {
154 p->config_pending = 1;
155 return;
156 }
157
158 br = p->br;
159
160 bpdu.topology_change = br->topology_change;
161 bpdu.topology_change_ack = p->topology_change_ack;
162 bpdu.root = br->designated_root;
163 bpdu.root_path_cost = br->root_path_cost;
164 bpdu.bridge_id = br->bridge_id;
165 bpdu.port_id = p->port_id;
166 if (br_is_root_bridge(br))
167 bpdu.message_age = 0;
168 else {
169 struct net_bridge_port *root;
170
171 root = br_get_port(br, br->root_port);
172 bpdu.message_age = br_timer_get_residue(&root->message_age_timer)
173 + MESSAGE_AGE_INCR;
174 }
175 bpdu.max_age = br->max_age;
176 bpdu.hello_time = br->hello_time;
177 bpdu.forward_delay = br->forward_delay;
178
179 if (bpdu.message_age < br->max_age) {
180 br_send_config_bpdu(p, &bpdu);
181
182 p->topology_change_ack = 0;
183 p->config_pending = 0;
184 br_timer_set(&p->hold_timer, jiffies);
185 }
186}
187
188
189static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
190{
191 p->designated_root = bpdu->root;
192 p->designated_cost = bpdu->root_path_cost;
193 p->designated_bridge = bpdu->bridge_id;
194 p->designated_port = bpdu->port_id;
195
196 br_timer_set(&p->message_age_timer, jiffies - bpdu->message_age);
197}
198
199
200static void br_record_config_timeout_values(struct net_bridge *br, struct br_config_bpdu *bpdu)
201{
202 br->max_age = bpdu->max_age;
203 br->hello_time = bpdu->hello_time;
204 br->forward_delay = bpdu->forward_delay;
205 br->topology_change = bpdu->topology_change;
206}
207
208
209void br_transmit_tcn(struct net_bridge *br)
210{
211 br_send_tcn_bpdu(br_get_port(br, br->root_port));
212}
213
214
215static int br_should_become_designated_port(struct net_bridge_port *p)
216{
217 struct net_bridge *br;
218 int t;
219
220 br = p->br;
221 if (br_is_designated_port(p))
222 return 1;
223
224 if (memcmp(&p->designated_root, &br->designated_root, 8))
225 return 1;
226
227 if (br->root_path_cost < p->designated_cost)
228 return 1;
229 else if (br->root_path_cost > p->designated_cost)
230 return 0;
231
232 t = memcmp(&br->bridge_id, &p->designated_bridge, 8);
233 if (t < 0)
234 return 1;
235 else if (t > 0)
236 return 0;
237
238 if (p->port_id < p->designated_port)
239 return 1;
240
241 return 0;
242}
243
244
245static void br_designated_port_selection(struct net_bridge *br)
246{
247 struct net_bridge_port *p;
248
249 p = br->port_list;
250 while (p != NULL) {
251 if (p->state != BR_STATE_DISABLED &&
252 br_should_become_designated_port(p))
253 br_become_designated_port(p);
254
255 p = p->next;
256 }
257}
258
259
260static int br_supersedes_port_info(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
261{
262 int t;
263
264 t = memcmp(&bpdu->root, &p->designated_root, 8);
265 if (t < 0)
266 return 1;
267 else if (t > 0)
268 return 0;
269
270 if (bpdu->root_path_cost < p->designated_cost)
271 return 1;
272 else if (bpdu->root_path_cost > p->designated_cost)
273 return 0;
274
275 t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8);
276 if (t < 0)
277 return 1;
278 else if (t > 0)
279 return 0;
280
281 if (memcmp(&bpdu->bridge_id, &p->br->bridge_id, 8))
282 return 1;
283
284 if (bpdu->port_id <= p->designated_port)
285 return 1;
286
287 return 0;
288}
289
290
291static void br_topology_change_acknowledged(struct net_bridge *br)
292{
293 br->topology_change_detected = 0;
294 br_timer_clear(&br->tcn_timer);
295}
296
297
298void br_topology_change_detection(struct net_bridge *br)
299{
300 printk(KERN_INFO "%s: topology change detected", br->dev.name);
301
302 if (br_is_root_bridge(br)) {
303 printk(", propagating");
304 br->topology_change = 1;
305 br_timer_set(&br->topology_change_timer, jiffies);
306 } else if (!br->topology_change_detected) {
307 printk(", sending tcn bpdu");
308 br_transmit_tcn(br);
309 br_timer_set(&br->tcn_timer, jiffies);
310 }
311
312 printk("\n");
313 br->topology_change_detected = 1;
314}
315
316
317void br_config_bpdu_generation(struct net_bridge *br)
318{
319 struct net_bridge_port *p;
320
321 p = br->port_list;
322 while (p != NULL) {
323 if (p->state != BR_STATE_DISABLED &&
324 br_is_designated_port(p))
325 br_transmit_config(p);
326
327 p = p->next;
328 }
329}
330
331
332static void br_reply(struct net_bridge_port *p)
333{
334 br_transmit_config(p);
335}
336
337
338void br_configuration_update(struct net_bridge *br)
339{
340 br_root_selection(br);
341 br_designated_port_selection(br);
342}
343
344
345void br_become_designated_port(struct net_bridge_port *p)
346{
347 struct net_bridge *br;
348
349 br = p->br;
350 p->designated_root = br->designated_root;
351 p->designated_cost = br->root_path_cost;
352 p->designated_bridge = br->bridge_id;
353 p->designated_port = p->port_id;
354}
355
356
357static void br_make_blocking(struct net_bridge_port *p)
358{
359 if (p->state != BR_STATE_DISABLED &&
360 p->state != BR_STATE_BLOCKING) {
361 if (p->state == BR_STATE_FORWARDING ||
362 p->state == BR_STATE_LEARNING)
363 br_topology_change_detection(p->br);
364
365 printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
366 p->br->dev.name, p->port_no, p->dev->name, "blocking");
367
368 p->state = BR_STATE_BLOCKING;
369 br_timer_clear(&p->forward_delay_timer);
370 }
371}
372
373
374static void br_make_forwarding(struct net_bridge_port *p)
375{
376 if (p->state == BR_STATE_BLOCKING) {
377 if (p->br->stp_enabled) {
378 printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
379 p->br->dev.name, p->port_no, p->dev->name,
380 "listening");
381
382 p->state = BR_STATE_LISTENING;
383 } else {
384 printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
385 p->br->dev.name, p->port_no, p->dev->name,
386 "learning");
387
388 p->state = BR_STATE_LEARNING;
389 }
390 br_timer_set(&p->forward_delay_timer, jiffies);
391 }
392}
393
394
395void br_port_state_selection(struct net_bridge *br)
396{
397 struct net_bridge_port *p;
398
399 p = br->port_list;
400 while (p != NULL) {
401 if (p->state != BR_STATE_DISABLED) {
402 if (p->port_no == br->root_port) {
403 p->config_pending = 0;
404 p->topology_change_ack = 0;
405 br_make_forwarding(p);
406 } else if (br_is_designated_port(p)) {
407 br_timer_clear(&p->message_age_timer);
408 br_make_forwarding(p);
409 } else {
410 p->config_pending = 0;
411 p->topology_change_ack = 0;
412 br_make_blocking(p);
413 }
414 }
415
416 p = p->next;
417 }
418}
419
420
421static void br_topology_change_acknowledge(struct net_bridge_port *p)
422{
423 p->topology_change_ack = 1;
424 br_transmit_config(p);
425}
426
427
428void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
429{
430 struct net_bridge *br;
431 int was_root;
432
433 if (p->state == BR_STATE_DISABLED)
434 return;
435
436 br = p->br;
437 read_lock(&br->lock);
438
439 was_root = br_is_root_bridge(br);
440 if (br_supersedes_port_info(p, bpdu)) {
441 br_record_config_information(p, bpdu);
442 br_configuration_update(br);
443 br_port_state_selection(br);
444
445 if (!br_is_root_bridge(br) && was_root) {
446 br_timer_clear(&br->hello_timer);
447 if (br->topology_change_detected) {
448 br_timer_clear(&br->topology_change_timer);
449 br_transmit_tcn(br);
450 br_timer_set(&br->tcn_timer, jiffies);
451 }
452 }
453
454 if (p->port_no == br->root_port) {
455 br_record_config_timeout_values(br, bpdu);
456 br_config_bpdu_generation(br);
457 if (bpdu->topology_change_ack)
458 br_topology_change_acknowledged(br);
459 }
460 } else if (br_is_designated_port(p)) {
461 br_reply(p);
462 }
463
464 read_unlock(&br->lock);
465}
466
467
468void br_received_tcn_bpdu(struct net_bridge_port *p)
469{
470 read_lock(&p->br->lock);
471 if (p->state != BR_STATE_DISABLED &&
472 br_is_designated_port(p)) {
473 printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n",
474 p->br->dev.name, p->port_no, p->dev->name);
475
476 br_topology_change_detection(p->br);
477 br_topology_change_acknowledge(p);
478 }
479 read_unlock(&p->br->lock);
480}
481