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

Merge branch 'net-API-and-initial-implementation-for-nexthop-objects'



David Ahern says:

====================
net: API and initial implementation for nexthop objects

This set contains the API and initial implementation for nexthops as
standalone objects.

Patch 1 contains the UAPI and updates to selinux struct.

Patch 2 contains the barebones code for nexthop commands, rbtree
maintenance and notifications.

Patch 3 then adds support for IPv4 gateways along with handling of
netdev events.

Patch 4 adds support for IPv6 gateways.

Patch 5 has the implementation of the encap attributes.

Patch 6 adds support for nexthop groups.

At the end of this set, nexthop objects can be created and deleted and
userspace can monitor nexthop events, but ipv4 and ipv6 routes can not
use them yet. Once the nexthop struct is defined, follow on sets add it
to fib{6}_info and handle it within the respective code before routes
can be inserted using them.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 602e0f29 430a0491
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <net/netns/packet.h>
#include <net/netns/ipv4.h>
#include <net/netns/ipv6.h>
#include <net/netns/nexthop.h>
#include <net/netns/ieee802154_6lowpan.h>
#include <net/netns/sctp.h>
#include <net/netns/dccp.h>
@@ -108,6 +109,7 @@ struct net {
	struct netns_mib	mib;
	struct netns_packet	packet;
	struct netns_unix	unx;
	struct netns_nexthop	nexthop;
	struct netns_ipv4	ipv4;
#if IS_ENABLED(CONFIG_IPV6)
	struct netns_ipv6	ipv6;
+18 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * nexthops in net namespaces
 */

#ifndef __NETNS_NEXTHOP_H__
#define __NETNS_NEXTHOP_H__

#include <linux/rbtree.h>

struct netns_nexthop {
	struct rb_root		rb_root;	/* tree of nexthops by id */
	struct hlist_head	*devhash;	/* nexthops by device */

	unsigned int		seq;		/* protected by rtnl_mutex */
	u32			last_id_allocated;
};
#endif

include/net/nexthop.h

0 → 100644
+195 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Generic nexthop implementation
 *
 * Copyright (c) 2017-19 Cumulus Networks
 * Copyright (c) 2017-19 David Ahern <dsa@cumulusnetworks.com>
 */

#ifndef __LINUX_NEXTHOP_H
#define __LINUX_NEXTHOP_H

#include <linux/netdevice.h>
#include <linux/types.h>
#include <net/ip_fib.h>
#include <net/ip6_fib.h>
#include <net/netlink.h>

#define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK

struct nexthop;

struct nh_config {
	u32		nh_id;

	u8		nh_family;
	u8		nh_protocol;
	u8		nh_blackhole;
	u32		nh_flags;

	int		nh_ifindex;
	struct net_device *dev;

	union {
		__be32		ipv4;
		struct in6_addr	ipv6;
	} gw;

	struct nlattr	*nh_grp;
	u16		nh_grp_type;

	struct nlattr	*nh_encap;
	u16		nh_encap_type;

	u32		nlflags;
	struct nl_info	nlinfo;
};

struct nh_info {
	struct hlist_node	dev_hash;    /* entry on netns devhash */
	struct nexthop		*nh_parent;

	u8			family;
	bool			reject_nh;

	union {
		struct fib_nh_common	fib_nhc;
		struct fib_nh		fib_nh;
		struct fib6_nh		fib6_nh;
	};
};

struct nh_grp_entry {
	struct nexthop	*nh;
	u8		weight;
	atomic_t	upper_bound;

	struct list_head nh_list;
	struct nexthop	*nh_parent;  /* nexthop of group with this entry */
};

struct nh_group {
	u16			num_nh;
	bool			mpath;
	bool			has_v4;
	struct nh_grp_entry	nh_entries[0];
};

struct nexthop {
	struct rb_node		rb_node;    /* entry on netns rbtree */
	struct list_head	grp_list;   /* nh group entries using this nh */
	struct net		*net;

	u32			id;

	u8			protocol;   /* app managing this nh */
	u8			nh_flags;
	bool			is_group;

	refcount_t		refcnt;
	struct rcu_head		rcu;

	union {
		struct nh_info	__rcu *nh_info;
		struct nh_group __rcu *nh_grp;
	};
};

/* caller is holding rcu or rtnl; no reference taken to nexthop */
struct nexthop *nexthop_find_by_id(struct net *net, u32 id);
void nexthop_free_rcu(struct rcu_head *head);

static inline bool nexthop_get(struct nexthop *nh)
{
	return refcount_inc_not_zero(&nh->refcnt);
}

static inline void nexthop_put(struct nexthop *nh)
{
	if (refcount_dec_and_test(&nh->refcnt))
		call_rcu(&nh->rcu, nexthop_free_rcu);
}

static inline bool nexthop_is_multipath(const struct nexthop *nh)
{
	if (nh->is_group) {
		struct nh_group *nh_grp;

		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
		return nh_grp->mpath;
	}
	return false;
}

struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);

static inline unsigned int nexthop_num_path(const struct nexthop *nh)
{
	unsigned int rc = 1;

	if (nexthop_is_multipath(nh)) {
		struct nh_group *nh_grp;

		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
		rc = nh_grp->num_nh;
	} else {
		const struct nh_info *nhi;

		nhi = rcu_dereference_rtnl(nh->nh_info);
		if (nhi->reject_nh)
			rc = 0;
	}

	return rc;
}

static inline
struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
{
	const struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp);

	/* for_nexthops macros in fib_semantics.c grabs a pointer to
	 * the nexthop before checking nhsel
	 */
	if (nhsel > nhg->num_nh)
		return NULL;

	return nhg->nh_entries[nhsel].nh;
}

static inline
int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
{
	struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
	int i;

	for (i = 0; i < nhg->num_nh; i++) {
		struct nexthop *nhe = nhg->nh_entries[i].nh;
		struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
		struct fib_nh_common *nhc = &nhi->fib_nhc;
		int weight = nhg->nh_entries[i].weight;

		if (fib_add_nexthop(skb, nhc, weight) < 0)
			return -EMSGSIZE;
	}

	return 0;
}

/* called with rcu lock */
static inline bool nexthop_is_blackhole(const struct nexthop *nh)
{
	const struct nh_info *nhi;

	if (nexthop_is_multipath(nh)) {
		if (nexthop_num_path(nh) > 1)
			return false;
		nh = nexthop_mpath_select(nh, 0);
		if (!nh)
			return false;
	}

	nhi = rcu_dereference_rtnl(nh->nh_info);
	return nhi->reject_nh;
}
#endif
+56 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_NEXTHOP_H
#define _UAPI_LINUX_NEXTHOP_H

#include <linux/types.h>

struct nhmsg {
	unsigned char	nh_family;
	unsigned char	nh_scope;     /* return only */
	unsigned char	nh_protocol;  /* Routing protocol that installed nh */
	unsigned char	resvd;
	unsigned int	nh_flags;     /* RTNH_F flags */
};

/* entry in a nexthop group */
struct nexthop_grp {
	__u32	id;	  /* nexthop id - must exist */
	__u8	weight;   /* weight of this nexthop */
	__u8	resvd1;
	__u16	resvd2;
};

enum {
	NEXTHOP_GRP_TYPE_MPATH,  /* default type if not specified */
	__NEXTHOP_GRP_TYPE_MAX,
};

#define NEXTHOP_GRP_TYPE_MAX (__NEXTHOP_GRP_TYPE_MAX - 1)

enum {
	NHA_UNSPEC,
	NHA_ID,		/* u32; id for nexthop. id == 0 means auto-assign */

	NHA_GROUP,	/* array of nexthop_grp */
	NHA_GROUP_TYPE,	/* u16 one of NEXTHOP_GRP_TYPE */
	/* if NHA_GROUP attribute is added, no other attributes can be set */

	NHA_BLACKHOLE,	/* flag; nexthop used to blackhole packets */
	/* if NHA_BLACKHOLE is added, OIF, GATEWAY, ENCAP can not be set */

	NHA_OIF,	/* u32; nexthop device */
	NHA_GATEWAY,	/* be32 (IPv4) or in6_addr (IPv6) gw address */
	NHA_ENCAP_TYPE, /* u16; lwt encap type */
	NHA_ENCAP,	/* lwt encap data */

	/* NHA_OIF can be appended to dump request to return only
	 * nexthops using given device
	 */
	NHA_GROUPS,	/* flag; only return nexthop groups in dump */
	NHA_MASTER,	/* u32;  only return nexthops with given master dev */

	__NHA_MAX,
};

#define NHA_MAX	(__NHA_MAX - 1)
#endif
+10 −0
Original line number Diff line number Diff line
@@ -157,6 +157,13 @@ enum {
	RTM_GETCHAIN,
#define RTM_GETCHAIN RTM_GETCHAIN

	RTM_NEWNEXTHOP = 104,
#define RTM_NEWNEXTHOP	RTM_NEWNEXTHOP
	RTM_DELNEXTHOP,
#define RTM_DELNEXTHOP	RTM_DELNEXTHOP
	RTM_GETNEXTHOP,
#define RTM_GETNEXTHOP	RTM_GETNEXTHOP

	__RTM_MAX,
#define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
};
@@ -342,6 +349,7 @@ enum rtattr_type_t {
	RTA_IP_PROTO,
	RTA_SPORT,
	RTA_DPORT,
	RTA_NH_ID,
	__RTA_MAX
};

@@ -704,6 +712,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV4_MROUTE_R	RTNLGRP_IPV4_MROUTE_R
	RTNLGRP_IPV6_MROUTE_R,
#define RTNLGRP_IPV6_MROUTE_R	RTNLGRP_IPV6_MROUTE_R
	RTNLGRP_NEXTHOP,
#define RTNLGRP_NEXTHOP		RTNLGRP_NEXTHOP
	__RTNLGRP_MAX
};
#define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
Loading