|
@@ -1470,6 +1470,56 @@ static int call_fib_nh_notifiers(struct fib_nh *fib_nh,
|
|
|
return NOTIFY_DONE;
|
|
|
}
|
|
|
|
|
|
+/* Update the PMTU of exceptions when:
|
|
|
+ * - the new MTU of the first hop becomes smaller than the PMTU
|
|
|
+ * - the old MTU was the same as the PMTU, and it limited discovery of
|
|
|
+ * larger MTUs on the path. With that limit raised, we can now
|
|
|
+ * discover larger MTUs
|
|
|
+ * A special case is locked exceptions, for which the PMTU is smaller
|
|
|
+ * than the minimal accepted PMTU:
|
|
|
+ * - if the new MTU is greater than the PMTU, don't make any change
|
|
|
+ * - otherwise, unlock and set PMTU
|
|
|
+ */
|
|
|
+static void nh_update_mtu(struct fib_nh *nh, u32 new, u32 orig)
|
|
|
+{
|
|
|
+ struct fnhe_hash_bucket *bucket;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ bucket = rcu_dereference_protected(nh->nh_exceptions, 1);
|
|
|
+ if (!bucket)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; i < FNHE_HASH_SIZE; i++) {
|
|
|
+ struct fib_nh_exception *fnhe;
|
|
|
+
|
|
|
+ for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
|
|
|
+ fnhe;
|
|
|
+ fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
|
|
|
+ if (fnhe->fnhe_mtu_locked) {
|
|
|
+ if (new <= fnhe->fnhe_pmtu) {
|
|
|
+ fnhe->fnhe_pmtu = new;
|
|
|
+ fnhe->fnhe_mtu_locked = false;
|
|
|
+ }
|
|
|
+ } else if (new < fnhe->fnhe_pmtu ||
|
|
|
+ orig == fnhe->fnhe_pmtu) {
|
|
|
+ fnhe->fnhe_pmtu = new;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
|
|
|
+{
|
|
|
+ unsigned int hash = fib_devindex_hashfn(dev->ifindex);
|
|
|
+ struct hlist_head *head = &fib_info_devhash[hash];
|
|
|
+ struct fib_nh *nh;
|
|
|
+
|
|
|
+ hlist_for_each_entry(nh, head, nh_hash) {
|
|
|
+ if (nh->nh_dev == dev)
|
|
|
+ nh_update_mtu(nh, dev->mtu, orig_mtu);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* Event force Flags Description
|
|
|
* NETDEV_CHANGE 0 LINKDOWN Carrier OFF, not for scope host
|
|
|
* NETDEV_DOWN 0 LINKDOWN|DEAD Link down, not for scope host
|