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

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
......@@ -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;
......
/* 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
/* 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
/* 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
......@@ -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)
......
......@@ -14,7 +14,7 @@ obj-y := route.o inetpeer.o protocol.o \
udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \
fib_frontend.o fib_semantics.o fib_trie.o fib_notifier.o \
inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o \
metrics.o netlink.o
metrics.o netlink.o nexthop.o
obj-$(CONFIG_BPFILTER) += bpfilter/
......
This diff is collapsed.
......@@ -83,6 +83,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
......@@ -166,7 +169,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
* structures at the top of this file with the new mappings
* before updating the BUILD_BUG_ON() macro!
*/
BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3));
BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOP + 3));
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
......
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