net: fib: move metrics parsing to a helper
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / fib_frontend.c
index b11321a8e58d8b63004ba761a1e91fb06dfea66f..4036c94dfbe1466cc7945ce7de580c465f930906 100644 (file)
@@ -46,6 +46,7 @@
 #include <net/rtnetlink.h>
 #include <net/xfrm.h>
 #include <net/vrf.h>
+#include <trace/events/fib.h>
 
 #ifndef CONFIG_IP_MULTIPLE_TABLES
 
@@ -260,6 +261,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
 }
 EXPORT_SYMBOL(inet_dev_addr_type);
 
+/* inet_addr_type with dev == NULL but using the table from a dev
+ * if one is associated
+ */
+unsigned int inet_addr_type_dev_table(struct net *net,
+                                     const struct net_device *dev,
+                                     __be32 addr)
+{
+       int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;
+
+       return __inet_dev_addr_type(net, NULL, addr, rt_table);
+}
+EXPORT_SYMBOL(inet_addr_type_dev_table);
+
 __be32 fib_compute_spec_dst(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
@@ -331,6 +345,8 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
 
        fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
 
+       trace_fib_validate_source(dev, &fl4);
+
        net = dev_net(dev);
        if (fib_lookup(net, &fl4, &res, 0))
                goto last_resort;
@@ -510,9 +526,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
 
        addr = sk_extract_addr(&rt->rt_gateway);
        if (rt->rt_gateway.sa_family == AF_INET && addr) {
+               unsigned int addr_type;
+
                cfg->fc_gw = addr;
+               addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
                if (rt->rt_flags & RTF_GATEWAY &&
-                   inet_addr_type(net, addr) == RTN_UNICAST)
+                   addr_type == RTN_UNICAST)
                        cfg->fc_scope = RT_SCOPE_UNIVERSE;
        }
 
@@ -784,6 +803,7 @@ out:
 static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
 {
        struct net *net = dev_net(ifa->ifa_dev->dev);
+       int tb_id = vrf_dev_table_rtnl(ifa->ifa_dev->dev);
        struct fib_table *tb;
        struct fib_config cfg = {
                .fc_protocol = RTPROT_KERNEL,
@@ -798,11 +818,10 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
                },
        };
 
-       if (type == RTN_UNICAST)
-               tb = fib_new_table(net, RT_TABLE_MAIN);
-       else
-               tb = fib_new_table(net, RT_TABLE_LOCAL);
+       if (!tb_id)
+               tb_id = (type == RTN_UNICAST) ? RT_TABLE_MAIN : RT_TABLE_LOCAL;
 
+       tb = fib_new_table(net, tb_id);
        if (!tb)
                return;
 
@@ -984,11 +1003,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
                        fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
        }
        if (!(ok & LOCAL_OK)) {
+               unsigned int addr_type;
+
                fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
 
                /* Check, that this local address finally disappeared. */
-               if (gone &&
-                   inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
+               addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
+                                                    ifa->ifa_local);
+               if (gone && addr_type != RTN_LOCAL) {
                        /* And the last, but not the least thing.
                         * We must flush stray FIB entries.
                         *