From: David Ahern <dsah...@gmail.com>

Consolidate the fib_nh initialization which is duplicated between
fib_create_info for single path and fib_get_nhs for multipath.

Move the fib_nh cleanup code from free_fib_info_rcu into a new helper,
fib_nh_release. Move classid accounting into fib_nh_release which is
called per fib_nh to make accounting symmetrical with fib_nh_init.

Export both new helpers to allow for use with nexthop objects.

Signed-off-by: David Ahern <dsah...@gmail.com>
---
 include/net/ip_fib.h     |   5 ++
 net/ipv4/fib_semantics.c | 185 +++++++++++++++++++++++++----------------------
 2 files changed, 104 insertions(+), 86 deletions(-)

diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 19012f3ed501..ce9b92485064 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -400,6 +400,11 @@ int fib_sync_up(struct net_device *dev, unsigned int 
nh_flags);
 int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
                       const struct sk_buff *skb, struct flow_keys *flkeys);
 #endif
+
+int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
+               struct fib_config *cfg, int nh_weight,
+               struct netlink_ext_ack *extack);
+void fib_nh_release(struct net *net, struct fib_nh *fib_nh);
 int fib_check_nh(struct net *net, struct fib_nh *nh, u32 table, u8 scope,
                 struct netlink_ext_ack *extack);
 bool fib_good_nh(const struct fib_nh *nh);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 9b2d8ba6bdb3..0d792666821a 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -204,6 +204,21 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * 
__percpu *rtp)
        free_percpu(rtp);
 }
 
+void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
+{
+#ifdef CONFIG_IP_ROUTE_CLASSID
+       if (fib_nh->nh_tclassid)
+               net->ipv4.fib_num_tclassid_users--;
+#endif
+       if (fib_nh->nh_dev)
+               dev_put(fib_nh->nh_dev);
+
+       lwtstate_put(fib_nh->nh_lwtstate);
+       free_nh_exceptions(fib_nh);
+       rt_fibinfo_free_cpus(fib_nh->nh_pcpu_rth_output);
+       rt_fibinfo_free(&fib_nh->nh_rth_input);
+}
+
 /* Release a nexthop info record */
 static void free_fib_info_rcu(struct rcu_head *head)
 {
@@ -211,12 +226,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
        struct dst_metrics *m;
 
        change_nexthops(fi) {
-               if (nexthop_nh->nh_dev)
-                       dev_put(nexthop_nh->nh_dev);
-               lwtstate_put(nexthop_nh->nh_lwtstate);
-               free_nh_exceptions(nexthop_nh);
-               rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output);
-               rt_fibinfo_free(&nexthop_nh->nh_rth_input);
+               fib_nh_release(fi->fib_net, nexthop_nh);
        } endfor_nexthops(fi);
 
        m = fi->fib_metrics;
@@ -459,6 +469,52 @@ static int fib_detect_death(struct fib_info *fi, int order,
        return 1;
 }
 
+int fib_nh_init(struct net *net, struct fib_nh *nh,
+               struct fib_config *cfg, int nh_weight,
+               struct netlink_ext_ack *extack)
+{
+       int err = -ENOMEM;
+
+       nh->nh_pcpu_rth_output = alloc_percpu(struct rtable __rcu *);
+       if (!nh->nh_pcpu_rth_output)
+               goto failure;
+
+       if (cfg->fc_encap) {
+               struct lwtunnel_state *lwtstate;
+
+               err = -EINVAL;
+               if (cfg->fc_encap_type == LWTUNNEL_ENCAP_NONE) {
+                       NL_SET_ERR_MSG(extack, "LWT encap type not specified");
+                       goto failure;
+               }
+               err = lwtunnel_build_state(cfg->fc_encap_type,
+                                          cfg->fc_encap, AF_INET, cfg,
+                                          &lwtstate, extack);
+               if (err)
+                       goto failure;
+
+               nh->nh_lwtstate = lwtstate_get(lwtstate);
+       }
+
+       nh->nh_oif   = cfg->fc_oif;
+       nh->nh_gw    = cfg->fc_gw;
+       nh->nh_flags = cfg->fc_flags;
+
+#ifdef CONFIG_IP_ROUTE_CLASSID
+       nh->nh_tclassid = cfg->fc_flow;
+       if (nh->nh_tclassid)
+               net->ipv4.fib_num_tclassid_users++;
+#endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+       nh->nh_weight = nh_weight;
+#endif
+
+       err = 0;
+
+failure:
+       return err;
+}
+
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 
 static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining,
@@ -485,11 +541,15 @@ static int fib_get_nhs(struct fib_info *fi, struct 
rtnexthop *rtnh,
                       int remaining, struct fib_config *cfg,
                       struct netlink_ext_ack *extack)
 {
+       struct net *net = fi->fib_net;
+       struct fib_config fib_cfg;
        int ret;
 
        change_nexthops(fi) {
                int attrlen;
 
+               memset(&fib_cfg, 0, sizeof(fib_cfg));
+
                if (!rtnh_ok(rtnh, remaining)) {
                        NL_SET_ERR_MSG(extack,
                                       "Invalid nexthop configuration - extra 
data after nexthop");
@@ -502,51 +562,52 @@ static int fib_get_nhs(struct fib_info *fi, struct 
rtnexthop *rtnh,
                        return -EINVAL;
                }
 
-               nexthop_nh->nh_flags =
-                       (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
-               nexthop_nh->nh_oif = rtnh->rtnh_ifindex;
-               nexthop_nh->nh_weight = rtnh->rtnh_hops + 1;
+               fib_cfg.fc_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
+               fib_cfg.fc_oif = rtnh->rtnh_ifindex;
 
                attrlen = rtnh_attrlen(rtnh);
                if (attrlen > 0) {
                        struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
 
                        nla = nla_find(attrs, attrlen, RTA_GATEWAY);
-                       nexthop_nh->nh_gw = nla ? nla_get_in_addr(nla) : 0;
+                       if (nla)
+                               fib_cfg.fc_gw = nla_get_in_addr(nla);
 #ifdef CONFIG_IP_ROUTE_CLASSID
                        nla = nla_find(attrs, attrlen, RTA_FLOW);
-                       nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
-                       if (nexthop_nh->nh_tclassid)
-                               fi->fib_net->ipv4.fib_num_tclassid_users++;
+                       if (nla)
+                               fib_cfg.fc_flow = nla_get_u32(nla);
 #endif
-                       nla = nla_find(attrs, attrlen, RTA_ENCAP);
-                       if (nla) {
-                               struct lwtunnel_state *lwtstate;
-                               struct nlattr *nla_entype;
-
-                               nla_entype = nla_find(attrs, attrlen,
-                                                     RTA_ENCAP_TYPE);
-                               if (!nla_entype) {
-                                       NL_SET_BAD_ATTR(extack, nla);
-                                       NL_SET_ERR_MSG(extack,
-                                                      "Encap type is missing");
-                                       goto err_inval;
-                               }
-
-                               ret = lwtunnel_build_state(nla_get_u16(
-                                                          nla_entype),
-                                                          nla,  AF_INET, cfg,
-                                                          &lwtstate, extack);
-                               if (ret)
-                                       goto errout;
-                               nexthop_nh->nh_lwtstate =
-                                       lwtstate_get(lwtstate);
-                       }
+                       fib_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
+                       nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
+                       if (nla)
+                               fib_cfg.fc_encap_type = nla_get_u16(nla);
                }
 
+               ret = fib_nh_init(net, nexthop_nh, &fib_cfg,
+                                 rtnh->rtnh_hops + 1, extack);
+               if (ret)
+                       goto errout;
+
                rtnh = rtnh_next(rtnh, &remaining);
        } endfor_nexthops(fi);
 
+       if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif) {
+               NL_SET_ERR_MSG(extack,
+                              "Nexthop device index does not match RTA_OIF");
+               goto err_inval;
+       }
+       if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw) {
+               NL_SET_ERR_MSG(extack,
+                              "Nexthop gateway does not match RTA_GATEWAY");
+               goto err_inval;
+       }
+#ifdef CONFIG_IP_ROUTE_CLASSID
+       if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) {
+               NL_SET_ERR_MSG(extack,
+                              "Nexthop class id does not match RTA_FLOW");
+               goto err_inval;
+       }
+#endif
        return 0;
 
 err_inval:
@@ -1111,9 +1172,6 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
        fi->fib_nhs = nhs;
        change_nexthops(fi) {
                nexthop_nh->nh_parent = fi;
-               nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable 
__rcu *);
-               if (!nexthop_nh->nh_pcpu_rth_output)
-                       goto failure;
        } endfor_nexthops(fi)
 
        err = fib_convert_metrics(fi, cfg);
@@ -1124,53 +1182,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
                err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, extack);
                if (err != 0)
                        goto failure;
-               if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif) {
-                       NL_SET_ERR_MSG(extack,
-                                      "Nexthop device index does not match 
RTA_OIF");
-                       goto err_inval;
-               }
-               if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw) {
-                       NL_SET_ERR_MSG(extack,
-                                      "Nexthop gateway does not match 
RTA_GATEWAY");
-                       goto err_inval;
-               }
-#ifdef CONFIG_IP_ROUTE_CLASSID
-               if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) {
-                       NL_SET_ERR_MSG(extack,
-                                      "Nexthop class id does not match 
RTA_FLOW");
-                       goto err_inval;
-               }
-#endif
        } else {
-               struct fib_nh *nh = fi->fib_nh;
-
-               if (cfg->fc_encap) {
-                       struct lwtunnel_state *lwtstate;
-
-                       if (cfg->fc_encap_type == LWTUNNEL_ENCAP_NONE) {
-                               NL_SET_ERR_MSG(extack,
-                                              "LWT encap type not specified");
-                               goto err_inval;
-                       }
-                       err = lwtunnel_build_state(cfg->fc_encap_type,
-                                                  cfg->fc_encap, AF_INET, cfg,
-                                                  &lwtstate, extack);
-                       if (err)
-                               goto failure;
-
-                       nh->nh_lwtstate = lwtstate_get(lwtstate);
-               }
-               nh->nh_oif = cfg->fc_oif;
-               nh->nh_gw = cfg->fc_gw;
-               nh->nh_flags = cfg->fc_flags;
-#ifdef CONFIG_IP_ROUTE_CLASSID
-               nh->nh_tclassid = cfg->fc_flow;
-               if (nh->nh_tclassid)
-                       fi->fib_net->ipv4.fib_num_tclassid_users++;
-#endif
-#ifdef CONFIG_IP_ROUTE_MULTIPATH
-               nh->nh_weight = 1;
-#endif
+               err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack);
        }
 
        if (fib_props[cfg->fc_type].error) {
-- 
2.11.0

Reply via email to