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

Commit 9b974499 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mpls-next'



Eric W. Biederman says:

====================
mpls: Minor fixes and cleanups

This is a bunch of small changes that have come out of the discussions
of the mpls code and the automated tests that people run against things.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 008a5b07 b79bda3d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -226,6 +226,7 @@ enum {
	NEIGH_ND_TABLE = 1,
	NEIGH_DN_TABLE = 2,
	NEIGH_NR_TABLES,
	NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */
};

static inline int neigh_parms_family(struct neigh_parms *p)
+11 −11
Original line number Diff line number Diff line
@@ -2391,22 +2391,15 @@ void __neigh_for_each_release(struct neigh_table *tbl,
}
EXPORT_SYMBOL(__neigh_for_each_release);

int neigh_xmit(int family, struct net_device *dev,
int neigh_xmit(int index, struct net_device *dev,
	       const void *addr, struct sk_buff *skb)
{
	int err;
	if (family == AF_PACKET) {
		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
				      addr, NULL, skb->len);
		if (err < 0)
			goto out_kfree_skb;
		err = dev_queue_xmit(skb);
	} else {
	int err = -EAFNOSUPPORT;
	if (likely(index < NEIGH_NR_TABLES)) {
		struct neigh_table *tbl;
		struct neighbour *neigh;

		err = -ENETDOWN;
		tbl = neigh_find_table(family);
		tbl = neigh_tables[index];
		if (!tbl)
			goto out;
		neigh = __neigh_lookup_noref(tbl, addr, dev);
@@ -2417,6 +2410,13 @@ int neigh_xmit(int family, struct net_device *dev,
			goto out_kfree_skb;
		err = neigh->output(neigh, skb);
	}
	else if (index == NEIGH_LINK_TABLE) {
		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
				      addr, NULL, skb->len);
		if (err < 0)
			goto out_kfree_skb;
		err = dev_queue_xmit(skb);
	}
out:
	return err;
out_kfree_skb:
+72 −42
Original line number Diff line number Diff line
@@ -24,13 +24,13 @@
#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long)))

struct mpls_route { /* next hop label forwarding entry */
	struct net_device 	*rt_dev;
	struct net_device __rcu *rt_dev;
	struct rcu_head		rt_rcu;
	u32			rt_label[MAX_NEW_LABELS];
	u8			rt_protocol; /* routing protocol that set this entry */
	u8			rt_labels:2,
				rt_via_alen:6;
	unsigned short		rt_via_family;
	u8			rt_labels;
	u8			rt_via_alen;
	u8			rt_via_table;
	u8			rt_via[0];
};

@@ -152,7 +152,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
		goto drop;

	/* Find the output device */
	out_dev = rt->rt_dev;
	out_dev = rcu_dereference(rt->rt_dev);
	if (!mpls_output_possible(out_dev))
		goto drop;

@@ -162,7 +162,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
	skb_forward_csum(skb);

	/* Verify ttl is valid */
	if (dec.ttl <= 2)
	if (dec.ttl <= 1)
		goto drop;
	dec.ttl -= 1;

@@ -201,7 +201,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
		}
	}

	err = neigh_xmit(rt->rt_via_family, out_dev, rt->rt_via, skb);
	err = neigh_xmit(rt->rt_via_table, out_dev, rt->rt_via, skb);
	if (err)
		net_dbg_ratelimited("%s: packet transmission failed: %d\n",
				    __func__, err);
@@ -225,7 +225,7 @@ static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = {
struct mpls_route_config {
	u32		rc_protocol;
	u32		rc_ifindex;
	u16		rc_via_family;
	u16		rc_via_table;
	u16		rc_via_alen;
	u8		rc_via[MAX_VIA_ALEN];
	u32		rc_label;
@@ -239,7 +239,7 @@ static struct mpls_route *mpls_rt_alloc(size_t alen)
{
	struct mpls_route *rt;

	rt = kzalloc(GFP_KERNEL, sizeof(*rt) + alen);
	rt = kzalloc(sizeof(*rt) + alen, GFP_KERNEL);
	if (rt)
		rt->rt_via_alen = alen;
	return rt;
@@ -269,13 +269,15 @@ static void mpls_route_update(struct net *net, unsigned index,
			      struct net_device *dev, struct mpls_route *new,
			      const struct nl_info *info)
{
	struct mpls_route __rcu **platform_label;
	struct mpls_route *rt, *old = NULL;

	ASSERT_RTNL();

	rt = net->mpls.platform_label[index];
	if (!dev || (rt && (rt->rt_dev == dev))) {
		rcu_assign_pointer(net->mpls.platform_label[index], new);
	platform_label = rtnl_dereference(net->mpls.platform_label);
	rt = rtnl_dereference(platform_label[index]);
	if (!dev || (rt && (rtnl_dereference(rt->rt_dev) == dev))) {
		rcu_assign_pointer(platform_label[index], new);
		old = rt;
	}

@@ -287,9 +289,14 @@ static void mpls_route_update(struct net *net, unsigned index,

static unsigned find_free_label(struct net *net)
{
	struct mpls_route __rcu **platform_label;
	size_t platform_labels;
	unsigned index;
	for (index = 16; index < net->mpls.platform_labels; index++) {
		if (!net->mpls.platform_label[index])

	platform_label = rtnl_dereference(net->mpls.platform_label);
	platform_labels = net->mpls.platform_labels;
	for (index = 16; index < platform_labels; index++) {
		if (!rtnl_dereference(platform_label[index]))
			return index;
	}
	return LABEL_NOT_SPECIFIED;
@@ -297,6 +304,7 @@ static unsigned find_free_label(struct net *net)

static int mpls_route_add(struct mpls_route_config *cfg)
{
	struct mpls_route __rcu **platform_label;
	struct net *net = cfg->rc_nlinfo.nl_net;
	struct net_device *dev = NULL;
	struct mpls_route *rt, *old;
@@ -335,17 +343,18 @@ static int mpls_route_add(struct mpls_route_config *cfg)
		goto errout;

	err = -EINVAL;
	if ((cfg->rc_via_family == AF_PACKET) &&
	if ((cfg->rc_via_table == NEIGH_LINK_TABLE) &&
	    (dev->addr_len != cfg->rc_via_alen))
		goto errout;

	/* Append makes no sense with mpls */
	err = -EINVAL;
	err = -EOPNOTSUPP;
	if (cfg->rc_nlflags & NLM_F_APPEND)
		goto errout;

	err = -EEXIST;
	old = net->mpls.platform_label[index];
	platform_label = rtnl_dereference(net->mpls.platform_label);
	old = rtnl_dereference(platform_label[index]);
	if ((cfg->rc_nlflags & NLM_F_EXCL) && old)
		goto errout;

@@ -366,8 +375,8 @@ static int mpls_route_add(struct mpls_route_config *cfg)
	for (i = 0; i < rt->rt_labels; i++)
		rt->rt_label[i] = cfg->rc_output_label[i];
	rt->rt_protocol = cfg->rc_protocol;
	rt->rt_dev = dev;
	rt->rt_via_family = cfg->rc_via_family;
	RCU_INIT_POINTER(rt->rt_dev, dev);
	rt->rt_via_table = cfg->rc_via_table;
	memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen);

	mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo);
@@ -406,14 +415,16 @@ static int mpls_route_del(struct mpls_route_config *cfg)

static void mpls_ifdown(struct net_device *dev)
{
	struct mpls_route __rcu **platform_label;
	struct net *net = dev_net(dev);
	unsigned index;

	platform_label = rtnl_dereference(net->mpls.platform_label);
	for (index = 0; index < net->mpls.platform_labels; index++) {
		struct mpls_route *rt = net->mpls.platform_label[index];
		struct mpls_route *rt = rtnl_dereference(platform_label[index]);
		if (!rt)
			continue;
		if (rt->rt_dev != dev)
		if (rtnl_dereference(rt->rt_dev) != dev)
			continue;
		rt->rt_dev = NULL;
	}
@@ -437,15 +448,22 @@ static struct notifier_block mpls_dev_notifier = {
};

static int nla_put_via(struct sk_buff *skb,
		       u16 family, const void *addr, int alen)
		       u8 table, const void *addr, int alen)
{
	static const int table_to_family[NEIGH_NR_TABLES + 1] = {
		AF_INET, AF_INET6, AF_DECnet, AF_PACKET,
	};
	struct nlattr *nla;
	struct rtvia *via;
	int family = AF_UNSPEC;

	nla = nla_reserve(skb, RTA_VIA, alen + 2);
	if (!nla)
		return -EMSGSIZE;

	if (table <= NEIGH_NR_TABLES)
		family = table_to_family[table];

	via = nla_data(nla);
	via->rtvia_family = family;
	memcpy(via->rtvia_addr, addr, alen);
@@ -588,21 +606,23 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
			struct rtvia *via = nla_data(nla);
			if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
				goto errout;
			cfg->rc_via_family = via->rtvia_family;
			cfg->rc_via_alen   = nla_len(nla) -
				offsetof(struct rtvia, rtvia_addr);
			if (cfg->rc_via_alen > MAX_VIA_ALEN)
				goto errout;

			/* Validate the address family */
			switch(cfg->rc_via_family) {
			switch(via->rtvia_family) {
			case AF_PACKET:
				cfg->rc_via_table = NEIGH_LINK_TABLE;
				break;
			case AF_INET:
				cfg->rc_via_table = NEIGH_ARP_TABLE;
				if (cfg->rc_via_alen != 4)
					goto errout;
				break;
			case AF_INET6:
				cfg->rc_via_table = NEIGH_ND_TABLE;
				if (cfg->rc_via_alen != 16)
					goto errout;
				break;
@@ -653,6 +673,7 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
			   u32 label, struct mpls_route *rt, int flags)
{
	struct net_device *dev;
	struct nlmsghdr *nlh;
	struct rtmsg *rtm;

@@ -674,9 +695,10 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
	if (rt->rt_labels &&
	    nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
		goto nla_put_failure;
	if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen))
	if (nla_put_via(skb, rt->rt_via_table, rt->rt_via, rt->rt_via_alen))
		goto nla_put_failure;
	if (rt->rt_dev && nla_put_u32(skb, RTA_OIF, rt->rt_dev->ifindex))
	dev = rtnl_dereference(rt->rt_dev);
	if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
		goto nla_put_failure;
	if (nla_put_labels(skb, RTA_DST, 1, &label))
		goto nla_put_failure;
@@ -692,6 +714,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct net *net = sock_net(skb->sk);
	struct mpls_route __rcu **platform_label;
	size_t platform_labels;
	unsigned int index;

	ASSERT_RTNL();
@@ -700,9 +724,11 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
	if (index < 16)
		index = 16;

	for (; index < net->mpls.platform_labels; index++) {
	platform_label = rtnl_dereference(net->mpls.platform_label);
	platform_labels = net->mpls.platform_labels;
	for (; index < platform_labels; index++) {
		struct mpls_route *rt;
		rt = net->mpls.platform_label[index];
		rt = rtnl_dereference(platform_label[index]);
		if (!rt)
			continue;

@@ -780,9 +806,9 @@ static int resize_platform_label_table(struct net *net, size_t limit)
		rt0 = mpls_rt_alloc(lo->addr_len);
		if (!rt0)
			goto nort0;
		rt0->rt_dev = lo;
		RCU_INIT_POINTER(rt0->rt_dev, lo);
		rt0->rt_protocol = RTPROT_KERNEL;
		rt0->rt_via_family = AF_PACKET;
		rt0->rt_via_table = NEIGH_LINK_TABLE;
		memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
	}
	if (limit > LABEL_IPV6_EXPLICIT_NULL) {
@@ -790,15 +816,15 @@ static int resize_platform_label_table(struct net *net, size_t limit)
		rt2 = mpls_rt_alloc(lo->addr_len);
		if (!rt2)
			goto nort2;
		rt2->rt_dev = lo;
		RCU_INIT_POINTER(rt2->rt_dev, lo);
		rt2->rt_protocol = RTPROT_KERNEL;
		rt2->rt_via_family = AF_PACKET;
		rt2->rt_via_table = NEIGH_LINK_TABLE;
		memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len);
	}

	rtnl_lock();
	/* Remember the original table */
	old = net->mpls.platform_label;
	old = rtnl_dereference(net->mpls.platform_label);
	old_limit = net->mpls.platform_labels;

	/* Free any labels beyond the new table */
@@ -815,19 +841,19 @@ static int resize_platform_label_table(struct net *net, size_t limit)
	/* If needed set the predefined labels */
	if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) &&
	    (limit > LABEL_IPV6_EXPLICIT_NULL)) {
		labels[LABEL_IPV6_EXPLICIT_NULL] = rt2;
		RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2);
		rt2 = NULL;
	}

	if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) &&
	    (limit > LABEL_IPV4_EXPLICIT_NULL)) {
		labels[LABEL_IPV4_EXPLICIT_NULL] = rt0;
		RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0);
		rt0 = NULL;
	}

	/* Update the global pointers */
	net->mpls.platform_labels = limit;
	net->mpls.platform_label = labels;
	rcu_assign_pointer(net->mpls.platform_label, labels);

	rtnl_unlock();

@@ -903,6 +929,8 @@ static int mpls_net_init(struct net *net)

static void mpls_net_exit(struct net *net)
{
	struct mpls_route __rcu **platform_label;
	size_t platform_labels;
	struct ctl_table *table;
	unsigned int index;

@@ -910,8 +938,8 @@ static void mpls_net_exit(struct net *net)
	unregister_net_sysctl_table(net->mpls.ctl);
	kfree(table);

	/* An rcu grace period haselapsed since there was a device in
	 * the network namespace (and thus the last in fqlight packet)
	/* An rcu grace period has passed since there was a device in
	 * the network namespace (and thus the last in flight packet)
	 * left this network namespace.  This is because
	 * unregister_netdevice_many and netdev_run_todo has completed
	 * for each network device that was in this network namespace.
@@ -920,14 +948,16 @@ static void mpls_net_exit(struct net *net)
	 * freeing the platform_label table.
	 */
	rtnl_lock();
	for (index = 0; index < net->mpls.platform_labels; index++) {
		struct mpls_route *rt = net->mpls.platform_label[index];
		rcu_assign_pointer(net->mpls.platform_label[index], NULL);
	platform_label = rtnl_dereference(net->mpls.platform_label);
	platform_labels = net->mpls.platform_labels;
	for (index = 0; index < platform_labels; index++) {
		struct mpls_route *rt = rtnl_dereference(platform_label[index]);
		RCU_INIT_POINTER(platform_label[index], NULL);
		mpls_rt_free(rt);
	}
	rtnl_unlock();

	kvfree(net->mpls.platform_label);
	kvfree(platform_label);
}

static struct pernet_operations mpls_net_ops = {
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ config OPENVSWITCH
	tristate "Open vSwitch"
	depends on INET
	select LIBCRC32C
	select MPLS
	select NET_MPLS_GSO
	---help---
	  Open vSwitch is a multilayer Ethernet switch targeted at virtualized