]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv6/route.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / ipv6 / route.c
index 6f32944e0223fc3e83019ae9ff4fc5cade2cefef..49817555449e2956fcfe81555e646b5f9b53261a 100644 (file)
@@ -1042,8 +1042,8 @@ static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
        return pcpu_rt;
 }
 
-static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
-                                     struct flowi6 *fl6, int flags)
+struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
+                              int oif, struct flowi6 *fl6, int flags)
 {
        struct fib6_node *fn, *saved_fn;
        struct rt6_info *rt;
@@ -1139,6 +1139,7 @@ redo_rt6_select:
 
        }
 }
+EXPORT_SYMBOL_GPL(ip6_pol_route);
 
 static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
                                            struct flowi6 *fl6, int flags)
@@ -1190,7 +1191,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
        struct dst_entry *dst;
        bool any_src;
 
-       dst = l3mdev_rt6_dst_by_oif(net, fl6);
+       dst = l3mdev_get_rt6_dst(net, fl6);
        if (dst)
                return dst;
 
@@ -1771,6 +1772,37 @@ static int ip6_convert_metrics(struct mx6_config *mxc,
        return -EINVAL;
 }
 
+static struct rt6_info *ip6_nh_lookup_table(struct net *net,
+                                           struct fib6_config *cfg,
+                                           const struct in6_addr *gw_addr)
+{
+       struct flowi6 fl6 = {
+               .flowi6_oif = cfg->fc_ifindex,
+               .daddr = *gw_addr,
+               .saddr = cfg->fc_prefsrc,
+       };
+       struct fib6_table *table;
+       struct rt6_info *rt;
+       int flags = RT6_LOOKUP_F_IFACE;
+
+       table = fib6_get_table(net, cfg->fc_table);
+       if (!table)
+               return NULL;
+
+       if (!ipv6_addr_any(&cfg->fc_prefsrc))
+               flags |= RT6_LOOKUP_F_HAS_SADDR;
+
+       rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
+
+       /* if table lookup failed, fall back to full lookup */
+       if (rt == net->ipv6.ip6_null_entry) {
+               ip6_rt_put(rt);
+               rt = NULL;
+       }
+
+       return rt;
+}
+
 static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
 {
        struct net *net = cfg->fc_nlinfo.nl_net;
@@ -1942,7 +1974,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
                rt->rt6i_gateway = *gw_addr;
 
                if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
-                       struct rt6_info *grt;
+                       struct rt6_info *grt = NULL;
 
                        /* IPv6 strictly inhibits using not link-local
                           addresses as nexthop address.
@@ -1954,7 +1986,12 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
                        if (!(gwa_type & IPV6_ADDR_UNICAST))
                                goto out;
 
-                       grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
+                       if (cfg->fc_table)
+                               grt = ip6_nh_lookup_table(net, cfg, gw_addr);
+
+                       if (!grt)
+                               grt = rt6_lookup(net, gw_addr, NULL,
+                                                cfg->fc_ifindex, 1);
 
                        err = -EHOSTUNREACH;
                        if (!grt)
@@ -2164,7 +2201,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
         *      first-hop router for the specified ICMP Destination Address.
         */
 
-       if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
+       if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
                net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
                return;
        }
@@ -2199,12 +2236,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
         *      We have finally decided to accept it.
         */
 
-       neigh_update(neigh, lladdr, NUD_STALE,
+       ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
                     NEIGH_UPDATE_F_WEAK_OVERRIDE|
                     NEIGH_UPDATE_F_OVERRIDE|
                     (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
-                                    NEIGH_UPDATE_F_ISROUTER))
-                    );
+                                    NEIGH_UPDATE_F_ISROUTER)),
+                    NDISC_REDIRECT, &ndopts);
 
        nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
        if (!nrt)
@@ -2549,23 +2586,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        return rt;
 }
 
-int ip6_route_get_saddr(struct net *net,
-                       struct rt6_info *rt,
-                       const struct in6_addr *daddr,
-                       unsigned int prefs,
-                       struct in6_addr *saddr)
-{
-       struct inet6_dev *idev =
-               rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
-       int err = 0;
-       if (rt && rt->rt6i_prefsrc.plen)
-               *saddr = rt->rt6i_prefsrc.addr;
-       else
-               err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
-                                        daddr, prefs, saddr);
-       return err;
-}
-
 /* remove deleted ip from prefsrc entries */
 struct arg_dev_net_ip {
        struct net_device *dev;
@@ -3270,6 +3290,8 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 
        err = -EINVAL;
        memset(&fl6, 0, sizeof(fl6));
+       rtm = nlmsg_data(nlh);
+       fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
 
        if (tb[RTA_SRC]) {
                if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))