ipv4: Prepare for fib6_nh from a nexthop object
authorDavid Ahern <dsahern@gmail.com>
Tue, 4 Jun 2019 03:19:50 +0000 (20:19 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Jun 2019 02:26:49 +0000 (19:26 -0700)
Convert more IPv4 code to use fib_nh_common over fib_nh to enable routes
to use a fib6_nh based nexthop. In the end, only code not using a
nexthop object in a fib_info should directly access fib_nh in a fib_info
without checking the famiy and going through fib_nh_common. Those
functions will be marked when it is not directly evident.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip_fib.h
net/ipv4/fib_frontend.c
net/ipv4/fib_rules.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/nexthop.c
net/ipv4/route.c

index 42b1a80..7da8ea7 100644 (file)
@@ -195,8 +195,8 @@ struct fib_result_nl {
 #define FIB_TABLE_HASHSZ 2
 #endif
 
-__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
-                               unsigned char scope);
+__be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
+                                unsigned char scope);
 __be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
 
 #define FIB_RES_NHC(res)               ((res).nhc)
@@ -455,11 +455,18 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
 {
 #ifdef CONFIG_IP_ROUTE_CLASSID
        struct fib_nh_common *nhc = res->nhc;
-       struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        u32 rtag;
 #endif
-       *itag = nh->nh_tclassid << 16;
+       if (nhc->nhc_family == AF_INET) {
+               struct fib_nh *nh;
+
+               nh = container_of(nhc, struct fib_nh, nh_common);
+               *itag = nh->nh_tclassid << 16;
+       } else {
+               *itag = 0;
+       }
+
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        rtag = res->tclassid;
        if (*itag == 0)
index a469136..5ea2750 100644 (file)
@@ -235,9 +235,9 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
        if (table) {
                ret = RTN_UNICAST;
                if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
-                       struct fib_nh *nh = fib_info_nh(res.fi, 0);
+                       struct fib_nh_common *nhc = fib_info_nhc(res.fi, 0);
 
-                       if (!dev || dev == nh->fib_nh_dev)
+                       if (!dev || dev == nhc->nhc_dev)
                                ret = res.type;
                }
        }
@@ -325,18 +325,18 @@ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev)
        int ret;
 
        for (ret = 0; ret < fib_info_num_path(fi); ret++) {
-               const struct fib_nh *nh = fib_info_nh(fi, ret);
+               const struct fib_nh_common *nhc = fib_info_nhc(fi, ret);
 
-               if (nh->fib_nh_dev == dev) {
+               if (nhc->nhc_dev == dev) {
                        dev_match = true;
                        break;
-               } else if (l3mdev_master_ifindex_rcu(nh->fib_nh_dev) == dev->ifindex) {
+               } else if (l3mdev_master_ifindex_rcu(nhc->nhc_dev) == dev->ifindex) {
                        dev_match = true;
                        break;
                }
        }
 #else
-       if (fib_info_nh(fi, 0)->fib_nh_dev == dev)
+       if (fib_info_nhc(fi, 0)->nhc_dev == dev)
                dev_match = true;
 #endif
 
index ab06fd7..88807c1 100644 (file)
@@ -147,9 +147,9 @@ static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg
        struct net_device *dev = NULL;
 
        if (result->fi) {
-               struct fib_nh *nh = fib_info_nh(result->fi, 0);
+               struct fib_nh_common *nhc = fib_info_nhc(result->fi, 0);
 
-               dev = nh->fib_nh_dev;
+               dev = nhc->nhc_dev;
        }
 
        /* do not accept result if the route does
index a37ff07..4a12c69 100644 (file)
@@ -61,6 +61,9 @@ static unsigned int fib_info_cnt;
 #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
 static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
 
+/* for_nexthops and change_nexthops only used when nexthop object
+ * is not set in a fib_info. The logic within can reference fib_nh.
+ */
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 
 #define for_nexthops(fi) {                                             \
@@ -402,20 +405,23 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
 
                /* each nexthop is packed in an attribute */
                size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
+               unsigned int i;
 
                /* may contain flow and gateway attribute */
                nhsize += 2 * nla_total_size(4);
 
                /* grab encap info */
-               for_nexthops(fi) {
-                       if (nh->fib_nh_lws) {
+               for (i = 0; i < fib_info_num_path(fi); i++) {
+                       struct fib_nh_common *nhc = fib_info_nhc(fi, i);
+
+                       if (nhc->nhc_lwtstate) {
                                /* RTA_ENCAP_TYPE */
                                nh_encapsize += lwtunnel_get_encap_size(
-                                               nh->fib_nh_lws);
+                                               nhc->nhc_lwtstate);
                                /* RTA_ENCAP */
                                nh_encapsize +=  nla_total_size(2);
                        }
-               } endfor_nexthops(fi);
+               }
 
                /* all nexthops are packed in a nested attribute */
                payload += nla_total_size((nhs * nhsize) + nh_encapsize);
@@ -1194,9 +1200,15 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
        fib_info_hash_free(old_laddrhash, bytes);
 }
 
-__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
-                               unsigned char scope)
+__be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
+                                unsigned char scope)
 {
+       struct fib_nh *nh;
+
+       if (nhc->nhc_family != AF_INET)
+               return inet_select_addr(nhc->nhc_dev, 0, scope);
+
+       nh = container_of(nhc, struct fib_nh, nh_common);
        nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
        nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
 
@@ -1206,16 +1218,19 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
 __be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
 {
        struct fib_nh_common *nhc = res->nhc;
-       struct fib_nh *nh;
 
        if (res->fi->fib_prefsrc)
                return res->fi->fib_prefsrc;
 
-       nh = container_of(nhc, struct fib_nh, nh_common);
-       if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
-               return nh->nh_saddr;
+       if (nhc->nhc_family == AF_INET) {
+               struct fib_nh *nh;
+
+               nh = container_of(nhc, struct fib_nh, nh_common);
+               if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
+                       return nh->nh_saddr;
+       }
 
-       return fib_info_update_nh_saddr(net, nh, res->fi->fib_scope);
+       return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope);
 }
 
 static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
@@ -1397,7 +1412,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
        }
 
        change_nexthops(fi) {
-               fib_info_update_nh_saddr(net, nexthop_nh, fi->fib_scope);
+               fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common,
+                                         fi->fib_scope);
                if (nexthop_nh->fib_nh_gw_family == AF_INET6)
                        fi->fib_nh_is_v6 = true;
        } endfor_nexthops(fi)
@@ -1625,17 +1641,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
            nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
                goto nla_put_failure;
        if (nhs == 1) {
-               const struct fib_nh *nh = fib_info_nh(fi, 0);
+               const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
                unsigned char flags = 0;
 
-               if (fib_nexthop_info(skb, &nh->nh_common, &flags, false) < 0)
+               if (fib_nexthop_info(skb, nhc, &flags, false) < 0)
                        goto nla_put_failure;
 
                rtm->rtm_flags = flags;
 #ifdef CONFIG_IP_ROUTE_CLASSID
-               if (nh->nh_tclassid &&
-                   nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
-                       goto nla_put_failure;
+               if (nhc->nhc_family == AF_INET) {
+                       struct fib_nh *nh;
+
+                       nh = container_of(nhc, struct fib_nh, nh_common);
+                       if (nh->nh_tclassid &&
+                           nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
+                               goto nla_put_failure;
+               }
 #endif
        } else {
                if (fib_add_multipath(skb, fi) < 0)
index 5c8a4d2..d704d16 100644 (file)
@@ -2724,9 +2724,9 @@ static unsigned int fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
        if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
                flags = RTF_REJECT;
        if (fi) {
-               const struct fib_nh *nh = fib_info_nh(fi, 0);
+               const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
 
-               if (nh->fib_nh_gw4)
+               if (nhc->nhc_gw.ipv4)
                        flags |= RTF_GATEWAY;
        }
        if (mask == htonl(0xFFFFFFFF))
@@ -2773,14 +2773,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
                seq_setwidth(seq, 127);
 
                if (fi) {
-                       struct fib_nh *nh = fib_info_nh(fi, 0);
+                       struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
+                       __be32 gw = 0;
+
+                       if (nhc->nhc_gw_family == AF_INET)
+                               gw = nhc->nhc_gw.ipv4;
 
                        seq_printf(seq,
                                   "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
                                   "%d\t%08X\t%d\t%u\t%u",
-                                  nh->fib_nh_dev ? nh->fib_nh_dev->name : "*",
-                                  prefix,
-                                  nh->fib_nh_gw4, flags, 0, 0,
+                                  nhc->nhc_dev ? nhc->nhc_dev->name : "*",
+                                  prefix, gw, flags, 0, 0,
                                   fi->fib_priority,
                                   mask,
                                   (fi->fib_advmss ?
index 7a5a3d0..aec4ecb 100644 (file)
@@ -815,7 +815,8 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
        err = fib_check_nh(net, fib_nh, tb_id, 0, extack);
        if (!err) {
                nh->nh_flags = fib_nh->fib_nh_flags;
-               fib_info_update_nh_saddr(net, fib_nh, fib_nh->fib_nh_scope);
+               fib_info_update_nhc_saddr(net, &fib_nh->nh_common,
+                                         fib_nh->fib_nh_scope);
        } else {
                fib_nh_release(net, fib_nh);
        }
index 05a6a8e..4a11684 100644 (file)
@@ -1585,7 +1585,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
                ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
-               {
+               if (nhc->nhc_family == AF_INET) {
                        struct fib_nh *nh;
 
                        nh = container_of(nhc, struct fib_nh, nh_common);