]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blobdiff - net/ipv4/route.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[mirror_ubuntu-eoan-kernel.git] / net / ipv4 / route.c
index 299e247b20326df8426ebf2bb3b6d91f1176527b..4ac5728689f57245f5f74a838be303cf2177ae00 100644 (file)
@@ -418,6 +418,7 @@ static void __net_exit ip_rt_do_proc_exit(struct net *net)
 static struct pernet_operations ip_rt_proc_ops __net_initdata =  {
        .init = ip_rt_do_proc_init,
        .exit = ip_rt_do_proc_exit,
+       .async = true,
 };
 
 static int __init ip_rt_proc_init(void)
@@ -1532,7 +1533,6 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
                rt->rt_mtu_locked = 0;
                rt->rt_gateway = 0;
                rt->rt_uses_gateway = 0;
-               rt->rt_table_id = 0;
                INIT_LIST_HEAD(&rt->rt_uncached);
 
                rt->dst.output = ip_output;
@@ -1668,19 +1668,6 @@ static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr)
        spin_unlock_bh(&fnhe_lock);
 }
 
-static void set_lwt_redirect(struct rtable *rth)
-{
-       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
-               rth->dst.lwtstate->orig_output = rth->dst.output;
-               rth->dst.output = lwtunnel_output;
-       }
-
-       if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
-               rth->dst.lwtstate->orig_input = rth->dst.input;
-               rth->dst.input = lwtunnel_input;
-       }
-}
-
 /* called in rcu_read_lock() section */
 static int __mkroute_input(struct sk_buff *skb,
                           const struct fib_result *res,
@@ -1763,15 +1750,13 @@ rt_cache:
        }
 
        rth->rt_is_input = 1;
-       if (res->table)
-               rth->rt_table_id = res->table->tb_id;
        RT_CACHE_STAT_INC(in_slow_tot);
 
        rth->dst.input = ip_forward;
 
        rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag,
                       do_cache);
-       set_lwt_redirect(rth);
+       lwtunnel_set_redirect(&rth->dst);
        skb_dst_set(skb, &rth->dst);
 out:
        err = 0;
@@ -1787,44 +1772,45 @@ static void ip_multipath_l3_keys(const struct sk_buff *skb,
                                 struct flow_keys *hash_keys)
 {
        const struct iphdr *outer_iph = ip_hdr(skb);
+       const struct iphdr *key_iph = outer_iph;
        const struct iphdr *inner_iph;
        const struct icmphdr *icmph;
        struct iphdr _inner_iph;
        struct icmphdr _icmph;
 
-       hash_keys->addrs.v4addrs.src = outer_iph->saddr;
-       hash_keys->addrs.v4addrs.dst = outer_iph->daddr;
        if (likely(outer_iph->protocol != IPPROTO_ICMP))
-               return;
+               goto out;
 
        if (unlikely((outer_iph->frag_off & htons(IP_OFFSET)) != 0))
-               return;
+               goto out;
 
        icmph = skb_header_pointer(skb, outer_iph->ihl * 4, sizeof(_icmph),
                                   &_icmph);
        if (!icmph)
-               return;
+               goto out;
 
        if (icmph->type != ICMP_DEST_UNREACH &&
            icmph->type != ICMP_REDIRECT &&
            icmph->type != ICMP_TIME_EXCEEDED &&
            icmph->type != ICMP_PARAMETERPROB)
-               return;
+               goto out;
 
        inner_iph = skb_header_pointer(skb,
                                       outer_iph->ihl * 4 + sizeof(_icmph),
                                       sizeof(_inner_iph), &_inner_iph);
        if (!inner_iph)
-               return;
-       hash_keys->addrs.v4addrs.src = inner_iph->saddr;
-       hash_keys->addrs.v4addrs.dst = inner_iph->daddr;
+               goto out;
+
+       key_iph = inner_iph;
+out:
+       hash_keys->addrs.v4addrs.src = key_iph->saddr;
+       hash_keys->addrs.v4addrs.dst = key_iph->daddr;
 }
 
 /* if skb is set it will be used and fl4 can be NULL */
-int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
-                      const struct sk_buff *skb)
+int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
+                      const struct sk_buff *skb, struct flow_keys *flkeys)
 {
-       struct net *net = fi->fib_net;
        struct flow_keys hash_keys;
        u32 mhash;
 
@@ -1848,15 +1834,20 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
                        /* short-circuit if we already have L4 hash present */
                        if (skb->l4_hash)
                                return skb_get_hash_raw(skb) >> 1;
+
                        memset(&hash_keys, 0, sizeof(hash_keys));
-                       skb_flow_dissect_flow_keys(skb, &keys, flag);
+
+                       if (!flkeys) {
+                               skb_flow_dissect_flow_keys(skb, &keys, flag);
+                               flkeys = &keys;
+                       }
 
                        hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
-                       hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
-                       hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
-                       hash_keys.ports.src = keys.ports.src;
-                       hash_keys.ports.dst = keys.ports.dst;
-                       hash_keys.basic.ip_proto = keys.basic.ip_proto;
+                       hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src;
+                       hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst;
+                       hash_keys.ports.src = flkeys->ports.src;
+                       hash_keys.ports.dst = flkeys->ports.dst;
+                       hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
                } else {
                        memset(&hash_keys, 0, sizeof(hash_keys));
                        hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
@@ -1872,17 +1863,17 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
 
        return mhash >> 1;
 }
-EXPORT_SYMBOL_GPL(fib_multipath_hash);
 #endif /* CONFIG_IP_ROUTE_MULTIPATH */
 
 static int ip_mkroute_input(struct sk_buff *skb,
                            struct fib_result *res,
                            struct in_device *in_dev,
-                           __be32 daddr, __be32 saddr, u32 tos)
+                           __be32 daddr, __be32 saddr, u32 tos,
+                           struct flow_keys *hkeys)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        if (res->fi && res->fi->fib_nhs > 1) {
-               int h = fib_multipath_hash(res->fi, NULL, skb);
+               int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys);
 
                fib_select_multipath(res, h);
        }
@@ -1908,13 +1899,14 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                               struct fib_result *res)
 {
        struct in_device *in_dev = __in_dev_get_rcu(dev);
+       struct flow_keys *flkeys = NULL, _flkeys;
+       struct net    *net = dev_net(dev);
        struct ip_tunnel_info *tun_info;
-       struct flowi4   fl4;
+       int             err = -EINVAL;
        unsigned int    flags = 0;
        u32             itag = 0;
        struct rtable   *rth;
-       int             err = -EINVAL;
-       struct net    *net = dev_net(dev);
+       struct flowi4   fl4;
        bool do_cache;
 
        /* IP on this device is disabled. */
@@ -1973,6 +1965,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        fl4.daddr = daddr;
        fl4.saddr = saddr;
        fl4.flowi4_uid = sock_net_uid(net, NULL);
+
+       if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys))
+               flkeys = &_flkeys;
+
        err = fib_lookup(net, &fl4, res, 0);
        if (err != 0) {
                if (!IN_DEV_FORWARD(in_dev))
@@ -1998,7 +1994,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        if (res->type != RTN_UNICAST)
                goto martian_destination;
 
-       err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos);
+       err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
 out:   return err;
 
 brd_input:
@@ -2040,8 +2036,6 @@ local_input:
        rth->dst.tclassid = itag;
 #endif
        rth->rt_is_input = 1;
-       if (res->table)
-               rth->rt_table_id = res->table->tb_id;
 
        RT_CACHE_STAT_INC(in_slow_tot);
        if (res->type == RTN_UNREACHABLE) {
@@ -2270,8 +2264,6 @@ add:
                return ERR_PTR(-ENOBUFS);
 
        rth->rt_iif = orig_oif;
-       if (res->table)
-               rth->rt_table_id = res->table->tb_id;
 
        RT_CACHE_STAT_INC(out_slow_tot);
 
@@ -2293,7 +2285,7 @@ add:
        }
 
        rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0, do_cache);
-       set_lwt_redirect(rth);
+       lwtunnel_set_redirect(&rth->dst);
 
        return rth;
 }
@@ -2804,7 +2796,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
                rt->rt_flags |= RTCF_NOTIFY;
 
        if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE)
-               table_id = rt->rt_table_id;
+               table_id = res.table ? res.table->tb_id : 0;
 
        if (rtm->rtm_flags & RTM_F_FIB_MATCH) {
                if (!res.fi) {
@@ -3025,6 +3017,7 @@ static __net_exit void sysctl_route_net_exit(struct net *net)
 static __net_initdata struct pernet_operations sysctl_route_ops = {
        .init = sysctl_route_net_init,
        .exit = sysctl_route_net_exit,
+       .async = true,
 };
 #endif
 
@@ -3038,6 +3031,7 @@ static __net_init int rt_genid_init(struct net *net)
 
 static __net_initdata struct pernet_operations rt_genid_ops = {
        .init = rt_genid_init,
+       .async = true,
 };
 
 static int __net_init ipv4_inetpeer_init(struct net *net)
@@ -3063,6 +3057,7 @@ static void __net_exit ipv4_inetpeer_exit(struct net *net)
 static __net_initdata struct pernet_operations ipv4_inetpeer_ops = {
        .init   =       ipv4_inetpeer_init,
        .exit   =       ipv4_inetpeer_exit,
+       .async  =       true,
 };
 
 #ifdef CONFIG_IP_ROUTE_CLASSID