Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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,
		     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 */
void fib_trie_init(void);
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
+91 −89
Original line number Diff line number Diff line
@@ -457,6 +457,54 @@ 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 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

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,
		       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");
@@ -500,56 +552,54 @@ 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;
#ifdef CONFIG_IP_ROUTE_CLASSID
			if (nla)
				fib_cfg.fc_gw = nla_get_in_addr(nla);

			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++;
#endif
			nla = nla_find(attrs, attrlen, RTA_ENCAP);
			if (nla) {
				struct lwtunnel_state *lwtstate;
				struct nlattr *nla_entype;
			if (nla)
				fib_cfg.fc_flow = nla_get_u32(nla);

				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;
			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 = lwtunnel_build_state(nla_get_u16(
							   nla_entype),
							   nla,  AF_INET, cfg,
							   &lwtstate, extack);
		ret = fib_nh_init(net, nexthop_nh, &fib_cfg,
				  rtnh->rtnh_hops + 1, extack);
		if (ret)
			goto errout;
				nexthop_nh->nh_lwtstate =
					lwtstate_get(lwtstate);
			}
		}

		rtnh = rtnh_next(rtnh, &remaining);
	} endfor_nexthops(fi);

	return 0;

err_inval:
	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:
	return ret;
}
@@ -1098,64 +1148,16 @@ 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)

	if (cfg->fc_mp) {
	if (cfg->fc_mp)
		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;
	else
		err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack);

			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)
	if (err != 0)
		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 (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) {
			NL_SET_ERR_MSG(extack,