more changes on original files
[linux-2.4.git] / net / bridge / br_stp.c
1 /*
2  *      Spanning tree protocol; generic parts
3  *      Linux ethernet bridge
4  *
5  *      Authors:
6  *      Lennert Buytenhek               <buytenh@gnu.org>
7  *
8  *      $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $
9  *
10  *      This program is free software; you can redistribute it and/or
11  *      modify it under the terms of the GNU General Public License
12  *      as published by the Free Software Foundation; either version
13  *      2 of the License, or (at your option) any later version.
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 /* since time values in bpdu are in jiffies and then scaled (1/256)
24  * before sending, make sure that is at least one.
25  */
26 #define MESSAGE_AGE_INCR        ((HZ < 256) ? 1 : (HZ/256))
27
28 /* called under ioctl_lock or bridge lock */
29 int br_is_root_bridge(struct net_bridge *br)
30 {
31         return !memcmp(&br->bridge_id, &br->designated_root, 8);
32 }
33
34 /* called under bridge lock */
35 int 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 /* called under ioctl_lock or bridge lock */
42 struct 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 /* called under bridge lock */
58 static 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 /* called under bridge lock */
108 static 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 /* called under bridge lock */
136 void 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
144         br_timer_set(&br->hello_timer, jiffies - br->hello_time);
145 }
146
147 /* called under bridge lock */
148 void 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 /* called under bridge lock */
189 static 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 /* called under bridge lock */
200 static 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 /* called under bridge lock */
209 void br_transmit_tcn(struct net_bridge *br)
210 {
211         br_send_tcn_bpdu(br_get_port(br, br->root_port));
212 }
213
214 /* called under bridge lock */
215 static 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 /* called under bridge lock */
245 static 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 /* called under bridge lock */
260 static 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 /* called under bridge lock */
291 static 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 /* called under bridge lock */
298 void 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 /* called under bridge lock */
317 void 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 /* called under bridge lock */
332 static void br_reply(struct net_bridge_port *p)
333 {
334         br_transmit_config(p);
335 }
336
337 /* called under bridge lock */
338 void br_configuration_update(struct net_bridge *br)
339 {
340         br_root_selection(br);
341         br_designated_port_selection(br);
342 }
343
344 /* called under bridge lock */
345 void 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 /* called under bridge lock */
357 static 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 /* called under bridge lock */
374 static 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 /* called under bridge lock */
395 void 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 /* called under bridge lock */
421 static 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 /* lock-safe */
428 void 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 /* lock-safe */
468 void 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 }