Commit e4516ef6 authored by David Ahern's avatar David Ahern Committed by David S. Miller

ipv4: Create init helper for fib_nh

Consolidate the fib_nh initialization which is duplicated between
fib_create_info for single path and fib_get_nhs for multipath.
Export the helper to allow for use with nexthop objects in the
future.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 331c7a40
...@@ -416,6 +416,10 @@ void fib_select_multipath(struct fib_result *res, int hash); ...@@ -416,6 +416,10 @@ void fib_select_multipath(struct fib_result *res, int hash);
void fib_select_path(struct net *net, struct fib_result *res, void fib_select_path(struct net *net, struct fib_result *res,
struct flowi4 *fl4, const struct sk_buff *skb); struct flowi4 *fl4, const struct sk_buff *skb);
int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
struct fib_config *cfg, int nh_weight,
struct netlink_ext_ack *extack);
/* Exported by fib_trie.c */ /* Exported by fib_trie.c */
void fib_trie_init(void); void fib_trie_init(void);
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias); struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
......
...@@ -457,6 +457,54 @@ static int fib_detect_death(struct fib_info *fi, int order, ...@@ -457,6 +457,54 @@ static int fib_detect_death(struct fib_info *fi, int order,
return 1; 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 err_out;
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 lwt_failure;
}
err = lwtunnel_build_state(cfg->fc_encap_type,
cfg->fc_encap, AF_INET, cfg,
&lwtstate, extack);
if (err)
goto lwt_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
return 0;
lwt_failure:
rt_fibinfo_free_cpus(nh->nh_pcpu_rth_output);
nh->nh_pcpu_rth_output = NULL;
err_out:
return err;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining, static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining,
...@@ -483,11 +531,15 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, ...@@ -483,11 +531,15 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
int remaining, struct fib_config *cfg, int remaining, struct fib_config *cfg,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct net *net = fi->fib_net;
struct fib_config fib_cfg;
int ret; int ret;
change_nexthops(fi) { change_nexthops(fi) {
int attrlen; int attrlen;
memset(&fib_cfg, 0, sizeof(fib_cfg));
if (!rtnh_ok(rtnh, remaining)) { if (!rtnh_ok(rtnh, remaining)) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack,
"Invalid nexthop configuration - extra data after nexthop"); "Invalid nexthop configuration - extra data after nexthop");
...@@ -500,56 +552,54 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, ...@@ -500,56 +552,54 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
return -EINVAL; return -EINVAL;
} }
nexthop_nh->nh_flags = fib_cfg.fc_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
(cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; fib_cfg.fc_oif = rtnh->rtnh_ifindex;
nexthop_nh->nh_oif = rtnh->rtnh_ifindex;
nexthop_nh->nh_weight = rtnh->rtnh_hops + 1;
attrlen = rtnh_attrlen(rtnh); attrlen = rtnh_attrlen(rtnh);
if (attrlen > 0) { if (attrlen > 0) {
struct nlattr *nla, *attrs = rtnh_attrs(rtnh); struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
nla = nla_find(attrs, attrlen, RTA_GATEWAY); nla = nla_find(attrs, attrlen, RTA_GATEWAY);
nexthop_nh->nh_gw = nla ? nla_get_in_addr(nla) : 0; if (nla)
#ifdef CONFIG_IP_ROUTE_CLASSID fib_cfg.fc_gw = nla_get_in_addr(nla);
nla = nla_find(attrs, attrlen, RTA_FLOW); nla = nla_find(attrs, attrlen, RTA_FLOW);
nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; if (nla)
if (nexthop_nh->nh_tclassid) fib_cfg.fc_flow = nla_get_u32(nla);
fi->fib_net->ipv4.fib_num_tclassid_users++;
#endif
nla = nla_find(attrs, attrlen, RTA_ENCAP);
if (nla) {
struct lwtunnel_state *lwtstate;
struct nlattr *nla_entype;
nla_entype = nla_find(attrs, attrlen, fib_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
RTA_ENCAP_TYPE); nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
if (!nla_entype) { if (nla)
NL_SET_BAD_ATTR(extack, nla); fib_cfg.fc_encap_type = nla_get_u16(nla);
NL_SET_ERR_MSG(extack,
"Encap type is missing");
goto err_inval;
} }
ret = lwtunnel_build_state(nla_get_u16( ret = fib_nh_init(net, nexthop_nh, &fib_cfg,
nla_entype), rtnh->rtnh_hops + 1, extack);
nla, AF_INET, cfg,
&lwtstate, extack);
if (ret) if (ret)
goto errout; goto errout;
nexthop_nh->nh_lwtstate =
lwtstate_get(lwtstate);
}
}
rtnh = rtnh_next(rtnh, &remaining); rtnh = rtnh_next(rtnh, &remaining);
} endfor_nexthops(fi); } endfor_nexthops(fi);
return 0;
err_inval:
ret = -EINVAL; ret = -EINVAL;
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 errout;
}
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 errout;
}
#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 errout;
}
#endif
ret = 0;
errout: errout:
return ret; return ret;
} }
...@@ -1098,64 +1148,16 @@ struct fib_info *fib_create_info(struct fib_config *cfg, ...@@ -1098,64 +1148,16 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
fi->fib_nhs = nhs; fi->fib_nhs = nhs;
change_nexthops(fi) { change_nexthops(fi) {
nexthop_nh->nh_parent = 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) } endfor_nexthops(fi)
if (cfg->fc_mp) { if (cfg->fc_mp)
err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, extack); err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, extack);
if (err != 0) else
goto failure; err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack);
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) { if (err != 0)
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; 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
}
if (fib_props[cfg->fc_type].error) { if (fib_props[cfg->fc_type].error) {
if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment