aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c47
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)
635static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) 635static 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
647static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, 648static 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
1395static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list); 1403static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
1396 1404
1397static void rt_add_uncached_list(struct rtable *rt) 1405void 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
1408static void ipv4_dst_destroy(struct dst_entry *dst) 1416void 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
1427static 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
1425void rt_flush_dev(struct net_device *dev) 1438void 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