diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index f8c7ec8171a8..b5c3937ca6ec 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -1457,6 +1457,56 @@ static int call_fib_nh_notifiers(struct fib_nh *fib_nh, | |||
1457 | return NOTIFY_DONE; | 1457 | return NOTIFY_DONE; |
1458 | } | 1458 | } |
1459 | 1459 | ||
1460 | /* Update the PMTU of exceptions when: | ||
1461 | * - the new MTU of the first hop becomes smaller than the PMTU | ||
1462 | * - the old MTU was the same as the PMTU, and it limited discovery of | ||
1463 | * larger MTUs on the path. With that limit raised, we can now | ||
1464 | * discover larger MTUs | ||
1465 | * A special case is locked exceptions, for which the PMTU is smaller | ||
1466 | * than the minimal accepted PMTU: | ||
1467 | * - if the new MTU is greater than the PMTU, don't make any change | ||
1468 | * - otherwise, unlock and set PMTU | ||
1469 | */ | ||
1470 | static void nh_update_mtu(struct fib_nh *nh, u32 new, u32 orig) | ||
1471 | { | ||
1472 | struct fnhe_hash_bucket *bucket; | ||
1473 | int i; | ||
1474 | |||
1475 | bucket = rcu_dereference_protected(nh->nh_exceptions, 1); | ||
1476 | if (!bucket) | ||
1477 | return; | ||
1478 | |||
1479 | for (i = 0; i < FNHE_HASH_SIZE; i++) { | ||
1480 | struct fib_nh_exception *fnhe; | ||
1481 | |||
1482 | for (fnhe = rcu_dereference_protected(bucket[i].chain, 1); | ||
1483 | fnhe; | ||
1484 | fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { | ||
1485 | if (fnhe->fnhe_mtu_locked) { | ||
1486 | if (new <= fnhe->fnhe_pmtu) { | ||
1487 | fnhe->fnhe_pmtu = new; | ||
1488 | fnhe->fnhe_mtu_locked = false; | ||
1489 | } | ||
1490 | } else if (new < fnhe->fnhe_pmtu || | ||
1491 | orig == fnhe->fnhe_pmtu) { | ||
1492 | fnhe->fnhe_pmtu = new; | ||
1493 | } | ||
1494 | } | ||
1495 | } | ||
1496 | } | ||
1497 | |||
1498 | void fib_sync_mtu(struct net_device *dev, u32 orig_mtu) | ||
1499 | { | ||
1500 | unsigned int hash = fib_devindex_hashfn(dev->ifindex); | ||
1501 | struct hlist_head *head = &fib_info_devhash[hash]; | ||
1502 | struct fib_nh *nh; | ||
1503 | |||
1504 | hlist_for_each_entry(nh, head, nh_hash) { | ||
1505 | if (nh->nh_dev == dev) | ||
1506 | nh_update_mtu(nh, dev->mtu, orig_mtu); | ||
1507 | } | ||
1508 | } | ||
1509 | |||
1460 | /* Event force Flags Description | 1510 | /* Event force Flags Description |
1461 | * NETDEV_CHANGE 0 LINKDOWN Carrier OFF, not for scope host | 1511 | * NETDEV_CHANGE 0 LINKDOWN Carrier OFF, not for scope host |
1462 | * NETDEV_DOWN 0 LINKDOWN|DEAD Link down, not for scope host | 1512 | * NETDEV_DOWN 0 LINKDOWN|DEAD Link down, not for scope host |