Blame view
net/bridge/br_stp.c
15.7 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 |
/* * Spanning tree protocol; generic parts * Linux ethernet bridge * * Authors: * Lennert Buytenhek <buytenh@gnu.org> |
1da177e4c Linux-2.6.12-rc2 |
8 9 |
*/ #include <linux/kernel.h> |
82524746c rcu: split list.h... |
10 |
#include <linux/rculist.h> |
38dcf357a bridge: call netd... |
11 |
#include <net/switchdev.h> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 15 16 |
#include "br_private.h" #include "br_private_stp.h" /* since time values in bpdu are in jiffies and then scaled (1/256) |
aaca735f4 bridge: Adjust mi... |
17 |
* before sending, make sure that is at least one STP tick. |
1da177e4c Linux-2.6.12-rc2 |
18 |
*/ |
aaca735f4 bridge: Adjust mi... |
19 |
#define MESSAGE_AGE_INCR ((HZ / 256) + 1) |
1da177e4c Linux-2.6.12-rc2 |
20 |
|
36cbd3dcc net: mark read-on... |
21 |
static const char *const br_port_state_names[] = { |
9d6f229fc [NET] BRIDGE: Fix... |
22 |
[BR_STATE_DISABLED] = "disabled", |
1da177e4c Linux-2.6.12-rc2 |
23 |
[BR_STATE_LISTENING] = "listening", |
9d6f229fc [NET] BRIDGE: Fix... |
24 25 |
[BR_STATE_LEARNING] = "learning", [BR_STATE_FORWARDING] = "forwarding", |
1da177e4c Linux-2.6.12-rc2 |
26 27 |
[BR_STATE_BLOCKING] = "blocking", }; |
775dd692b net: bridge: add ... |
28 29 |
void br_set_state(struct net_bridge_port *p, unsigned int state) { |
356360625 switchdev: conver... |
30 |
struct switchdev_attr attr = { |
6ff64f6f9 switchdev: Pass o... |
31 |
.orig_dev = p->dev, |
1f8683987 switchdev: rename... |
32 |
.id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, |
0bc05d585 switchdev: allow ... |
33 |
.flags = SWITCHDEV_F_DEFER, |
42275bd8f switchdev: don't ... |
34 |
.u.stp_state = state, |
356360625 switchdev: conver... |
35 |
}; |
38dcf357a bridge: call netd... |
36 |
int err; |
419dba8a4 net: bridge: Add ... |
37 38 39 40 41 |
/* Don't change the state of the ports if they are driven by a different * protocol. */ if (p->flags & BR_MRP_AWARE) return; |
775dd692b net: bridge: add ... |
42 |
p->state = state; |
356360625 switchdev: conver... |
43 |
err = switchdev_port_attr_set(p->dev, &attr); |
bbe14f542 switchdev: bridge... |
44 |
if (err && err != -EOPNOTSUPP) |
38dcf357a bridge: call netd... |
45 46 47 |
br_warn(p->br, "error setting offload STP state on port %u(%s) ", (unsigned int) p->port_no, p->dev->name); |
7c25b16db net: bridge: log ... |
48 49 50 51 52 |
else br_info(p->br, "port %u(%s) entered %s state ", (unsigned int) p->port_no, p->dev->name, br_port_state_names[p->state]); |
de1799667 net: bridge: add ... |
53 54 55 56 57 58 59 60 61 62 63 |
if (p->br->stp_enabled == BR_KERNEL_STP) { switch (p->state) { case BR_STATE_BLOCKING: p->stp_xstats.transition_blk++; break; case BR_STATE_FORWARDING: p->stp_xstats.transition_fwd++; break; } } |
775dd692b net: bridge: add ... |
64 |
} |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 68 |
/* called under bridge lock */ struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no) { struct net_bridge_port *p; |
33c4acbe2 bridge: br_stp: U... |
69 70 |
list_for_each_entry_rcu(p, &br->port_list, list, lockdep_is_held(&br->lock)) { |
1da177e4c Linux-2.6.12-rc2 |
71 72 73 74 75 76 77 78 |
if (p->port_no == port_no) return p; } return NULL; } /* called under bridge lock */ |
9d6f229fc [NET] BRIDGE: Fix... |
79 |
static int br_should_become_root_port(const struct net_bridge_port *p, |
1da177e4c Linux-2.6.12-rc2 |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
u16 root_port) { struct net_bridge *br; struct net_bridge_port *rp; int t; br = p->br; if (p->state == BR_STATE_DISABLED || br_is_designated_port(p)) return 0; if (memcmp(&br->bridge_id, &p->designated_root, 8) <= 0) return 0; if (!root_port) return 1; rp = br_get_port(br, root_port); t = memcmp(&p->designated_root, &rp->designated_root, 8); if (t < 0) return 1; else if (t > 0) return 0; if (p->designated_cost + p->path_cost < rp->designated_cost + rp->path_cost) return 1; else if (p->designated_cost + p->path_cost > rp->designated_cost + rp->path_cost) return 0; t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8); if (t < 0) return 1; else if (t > 0) return 0; if (p->designated_port < rp->designated_port) return 1; else if (p->designated_port > rp->designated_port) return 0; if (p->port_id < rp->port_id) return 1; return 0; } |
1007dd1aa bridge: add root ... |
128 129 130 131 132 133 |
static void br_root_port_block(const struct net_bridge *br, struct net_bridge_port *p) { br_notice(br, "port %u(%s) tried to become root port (blocked)", (unsigned int) p->port_no, p->dev->name); |
775dd692b net: bridge: add ... |
134 |
br_set_state(p, BR_STATE_LISTENING); |
928990631 net: bridge: add ... |
135 |
br_ifinfo_notify(RTM_NEWLINK, NULL, p); |
1007dd1aa bridge: add root ... |
136 137 138 139 |
if (br->forward_delay > 0) mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); } |
1da177e4c Linux-2.6.12-rc2 |
140 141 142 143 144 145 146 |
/* called under bridge lock */ static void br_root_selection(struct net_bridge *br) { struct net_bridge_port *p; u16 root_port = 0; list_for_each_entry(p, &br->port_list, list) { |
1007dd1aa bridge: add root ... |
147 148 149 150 151 152 |
if (!br_should_become_root_port(p, root_port)) continue; if (p->flags & BR_ROOT_BLOCK) br_root_port_block(br, p); else |
1da177e4c Linux-2.6.12-rc2 |
153 |
root_port = p->port_no; |
1da177e4c Linux-2.6.12-rc2 |
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
} br->root_port = root_port; if (!root_port) { br->designated_root = br->bridge_id; br->root_path_cost = 0; } else { p = br_get_port(br, root_port); br->designated_root = p->designated_root; br->root_path_cost = p->designated_cost + p->path_cost; } } /* called under bridge lock */ void br_become_root_bridge(struct net_bridge *br) { br->max_age = br->bridge_max_age; br->hello_time = br->bridge_hello_time; br->forward_delay = br->bridge_forward_delay; br_topology_change_detection(br); del_timer(&br->tcn_timer); if (br->dev->flags & IFF_UP) { br_config_bpdu_generation(br); mod_timer(&br->hello_timer, jiffies + br->hello_time); } } /* called under bridge lock */ void br_transmit_config(struct net_bridge_port *p) { struct br_config_bpdu bpdu; struct net_bridge *br; |
1da177e4c Linux-2.6.12-rc2 |
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
if (timer_pending(&p->hold_timer)) { p->config_pending = 1; return; } br = p->br; bpdu.topology_change = br->topology_change; bpdu.topology_change_ack = p->topology_change_ack; bpdu.root = br->designated_root; bpdu.root_path_cost = br->root_path_cost; bpdu.bridge_id = br->bridge_id; bpdu.port_id = p->port_id; if (br_is_root_bridge(br)) bpdu.message_age = 0; else { struct net_bridge_port *root = br_get_port(br, br->root_port); |
0c03150e7 bridge: send prop... |
206 |
bpdu.message_age = (jiffies - root->designated_age) |
1da177e4c Linux-2.6.12-rc2 |
207 208 209 210 211 212 213 214 215 216 |
+ MESSAGE_AGE_INCR; } bpdu.max_age = br->max_age; bpdu.hello_time = br->hello_time; bpdu.forward_delay = br->forward_delay; if (bpdu.message_age < br->max_age) { br_send_config_bpdu(p, &bpdu); p->topology_change_ack = 0; p->config_pending = 0; |
76b91c32d bridge: stp: when... |
217 218 219 |
if (p->br->stp_enabled == BR_KERNEL_STP) mod_timer(&p->hold_timer, round_jiffies(jiffies + BR_HOLD_TIME)); |
1da177e4c Linux-2.6.12-rc2 |
220 221 222 223 |
} } /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
224 225 |
static void br_record_config_information(struct net_bridge_port *p, const struct br_config_bpdu *bpdu) |
1da177e4c Linux-2.6.12-rc2 |
226 227 228 229 230 |
{ p->designated_root = bpdu->root; p->designated_cost = bpdu->root_path_cost; p->designated_bridge = bpdu->bridge_id; p->designated_port = bpdu->port_id; |
709e1b5cd bridge: message a... |
231 |
p->designated_age = jiffies - bpdu->message_age; |
1da177e4c Linux-2.6.12-rc2 |
232 |
|
9d6f229fc [NET] BRIDGE: Fix... |
233 |
mod_timer(&p->message_age_timer, jiffies |
9a0620133 resubmit bridge: ... |
234 |
+ (bpdu->max_age - bpdu->message_age)); |
1da177e4c Linux-2.6.12-rc2 |
235 236 237 |
} /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
238 |
static void br_record_config_timeout_values(struct net_bridge *br, |
1da177e4c Linux-2.6.12-rc2 |
239 240 241 242 243 |
const struct br_config_bpdu *bpdu) { br->max_age = bpdu->max_age; br->hello_time = bpdu->hello_time; br->forward_delay = bpdu->forward_delay; |
8384b5f5b net: bridge: add ... |
244 |
__br_set_topology_change(br, bpdu->topology_change); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 248 249 |
} /* called under bridge lock */ void br_transmit_tcn(struct net_bridge *br) { |
91bc033c4 bridge: avoid OOP... |
250 251 252 253 254 255 256 257 258 |
struct net_bridge_port *p; p = br_get_port(br, br->root_port); if (p) br_send_tcn_bpdu(p); else br_notice(br, "root port %u not found for topology notice ", br->root_port); |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
} /* called under bridge lock */ static int br_should_become_designated_port(const struct net_bridge_port *p) { struct net_bridge *br; int t; br = p->br; if (br_is_designated_port(p)) return 1; if (memcmp(&p->designated_root, &br->designated_root, 8)) return 1; if (br->root_path_cost < p->designated_cost) return 1; else if (br->root_path_cost > p->designated_cost) return 0; t = memcmp(&br->bridge_id, &p->designated_bridge, 8); if (t < 0) return 1; else if (t > 0) return 0; if (p->port_id < p->designated_port) return 1; return 0; } /* called under bridge lock */ static void br_designated_port_selection(struct net_bridge *br) { struct net_bridge_port *p; list_for_each_entry(p, &br->port_list, list) { if (p->state != BR_STATE_DISABLED && br_should_become_designated_port(p)) br_become_designated_port(p); } } /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
305 306 |
static int br_supersedes_port_info(const struct net_bridge_port *p, const struct br_config_bpdu *bpdu) |
1da177e4c Linux-2.6.12-rc2 |
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
{ int t; t = memcmp(&bpdu->root, &p->designated_root, 8); if (t < 0) return 1; else if (t > 0) return 0; if (bpdu->root_path_cost < p->designated_cost) return 1; else if (bpdu->root_path_cost > p->designated_cost) return 0; t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8); if (t < 0) return 1; else if (t > 0) return 0; if (memcmp(&bpdu->bridge_id, &p->br->bridge_id, 8)) return 1; if (bpdu->port_id <= p->designated_port) return 1; return 0; } /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
337 |
static void br_topology_change_acknowledged(struct net_bridge *br) |
1da177e4c Linux-2.6.12-rc2 |
338 339 340 341 342 343 344 345 346 |
{ br->topology_change_detected = 0; del_timer(&br->tcn_timer); } /* called under bridge lock */ void br_topology_change_detection(struct net_bridge *br) { int isroot = br_is_root_bridge(br); |
4f0611af4 bridge: fix initi... |
347 348 |
if (br->stp_enabled != BR_KERNEL_STP) return; |
28a16c979 bridge: change co... |
349 350 |
br_info(br, "topology change detected, %s ", |
1da177e4c Linux-2.6.12-rc2 |
351 352 353 |
isroot ? "propagating" : "sending tcn bpdu"); if (isroot) { |
8384b5f5b net: bridge: add ... |
354 |
__br_set_topology_change(br, 1); |
1da177e4c Linux-2.6.12-rc2 |
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
mod_timer(&br->topology_change_timer, jiffies + br->bridge_forward_delay + br->bridge_max_age); } else if (!br->topology_change_detected) { br_transmit_tcn(br); mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); } br->topology_change_detected = 1; } /* called under bridge lock */ void br_config_bpdu_generation(struct net_bridge *br) { struct net_bridge_port *p; list_for_each_entry(p, &br->port_list, list) { if (p->state != BR_STATE_DISABLED && br_is_designated_port(p)) br_transmit_config(p); } } /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
378 |
static void br_reply(struct net_bridge_port *p) |
1da177e4c Linux-2.6.12-rc2 |
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
{ br_transmit_config(p); } /* called under bridge lock */ void br_configuration_update(struct net_bridge *br) { br_root_selection(br); br_designated_port_selection(br); } /* called under bridge lock */ void br_become_designated_port(struct net_bridge_port *p) { struct net_bridge *br; br = p->br; p->designated_root = br->designated_root; p->designated_cost = br->root_path_cost; p->designated_bridge = br->bridge_id; p->designated_port = p->port_id; } /* called under bridge lock */ static void br_make_blocking(struct net_bridge_port *p) { if (p->state != BR_STATE_DISABLED && p->state != BR_STATE_BLOCKING) { if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) br_topology_change_detection(p->br); |
775dd692b net: bridge: add ... |
411 |
br_set_state(p, BR_STATE_BLOCKING); |
928990631 net: bridge: add ... |
412 |
br_ifinfo_notify(RTM_NEWLINK, NULL, p); |
4ecb961c8 bridge: add notif... |
413 |
|
1da177e4c Linux-2.6.12-rc2 |
414 415 416 417 418 419 420 |
del_timer(&p->forward_delay_timer); } } /* called under bridge lock */ static void br_make_forwarding(struct net_bridge_port *p) { |
ef647f130 bridge: Eliminate... |
421 |
struct net_bridge *br = p->br; |
9cde07087 bridge: add suppo... |
422 |
|
ef647f130 bridge: Eliminate... |
423 424 |
if (p->state != BR_STATE_BLOCKING) return; |
a461c0297 bridge: skip forw... |
425 |
if (br->stp_enabled == BR_NO_STP || br->forward_delay == 0) { |
775dd692b net: bridge: add ... |
426 |
br_set_state(p, BR_STATE_FORWARDING); |
ef647f130 bridge: Eliminate... |
427 428 |
br_topology_change_detection(br); del_timer(&p->forward_delay_timer); |
160d73b84 bridge: minor cle... |
429 |
} else if (br->stp_enabled == BR_KERNEL_STP) |
775dd692b net: bridge: add ... |
430 |
br_set_state(p, BR_STATE_LISTENING); |
ef647f130 bridge: Eliminate... |
431 |
else |
775dd692b net: bridge: add ... |
432 |
br_set_state(p, BR_STATE_LEARNING); |
ef647f130 bridge: Eliminate... |
433 |
|
928990631 net: bridge: add ... |
434 |
br_ifinfo_notify(RTM_NEWLINK, NULL, p); |
ef647f130 bridge: Eliminate... |
435 436 437 |
if (br->forward_delay != 0) mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); |
1da177e4c Linux-2.6.12-rc2 |
438 439 440 441 442 443 |
} /* called under bridge lock */ void br_port_state_selection(struct net_bridge *br) { struct net_bridge_port *p; |
1faa4356a bridge: control c... |
444 |
unsigned int liveports = 0; |
1da177e4c Linux-2.6.12-rc2 |
445 446 |
list_for_each_entry(p, &br->port_list, list) { |
1faa4356a bridge: control c... |
447 448 |
if (p->state == BR_STATE_DISABLED) continue; |
b03b6dd58 bridge: master de... |
449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
/* Don't change port states if userspace is handling STP */ if (br->stp_enabled != BR_USER_STP) { if (p->port_no == br->root_port) { p->config_pending = 0; p->topology_change_ack = 0; br_make_forwarding(p); } else if (br_is_designated_port(p)) { del_timer(&p->message_age_timer); br_make_forwarding(p); } else { p->config_pending = 0; p->topology_change_ack = 0; br_make_blocking(p); } |
1da177e4c Linux-2.6.12-rc2 |
463 |
} |
7ce42de18 bridge: multicast... |
464 465 |
if (p->state != BR_STATE_BLOCKING) br_multicast_enable_port(p); |
9aa663821 bridge: multicast... |
466 467 468 469 |
/* Multicast is not disabled for the port when it goes in * blocking state because the timers will expire and stop by * themselves without sending more queries. */ |
1faa4356a bridge: control c... |
470 471 |
if (p->state == BR_STATE_FORWARDING) ++liveports; |
1da177e4c Linux-2.6.12-rc2 |
472 |
} |
1faa4356a bridge: control c... |
473 474 475 476 477 |
if (liveports == 0) netif_carrier_off(br->dev); else netif_carrier_on(br->dev); |
1da177e4c Linux-2.6.12-rc2 |
478 479 480 |
} /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
481 |
static void br_topology_change_acknowledge(struct net_bridge_port *p) |
1da177e4c Linux-2.6.12-rc2 |
482 483 484 485 486 487 |
{ p->topology_change_ack = 1; br_transmit_config(p); } /* called under bridge lock */ |
160d73b84 bridge: minor cle... |
488 489 |
void br_received_config_bpdu(struct net_bridge_port *p, const struct br_config_bpdu *bpdu) |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 |
{ struct net_bridge *br; int was_root; |
9d6f229fc [NET] BRIDGE: Fix... |
493 |
|
de1799667 net: bridge: add ... |
494 |
p->stp_xstats.rx_bpdu++; |
1da177e4c Linux-2.6.12-rc2 |
495 496 497 498 499 500 501 502 503 504 505 506 507 |
br = p->br; was_root = br_is_root_bridge(br); if (br_supersedes_port_info(p, bpdu)) { br_record_config_information(p, bpdu); br_configuration_update(br); br_port_state_selection(br); if (!br_is_root_bridge(br) && was_root) { del_timer(&br->hello_timer); if (br->topology_change_detected) { del_timer(&br->topology_change_timer); br_transmit_tcn(br); |
9d6f229fc [NET] BRIDGE: Fix... |
508 |
mod_timer(&br->tcn_timer, |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 512 513 514 515 516 517 518 |
jiffies + br->bridge_hello_time); } } if (p->port_no == br->root_port) { br_record_config_timeout_values(br, bpdu); br_config_bpdu_generation(br); if (bpdu->topology_change_ack) br_topology_change_acknowledged(br); } |
9d6f229fc [NET] BRIDGE: Fix... |
519 520 |
} else if (br_is_designated_port(p)) { br_reply(p); |
1da177e4c Linux-2.6.12-rc2 |
521 522 523 524 525 526 |
} } /* called under bridge lock */ void br_received_tcn_bpdu(struct net_bridge_port *p) { |
de1799667 net: bridge: add ... |
527 |
p->stp_xstats.rx_tcn++; |
1da177e4c Linux-2.6.12-rc2 |
528 |
if (br_is_designated_port(p)) { |
28a16c979 bridge: change co... |
529 530 |
br_info(p->br, "port %u(%s) received tcn bpdu ", |
95c961747 net: cleanup unsi... |
531 |
(unsigned int) p->port_no, p->dev->name); |
1da177e4c Linux-2.6.12-rc2 |
532 533 534 535 536 |
br_topology_change_detection(p->br); br_topology_change_acknowledge(p); } } |
14f98f258 bridge: range che... |
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
/* Change bridge STP parameter */ int br_set_hello_time(struct net_bridge *br, unsigned long val) { unsigned long t = clock_t_to_jiffies(val); if (t < BR_MIN_HELLO_TIME || t > BR_MAX_HELLO_TIME) return -ERANGE; spin_lock_bh(&br->lock); br->bridge_hello_time = t; if (br_is_root_bridge(br)) br->hello_time = br->bridge_hello_time; spin_unlock_bh(&br->lock); return 0; } int br_set_max_age(struct net_bridge *br, unsigned long val) { unsigned long t = clock_t_to_jiffies(val); if (t < BR_MIN_MAX_AGE || t > BR_MAX_MAX_AGE) return -ERANGE; spin_lock_bh(&br->lock); br->bridge_max_age = t; if (br_is_root_bridge(br)) br->max_age = br->bridge_max_age; spin_unlock_bh(&br->lock); return 0; } |
82dd4332a net: bridge: add ... |
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
/* called under bridge lock */ int __set_ageing_time(struct net_device *dev, unsigned long t) { struct switchdev_attr attr = { .orig_dev = dev, .id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER, .u.ageing_time = jiffies_to_clock_t(t), }; int err; err = switchdev_port_attr_set(dev, &attr); if (err && err != -EOPNOTSUPP) return err; return 0; } |
4c656c13b bridge: allow zer... |
586 587 588 589 590 591 592 593 |
/* Set time interval that dynamic forwarding entries live * For pure software bridge, allow values outside the 802.1 * standard specification for special cases: * 0 - entry never ages (all permanant) * 1 - entry disappears (no persistance) * * Offloaded switch entries maybe more restrictive */ |
9e0b27fe5 net: bridge: br_s... |
594 |
int br_set_ageing_time(struct net_bridge *br, clock_t ageing_time) |
c62987bbd bridge: push brid... |
595 |
{ |
c62987bbd bridge: push brid... |
596 597 |
unsigned long t = clock_t_to_jiffies(ageing_time); int err; |
82dd4332a net: bridge: add ... |
598 599 |
err = __set_ageing_time(br->dev, t); if (err) |
c62987bbd bridge: push brid... |
600 |
return err; |
34d8acd8a net: bridge: shor... |
601 602 |
spin_lock_bh(&br->lock); br->bridge_ageing_time = t; |
c62987bbd bridge: push brid... |
603 |
br->ageing_time = t; |
34d8acd8a net: bridge: shor... |
604 |
spin_unlock_bh(&br->lock); |
f7cdee8a7 bridge: move to w... |
605 |
mod_delayed_work(system_long_wq, &br->gc_work, 0); |
c62987bbd bridge: push brid... |
606 607 608 |
return 0; } |
8384b5f5b net: bridge: add ... |
609 610 611 |
/* called under bridge lock */ void __br_set_topology_change(struct net_bridge *br, unsigned char val) { |
34d8acd8a net: bridge: shor... |
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
unsigned long t; int err; if (br->stp_enabled == BR_KERNEL_STP && br->topology_change != val) { /* On topology change, set the bridge ageing time to twice the * forward delay. Otherwise, restore its default ageing time. */ if (val) { t = 2 * br->forward_delay; br_debug(br, "decreasing ageing time to %lu ", t); } else { t = br->bridge_ageing_time; br_debug(br, "restoring ageing time to %lu ", t); } err = __set_ageing_time(br->dev, t); if (err) br_warn(br, "error offloading ageing time "); else br->ageing_time = t; } |
8384b5f5b net: bridge: add ... |
637 638 |
br->topology_change = val; } |
be4f154d5 bridge: Clamp for... |
639 640 641 642 643 644 |
void __br_set_forward_delay(struct net_bridge *br, unsigned long t) { br->bridge_forward_delay = t; if (br_is_root_bridge(br)) br->forward_delay = br->bridge_forward_delay; } |
14f98f258 bridge: range che... |
645 646 647 |
int br_set_forward_delay(struct net_bridge *br, unsigned long val) { unsigned long t = clock_t_to_jiffies(val); |
8a921265e Revert "bridge: A... |
648 |
int err = -ERANGE; |
14f98f258 bridge: range che... |
649 |
|
34c2d9fb0 bridge: Allow for... |
650 |
spin_lock_bh(&br->lock); |
8a921265e Revert "bridge: A... |
651 652 653 |
if (br->stp_enabled != BR_NO_STP && (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY)) goto unlock; |
be4f154d5 bridge: Clamp for... |
654 |
__br_set_forward_delay(br, t); |
8a921265e Revert "bridge: A... |
655 656 657 |
err = 0; unlock: |
14f98f258 bridge: range che... |
658 |
spin_unlock_bh(&br->lock); |
8a921265e Revert "bridge: A... |
659 |
return err; |
14f98f258 bridge: range che... |
660 |
} |