diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e74ee837b300..4ac5728689f5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -635,6 +635,7 @@ static inline u32 fnhe_hashfun(__be32 daddr) | |||
635 | static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) | 635 | static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) |
636 | { | 636 | { |
637 | rt->rt_pmtu = fnhe->fnhe_pmtu; | 637 | rt->rt_pmtu = fnhe->fnhe_pmtu; |
638 | rt->rt_mtu_locked = fnhe->fnhe_mtu_locked; | ||
638 | rt->dst.expires = fnhe->fnhe_expires; | 639 | rt->dst.expires = fnhe->fnhe_expires; |
639 | 640 | ||
640 | if (fnhe->fnhe_gw) { | 641 | if (fnhe->fnhe_gw) { |
@@ -645,7 +646,7 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh | |||
645 | } | 646 | } |
646 | 647 | ||
647 | static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, | 648 | static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, |
648 | u32 pmtu, unsigned long expires) | 649 | u32 pmtu, bool lock, unsigned long expires) |
649 | { | 650 | { |
650 | struct fnhe_hash_bucket *hash; | 651 | struct fnhe_hash_bucket *hash; |
651 | struct fib_nh_exception *fnhe; | 652 | struct fib_nh_exception *fnhe; |
@@ -682,8 +683,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, | |||
682 | fnhe->fnhe_genid = genid; | 683 | fnhe->fnhe_genid = genid; |
683 | if (gw) | 684 | if (gw) |
684 | fnhe->fnhe_gw = gw; | 685 | fnhe->fnhe_gw = gw; |
685 | if (pmtu) | 686 | if (pmtu) { |
686 | fnhe->fnhe_pmtu = pmtu; | 687 | fnhe->fnhe_pmtu = pmtu; |
688 | fnhe->fnhe_mtu_locked = lock; | ||
689 | } | ||
687 | fnhe->fnhe_expires = max(1UL, expires); | 690 | fnhe->fnhe_expires = max(1UL, expires); |
688 | /* Update all cached dsts too */ | 691 | /* Update all cached dsts too */ |
689 | rt = rcu_dereference(fnhe->fnhe_rth_input); | 692 | rt = rcu_dereference(fnhe->fnhe_rth_input); |
@@ -707,6 +710,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, | |||
707 | fnhe->fnhe_daddr = daddr; | 710 | fnhe->fnhe_daddr = daddr; |
708 | fnhe->fnhe_gw = gw; | 711 | fnhe->fnhe_gw = gw; |
709 | fnhe->fnhe_pmtu = pmtu; | 712 | fnhe->fnhe_pmtu = pmtu; |
713 | fnhe->fnhe_mtu_locked = lock; | ||
710 | fnhe->fnhe_expires = expires; | 714 | fnhe->fnhe_expires = expires; |
711 | 715 | ||
712 | /* Exception created; mark the cached routes for the nexthop | 716 | /* Exception created; mark the cached routes for the nexthop |
@@ -788,7 +792,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow | |||
788 | struct fib_nh *nh = &FIB_RES_NH(res); | 792 | struct fib_nh *nh = &FIB_RES_NH(res); |
789 | 793 | ||
790 | update_or_create_fnhe(nh, fl4->daddr, new_gw, | 794 | update_or_create_fnhe(nh, fl4->daddr, new_gw, |
791 | 0, jiffies + ip_rt_gc_timeout); | 795 | 0, false, |
796 | jiffies + ip_rt_gc_timeout); | ||
792 | } | 797 | } |
793 | if (kill_route) | 798 | if (kill_route) |
794 | rt->dst.obsolete = DST_OBSOLETE_KILL; | 799 | rt->dst.obsolete = DST_OBSOLETE_KILL; |
@@ -1010,15 +1015,18 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) | |||
1010 | { | 1015 | { |
1011 | struct dst_entry *dst = &rt->dst; | 1016 | struct dst_entry *dst = &rt->dst; |
1012 | struct fib_result res; | 1017 | struct fib_result res; |
1018 | bool lock = false; | ||
1013 | 1019 | ||
1014 | if (dst_metric_locked(dst, RTAX_MTU)) | 1020 | if (ip_mtu_locked(dst)) |
1015 | return; | 1021 | return; |
1016 | 1022 | ||
1017 | if (ipv4_mtu(dst) < mtu) | 1023 | if (ipv4_mtu(dst) < mtu) |
1018 | return; | 1024 | return; |
1019 | 1025 | ||
1020 | if (mtu < ip_rt_min_pmtu) | 1026 | if (mtu < ip_rt_min_pmtu) { |
1027 | lock = true; | ||
1021 | mtu = ip_rt_min_pmtu; | 1028 | mtu = ip_rt_min_pmtu; |
1029 | } | ||
1022 | 1030 | ||
1023 | if (rt->rt_pmtu == mtu && | 1031 | if (rt->rt_pmtu == mtu && |
1024 | time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) | 1032 | time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) |
@@ -1028,7 +1036,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) | |||
1028 | if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { | 1036 | if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { |
1029 | struct fib_nh *nh = &FIB_RES_NH(res); | 1037 | struct fib_nh *nh = &FIB_RES_NH(res); |
1030 | 1038 | ||
1031 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, | 1039 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock, |
1032 | jiffies + ip_rt_mtu_expires); | 1040 | jiffies + ip_rt_mtu_expires); |
1033 | } | 1041 | } |
1034 | rcu_read_unlock(); | 1042 | rcu_read_unlock(); |
@@ -1281,7 +1289,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) | |||
1281 | 1289 | ||
1282 | mtu = READ_ONCE(dst->dev->mtu); | 1290 | mtu = READ_ONCE(dst->dev->mtu); |
1283 | 1291 | ||
1284 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { | 1292 | if (unlikely(ip_mtu_locked(dst))) { |
1285 | if (rt->rt_uses_gateway && mtu > 576) | 1293 | if (rt->rt_uses_gateway && mtu > 576) |
1286 | mtu = 576; | 1294 | mtu = 576; |
1287 | } | 1295 | } |
@@ -1394,7 +1402,7 @@ struct uncached_list { | |||
1394 | 1402 | ||
1395 | static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list); | 1403 | static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list); |
1396 | 1404 | ||
1397 | static void rt_add_uncached_list(struct rtable *rt) | 1405 | void rt_add_uncached_list(struct rtable *rt) |
1398 | { | 1406 | { |
1399 | struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list); | 1407 | struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list); |
1400 | 1408 | ||
@@ -1405,14 +1413,8 @@ static void rt_add_uncached_list(struct rtable *rt) | |||
1405 | spin_unlock_bh(&ul->lock); | 1413 | spin_unlock_bh(&ul->lock); |
1406 | } | 1414 | } |
1407 | 1415 | ||
1408 | static void ipv4_dst_destroy(struct dst_entry *dst) | 1416 | void rt_del_uncached_list(struct rtable *rt) |
1409 | { | 1417 | { |
1410 | struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); | ||
1411 | struct rtable *rt = (struct rtable *) dst; | ||
1412 | |||
1413 | if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) | ||
1414 | kfree(p); | ||
1415 | |||
1416 | if (!list_empty(&rt->rt_uncached)) { | 1418 | if (!list_empty(&rt->rt_uncached)) { |
1417 | struct uncached_list *ul = rt->rt_uncached_list; | 1419 | struct uncached_list *ul = rt->rt_uncached_list; |
1418 | 1420 | ||
@@ -1422,6 +1424,17 @@ static void ipv4_dst_destroy(struct dst_entry *dst) | |||
1422 | } | 1424 | } |
1423 | } | 1425 | } |
1424 | 1426 | ||
1427 | static void ipv4_dst_destroy(struct dst_entry *dst) | ||
1428 | { | ||
1429 | struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); | ||
1430 | struct rtable *rt = (struct rtable *)dst; | ||
1431 | |||
1432 | if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) | ||
1433 | kfree(p); | ||
1434 | |||
1435 | rt_del_uncached_list(rt); | ||
1436 | } | ||
1437 | |||
1425 | void rt_flush_dev(struct net_device *dev) | 1438 | void rt_flush_dev(struct net_device *dev) |
1426 | { | 1439 | { |
1427 | struct net *net = dev_net(dev); | 1440 | struct net *net = dev_net(dev); |
@@ -1517,6 +1530,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev, | |||
1517 | rt->rt_is_input = 0; | 1530 | rt->rt_is_input = 0; |
1518 | rt->rt_iif = 0; | 1531 | rt->rt_iif = 0; |
1519 | rt->rt_pmtu = 0; | 1532 | rt->rt_pmtu = 0; |
1533 | rt->rt_mtu_locked = 0; | ||
1520 | rt->rt_gateway = 0; | 1534 | rt->rt_gateway = 0; |
1521 | rt->rt_uses_gateway = 0; | 1535 | rt->rt_uses_gateway = 0; |
1522 | INIT_LIST_HEAD(&rt->rt_uncached); | 1536 | INIT_LIST_HEAD(&rt->rt_uncached); |
@@ -2533,6 +2547,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or | |||
2533 | rt->rt_is_input = ort->rt_is_input; | 2547 | rt->rt_is_input = ort->rt_is_input; |
2534 | rt->rt_iif = ort->rt_iif; | 2548 | rt->rt_iif = ort->rt_iif; |
2535 | rt->rt_pmtu = ort->rt_pmtu; | 2549 | rt->rt_pmtu = ort->rt_pmtu; |
2550 | rt->rt_mtu_locked = ort->rt_mtu_locked; | ||
2536 | 2551 | ||
2537 | rt->rt_genid = rt_genid_ipv4(net); | 2552 | rt->rt_genid = rt_genid_ipv4(net); |
2538 | rt->rt_flags = ort->rt_flags; | 2553 | rt->rt_flags = ort->rt_flags; |
@@ -2635,6 +2650,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, | |||
2635 | memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); | 2650 | memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); |
2636 | if (rt->rt_pmtu && expires) | 2651 | if (rt->rt_pmtu && expires) |
2637 | metrics[RTAX_MTU - 1] = rt->rt_pmtu; | 2652 | metrics[RTAX_MTU - 1] = rt->rt_pmtu; |
2653 | if (rt->rt_mtu_locked && expires) | ||
2654 | metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU); | ||
2638 | if (rtnetlink_put_metrics(skb, metrics) < 0) | 2655 | if (rtnetlink_put_metrics(skb, metrics) < 0) |
2639 | goto nla_put_failure; | 2656 | goto nla_put_failure; |
2640 | 2657 | ||