Commit 47f0bd50 authored by Jacques de Laval's avatar Jacques de Laval Committed by Jakub Kicinski
Browse files

net: Add new protocol attribute to IP addresses

This patch adds a new protocol attribute to IPv4 and IPv6 addresses.
Inspiration was taken from the protocol attribute of routes. User space
applications like iproute2 can set/get the protocol with the Netlink API.

The attribute is stored as an 8-bit unsigned integer.

The protocol attribute is set by kernel for these categories:

- IPv4 and IPv6 loopback addresses
- IPv6 addresses generated from router announcements
- IPv6 link local addresses

User space may pass custom protocols, not defined by the kernel.

Grouping addresses on their origin is useful in scenarios where you want
to distinguish between addresses based on who added them, e.g. kernel
vs. user space.

Tagging addresses with a string label is an existing feature that could be
used as a solution. Unfortunately the max length of a label is
15 characters, and for compatibility reasons the label must be prefixed
with the name of the device followed by a colon. Since device names also
have a max length of 15 characters, only -1 characters is guaranteed to be
available for any origin tag, which is not that much.

A reference implementation of user space setting and getting protocols
is available for iproute2:

https://github.com/westermo/iproute2/commit/9a6ea18bd79f47f293e5edc7780f315ea42ff540



Signed-off-by: default avatarJacques de Laval <Jacques.De.Laval@westermo.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20220217150202.80802-1-Jacques.De.Laval@westermo.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6e2e59ea
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ struct in_ifaddr {
	__be32			ifa_broadcast;
	unsigned char		ifa_scope;
	unsigned char		ifa_prefixlen;
	unsigned char		ifa_proto;
	__u32			ifa_flags;
	char			ifa_label[IFNAMSIZ];

+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ struct ifa6_config {
	const struct in6_addr	*pfx;
	unsigned int		plen;

	u8			ifa_proto;

	const struct in6_addr	*peer_pfx;

	u32			rt_priority;
+2 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ struct inet6_ifaddr {

	bool			tokenized;

	u8			ifa_proto;

	struct rcu_head		rcu;
	struct in6_addr		peer_addr;
};
+8 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ enum {
	IFA_FLAGS,
	IFA_RT_PRIORITY,	/* u32, priority/metric for prefix route */
	IFA_TARGET_NETNSID,
	IFA_PROTO,		/* u8, address protocol */
	__IFA_MAX,
};

@@ -69,4 +70,10 @@ struct ifa_cacheinfo {
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
#endif

/* ifa_proto */
#define IFAPROT_UNSPEC		0
#define IFAPROT_KERNEL_LO	1	/* loopback */
#define IFAPROT_KERNEL_RA	2	/* set by kernel from router announcement */
#define IFAPROT_KERNEL_LL	3	/* link-local set by kernel */

#endif
+7 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
	[IFA_FLAGS]		= { .type = NLA_U32 },
	[IFA_RT_PRIORITY]	= { .type = NLA_U32 },
	[IFA_TARGET_NETNSID]	= { .type = NLA_S32 },
	[IFA_PROTO]		= { .type = NLA_U8 },
};

struct inet_fill_args {
@@ -889,6 +890,9 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
	if (tb[IFA_RT_PRIORITY])
		ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);

	if (tb[IFA_PROTO])
		ifa->ifa_proto = nla_get_u8(tb[IFA_PROTO]);

	if (tb[IFA_CACHEINFO]) {
		struct ifa_cacheinfo *ci;

@@ -1625,6 +1629,7 @@ static size_t inet_nlmsg_size(void)
	       + nla_total_size(4) /* IFA_BROADCAST */
	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
	       + nla_total_size(4)  /* IFA_FLAGS */
	       + nla_total_size(1)  /* IFA_PROTO */
	       + nla_total_size(4)  /* IFA_RT_PRIORITY */
	       + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
}
@@ -1699,6 +1704,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
	     nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
	    (ifa->ifa_label[0] &&
	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
	    (ifa->ifa_proto &&
	     nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto)) ||
	    nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
	    (ifa->ifa_rt_priority &&
	     nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Loading