route.c (effda4dd97e878ab83336bec7411cc41b5cc6d37) | route.c (7d21fec90438941b44b699ae73673d2f8a3a9d76) |
---|---|
1/* 2 * Linux INET6 implementation 3 * FIB front-end. 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * This program is free software; you can redistribute it and/or --- 486 unchanged lines hidden (view full) --- 495 const struct in6_addr *saddr, int oif, int flags) 496{ 497 struct fib6_info *f6i = res->f6i; 498 struct fib6_info *spf6i; 499 struct fib6_nh *nh; 500 501 if (!oif && ipv6_addr_any(saddr)) { 502 nh = &f6i->fib6_nh; | 1/* 2 * Linux INET6 implementation 3 * FIB front-end. 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * This program is free software; you can redistribute it and/or --- 486 unchanged lines hidden (view full) --- 495 const struct in6_addr *saddr, int oif, int flags) 496{ 497 struct fib6_info *f6i = res->f6i; 498 struct fib6_info *spf6i; 499 struct fib6_nh *nh; 500 501 if (!oif && ipv6_addr_any(saddr)) { 502 nh = &f6i->fib6_nh; |
503 if (!(nh->fib_nh_flags & RTNH_F_DEAD)) { 504 res->nh = nh; 505 return; 506 } | 503 if (!(nh->fib_nh_flags & RTNH_F_DEAD)) 504 goto out; |
507 } 508 509 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) { 510 nh = &spf6i->fib6_nh; 511 if (__rt6_device_match(net, nh, saddr, oif, flags)) { 512 res->f6i = spf6i; | 505 } 506 507 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) { 508 nh = &spf6i->fib6_nh; 509 if (__rt6_device_match(net, nh, saddr, oif, flags)) { 510 res->f6i = spf6i; |
513 res->nh = nh; | 511 goto out; |
514 } 515 } 516 517 if (oif && flags & RT6_LOOKUP_F_IFACE) { 518 res->f6i = net->ipv6.fib6_null_entry; | 512 } 513 } 514 515 if (oif && flags & RT6_LOOKUP_F_IFACE) { 516 res->f6i = net->ipv6.fib6_null_entry; |
519 res->nh = &res->f6i->fib6_nh; 520 return; | 517 nh = &res->f6i->fib6_nh; 518 goto out; |
521 } 522 | 519 } 520 |
523 res->nh = &f6i->fib6_nh; 524 if (res->nh->fib_nh_flags & RTNH_F_DEAD) { | 521 nh = &f6i->fib6_nh; 522 if (nh->fib_nh_flags & RTNH_F_DEAD) { |
525 res->f6i = net->ipv6.fib6_null_entry; | 523 res->f6i = net->ipv6.fib6_null_entry; |
526 res->nh = &res->f6i->fib6_nh; | 524 nh = &res->f6i->fib6_nh; |
527 } | 525 } |
526out: 527 res->nh = nh; 528 res->fib6_type = res->f6i->fib6_type; 529 res->fib6_flags = res->f6i->fib6_flags; |
|
528} 529 530#ifdef CONFIG_IPV6_ROUTER_PREF 531struct __rt6_probe_work { 532 struct work_struct work; 533 struct in6_addr target; 534 struct net_device *dev; 535}; --- 178 unchanged lines hidden (view full) --- 714 715 if (fib6_check_expired(f6i)) 716 continue; 717 718 nh = &f6i->fib6_nh; 719 if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) { 720 res->f6i = f6i; 721 res->nh = nh; | 530} 531 532#ifdef CONFIG_IPV6_ROUTER_PREF 533struct __rt6_probe_work { 534 struct work_struct work; 535 struct in6_addr target; 536 struct net_device *dev; 537}; --- 178 unchanged lines hidden (view full) --- 716 717 if (fib6_check_expired(f6i)) 718 continue; 719 720 nh = &f6i->fib6_nh; 721 if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) { 722 res->f6i = f6i; 723 res->nh = nh; |
724 res->fib6_flags = f6i->fib6_flags; 725 res->fib6_type = f6i->fib6_type; |
|
722 } 723 } 724} 725 726static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf, 727 struct fib6_info *rr_head, int oif, int strict, 728 bool *do_rr, struct fib6_result *res) 729{ --- 61 unchanged lines hidden (view full) --- 791 spin_unlock_bh(&leaf->fib6_table->tb6_lock); 792 } 793 } 794 795out: 796 if (!res->f6i) { 797 res->f6i = net->ipv6.fib6_null_entry; 798 res->nh = &res->f6i->fib6_nh; | 726 } 727 } 728} 729 730static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf, 731 struct fib6_info *rr_head, int oif, int strict, 732 bool *do_rr, struct fib6_result *res) 733{ --- 61 unchanged lines hidden (view full) --- 795 spin_unlock_bh(&leaf->fib6_table->tb6_lock); 796 } 797 } 798 799out: 800 if (!res->f6i) { 801 res->f6i = net->ipv6.fib6_null_entry; 802 res->nh = &res->f6i->fib6_nh; |
803 res->fib6_flags = res->f6i->fib6_flags; 804 res->fib6_type = res->f6i->fib6_type; |
|
799 } 800} 801 802static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res) 803{ 804 return (res->f6i->fib6_flags & RTF_NONEXTHOP) || 805 res->nh->fib_nh_gw_family; 806} --- 77 unchanged lines hidden (view full) --- 884/* 885 * Misc support functions 886 */ 887 888/* called with rcu_lock held */ 889static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res) 890{ 891 struct net_device *dev = res->nh->fib_nh_dev; | 805 } 806} 807 808static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res) 809{ 810 return (res->f6i->fib6_flags & RTF_NONEXTHOP) || 811 res->nh->fib_nh_gw_family; 812} --- 77 unchanged lines hidden (view full) --- 890/* 891 * Misc support functions 892 */ 893 894/* called with rcu_lock held */ 895static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res) 896{ 897 struct net_device *dev = res->nh->fib_nh_dev; |
892 const struct fib6_info *f6i = res->f6i; | |
893 | 898 |
894 if (f6i->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { | 899 if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { |
895 /* for copies of local routes, dst->dev needs to be the 896 * device if it is a master device, the master device if 897 * device is enslaved, and the loopback as the default 898 */ 899 if (netif_is_l3_slave(dev) && | 900 /* for copies of local routes, dst->dev needs to be the 901 * device if it is a master device, the master device if 902 * device is enslaved, and the loopback as the default 903 */ 904 if (netif_is_l3_slave(dev) && |
900 !rt6_need_strict(&f6i->fib6_dst.addr)) | 905 !rt6_need_strict(&res->f6i->fib6_dst.addr)) |
901 dev = l3mdev_master_dev_rcu(dev); 902 else if (!netif_is_l3_master(dev)) 903 dev = dev_net(dev)->loopback_dev; 904 /* last case is netif_is_l3_master(dev) is true in which 905 * case we want dev returned to be dev 906 */ 907 } 908 --- 29 unchanged lines hidden (view full) --- 938 if (rt->dst_nopolicy) 939 flags |= DST_NOPOLICY; 940 if (rt->dst_host) 941 flags |= DST_HOST; 942 943 return flags; 944} 945 | 906 dev = l3mdev_master_dev_rcu(dev); 907 else if (!netif_is_l3_master(dev)) 908 dev = dev_net(dev)->loopback_dev; 909 /* last case is netif_is_l3_master(dev) is true in which 910 * case we want dev returned to be dev 911 */ 912 } 913 --- 29 unchanged lines hidden (view full) --- 943 if (rt->dst_nopolicy) 944 flags |= DST_NOPOLICY; 945 if (rt->dst_host) 946 flags |= DST_HOST; 947 948 return flags; 949} 950 |
946static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort) | 951static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type) |
947{ | 952{ |
948 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type); | 953 rt->dst.error = ip6_rt_type_to_error(fib6_type); |
949 | 954 |
950 switch (ort->fib6_type) { | 955 switch (fib6_type) { |
951 case RTN_BLACKHOLE: 952 rt->dst.output = dst_discard_out; 953 rt->dst.input = dst_discard; 954 break; 955 case RTN_PROHIBIT: 956 rt->dst.output = ip6_pkt_prohibit_out; 957 rt->dst.input = ip6_pkt_prohibit; 958 break; 959 case RTN_THROW: 960 case RTN_UNREACHABLE: 961 default: 962 rt->dst.output = ip6_pkt_discard_out; 963 rt->dst.input = ip6_pkt_discard; 964 break; 965 } 966} 967 968static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) 969{ | 956 case RTN_BLACKHOLE: 957 rt->dst.output = dst_discard_out; 958 rt->dst.input = dst_discard; 959 break; 960 case RTN_PROHIBIT: 961 rt->dst.output = ip6_pkt_prohibit_out; 962 rt->dst.input = ip6_pkt_prohibit; 963 break; 964 case RTN_THROW: 965 case RTN_UNREACHABLE: 966 default: 967 rt->dst.output = ip6_pkt_discard_out; 968 rt->dst.input = ip6_pkt_discard; 969 break; 970 } 971} 972 973static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) 974{ |
970 struct fib6_info *ort = res->f6i; | 975 struct fib6_info *f6i = res->f6i; |
971 | 976 |
972 if (ort->fib6_flags & RTF_REJECT) { 973 ip6_rt_init_dst_reject(rt, ort); | 977 if (res->fib6_flags & RTF_REJECT) { 978 ip6_rt_init_dst_reject(rt, res->fib6_type); |
974 return; 975 } 976 977 rt->dst.error = 0; 978 rt->dst.output = ip6_output; 979 | 979 return; 980 } 981 982 rt->dst.error = 0; 983 rt->dst.output = ip6_output; 984 |
980 if (ort->fib6_type == RTN_LOCAL || ort->fib6_type == RTN_ANYCAST) { | 985 if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) { |
981 rt->dst.input = ip6_input; | 986 rt->dst.input = ip6_input; |
982 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) { | 987 } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) { |
983 rt->dst.input = ip6_mc_input; 984 } else { 985 rt->dst.input = ip6_forward; 986 } 987 988 if (res->nh->fib_nh_lws) { 989 rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws); 990 lwtunnel_set_redirect(&rt->dst); --- 16 unchanged lines hidden (view full) --- 1007 const struct fib6_nh *nh = res->nh; 1008 const struct net_device *dev = nh->fib_nh_dev; 1009 struct fib6_info *f6i = res->f6i; 1010 1011 ip6_rt_init_dst(rt, res); 1012 1013 rt->rt6i_dst = f6i->fib6_dst; 1014 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; | 988 rt->dst.input = ip6_mc_input; 989 } else { 990 rt->dst.input = ip6_forward; 991 } 992 993 if (res->nh->fib_nh_lws) { 994 rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws); 995 lwtunnel_set_redirect(&rt->dst); --- 16 unchanged lines hidden (view full) --- 1012 const struct fib6_nh *nh = res->nh; 1013 const struct net_device *dev = nh->fib_nh_dev; 1014 struct fib6_info *f6i = res->f6i; 1015 1016 ip6_rt_init_dst(rt, res); 1017 1018 rt->rt6i_dst = f6i->fib6_dst; 1019 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; |
1015 rt->rt6i_flags = f6i->fib6_flags; | 1020 rt->rt6i_flags = res->fib6_flags; |
1016 if (nh->fib_nh_gw_family) { 1017 rt->rt6i_gateway = nh->fib_nh_gw6; 1018 rt->rt6i_flags |= RTF_GATEWAY; 1019 } 1020 rt6_set_from(rt, f6i); 1021#ifdef CONFIG_IPV6_SUBTREES 1022 rt->rt6i_src = f6i->fib6_src; 1023#endif --- 1336 unchanged lines hidden (view full) --- 2360 2361 rcu_read_lock(); 2362 res.f6i = rcu_dereference(rt6->from); 2363 if (!res.f6i) { 2364 rcu_read_unlock(); 2365 return; 2366 } 2367 res.nh = &res.f6i->fib6_nh; | 1021 if (nh->fib_nh_gw_family) { 1022 rt->rt6i_gateway = nh->fib_nh_gw6; 1023 rt->rt6i_flags |= RTF_GATEWAY; 1024 } 1025 rt6_set_from(rt, f6i); 1026#ifdef CONFIG_IPV6_SUBTREES 1027 rt->rt6i_src = f6i->fib6_src; 1028#endif --- 1336 unchanged lines hidden (view full) --- 2365 2366 rcu_read_lock(); 2367 res.f6i = rcu_dereference(rt6->from); 2368 if (!res.f6i) { 2369 rcu_read_unlock(); 2370 return; 2371 } 2372 res.nh = &res.f6i->fib6_nh; |
2373 res.fib6_flags = res.f6i->fib6_flags; 2374 res.fib6_type = res.f6i->fib6_type; 2375 |
|
2368 nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr); 2369 if (nrt6) { 2370 rt6_do_update_pmtu(nrt6, mtu); 2371 if (rt6_insert_exception(nrt6, &res)) 2372 dst_release_immediate(&nrt6->dst); 2373 } 2374 rcu_read_unlock(); 2375 } --- 149 unchanged lines hidden (view full) --- 2525 fn = fib6_backtrack(fn, &fl6->saddr); 2526 if (fn) 2527 goto restart; 2528 } 2529 2530 res.f6i = rt; 2531 res.nh = &rt->fib6_nh; 2532out: | 2376 nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr); 2377 if (nrt6) { 2378 rt6_do_update_pmtu(nrt6, mtu); 2379 if (rt6_insert_exception(nrt6, &res)) 2380 dst_release_immediate(&nrt6->dst); 2381 } 2382 rcu_read_unlock(); 2383 } --- 149 unchanged lines hidden (view full) --- 2533 fn = fib6_backtrack(fn, &fl6->saddr); 2534 if (fn) 2535 goto restart; 2536 } 2537 2538 res.f6i = rt; 2539 res.nh = &rt->fib6_nh; 2540out: |
2533 if (ret) | 2541 if (ret) { |
2534 ip6_hold_safe(net, &ret); | 2542 ip6_hold_safe(net, &ret); |
2535 else | 2543 } else { 2544 res.fib6_flags = res.f6i->fib6_flags; 2545 res.fib6_type = res.f6i->fib6_type; |
2536 ret = ip6_create_rt_rcu(&res); | 2546 ret = ip6_create_rt_rcu(&res); |
2547 } |
|
2537 2538 rcu_read_unlock(); 2539 2540 trace_fib6_table_lookup(net, &res, table, fl6); 2541 return ret; 2542}; 2543 2544static struct dst_entry *ip6_route_redirect(struct net *net, --- 941 unchanged lines hidden (view full) --- 3486 res.f6i = rcu_dereference(rt->from); 3487 /* This fib6_info_hold() is safe here because we hold reference to rt 3488 * and rt already holds reference to fib6_info. 3489 */ 3490 fib6_info_hold(res.f6i); 3491 rcu_read_unlock(); 3492 3493 res.nh = &res.f6i->fib6_nh; | 2548 2549 rcu_read_unlock(); 2550 2551 trace_fib6_table_lookup(net, &res, table, fl6); 2552 return ret; 2553}; 2554 2555static struct dst_entry *ip6_route_redirect(struct net *net, --- 941 unchanged lines hidden (view full) --- 3497 res.f6i = rcu_dereference(rt->from); 3498 /* This fib6_info_hold() is safe here because we hold reference to rt 3499 * and rt already holds reference to fib6_info. 3500 */ 3501 fib6_info_hold(res.f6i); 3502 rcu_read_unlock(); 3503 3504 res.nh = &res.f6i->fib6_nh; |
3505 res.fib6_flags = res.f6i->fib6_flags; 3506 res.fib6_type = res.f6i->fib6_type; |
|
3494 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL); 3495 if (!nrt) 3496 goto out; 3497 3498 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE; 3499 if (on_link) 3500 nrt->rt6i_flags &= ~RTF_GATEWAY; 3501 --- 2053 unchanged lines hidden --- | 3507 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL); 3508 if (!nrt) 3509 goto out; 3510 3511 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE; 3512 if (on_link) 3513 nrt->rt6i_flags &= ~RTF_GATEWAY; 3514 --- 2053 unchanged lines hidden --- |