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 ---