All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 net-next 1/1] net: Add new protocol attribute to IP addresses
@ 2022-02-09 16:34 Jacques de Laval
  2022-02-10 17:47 ` David Ahern
  0 siblings, 1 reply; 2+ messages in thread
From: Jacques de Laval @ 2022-02-09 16:34 UTC (permalink / raw)
  To: David S. Miller, Jakub Kicinski, Hideaki YOSHIFUJI, David Ahern
  Cc: netdev, Jacques de Laval

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/c25e0affdb14da4b8c582cda29017855e51838be

Signed-off-by: Jacques de Laval <Jacques.De.Laval@westermo.com>
---
v1 -> v2:
  - Move ifa_prot to existing holes in structs (David)
  - Change __u8 to u8 (Jakub)
  - Define and use constants for addresses set by kernel (David)
---
 include/linux/inetdevice.h   |  1 +
 include/net/addrconf.h       |  2 ++
 include/net/if_inet6.h       |  2 ++
 include/uapi/linux/if_addr.h |  9 +++++++++
 net/ipv4/devinet.c           | 10 +++++++++-
 net/ipv6/addrconf.c          | 26 ++++++++++++++++++++------
 6 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index a038feb63f23..6a8bca95a443 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -146,6 +146,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];
 
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 78ea3e332688..54890114127f 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -62,6 +62,8 @@ struct ifa6_config {
 	const struct in6_addr	*pfx;
 	unsigned int		plen;
 
+	u8			ifa_proto;
+
 	const struct in6_addr	*peer_pfx;
 
 	u32			rt_priority;
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 653e7d0f65cb..9127ab101af5 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -71,6 +71,8 @@ struct inet6_ifaddr {
 
 	bool			tokenized;
 
+	u8			ifa_proto;
+
 	struct rcu_head		rcu;
 	struct in6_addr		peer_addr;
 };
diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
index dfcf3ce0097f..2c487a9de658 100644
--- a/include/uapi/linux/if_addr.h
+++ b/include/uapi/linux/if_addr.h
@@ -35,6 +35,7 @@ enum {
 	IFA_FLAGS,
 	IFA_RT_PRIORITY,  /* u32, priority/metric for prefix route */
 	IFA_TARGET_NETNSID,
+	IFA_PROTO,
 	__IFA_MAX,
 };
 
@@ -69,4 +70,12 @@ struct ifa_cacheinfo {
 #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
 #endif
 
+/* ifa_protocol */
+#define IFAPROT_UNSPEC		0
+#define IFAPROT_KERNEL_LO	1       /* loopback */
+#define IFAPROT_KERNEL_RA	2       /* auto assigned by kernel from router
+					   announcement
+					 */
+#define IFAPROT_KERNEL_LL	3       /* link-local set by kernel*/
+
 #endif
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 4744c7839de5..4c72ccd72ceb 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -102,6 +102,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 {
@@ -577,8 +578,10 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
 		in_dev_hold(in_dev);
 		ifa->ifa_dev = in_dev;
 	}
-	if (ipv4_is_loopback(ifa->ifa_local))
+	if (ipv4_is_loopback(ifa->ifa_local)) {
 		ifa->ifa_scope = RT_SCOPE_HOST;
+		ifa->ifa_proto = IFAPROT_KERNEL_LO;
+	}
 	return inet_insert_ifa(ifa);
 }
 
@@ -887,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;
 
@@ -1623,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 */
 }
@@ -1697,6 +1704,7 @@ 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)) ||
+	    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)) ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 846037e73723..09e5fc746a93 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1117,6 +1117,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
 	ifa->prefix_len = cfg->plen;
 	ifa->rt_priority = cfg->rt_priority;
 	ifa->flags = cfg->ifa_flags;
+	ifa->ifa_proto = cfg->ifa_proto;
 	/* No need to add the TENTATIVE flag for addresses with NODAD */
 	if (!(cfg->ifa_flags & IFA_F_NODAD))
 		ifa->flags |= IFA_F_TENTATIVE;
@@ -2598,6 +2599,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
 			.valid_lft = valid_lft,
 			.preferred_lft = prefered_lft,
 			.scope = addr_type & IPV6_ADDR_SCOPE_MASK,
+			.ifa_proto = IFAPROT_KERNEL_RA
 		};
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -3069,7 +3071,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg)
 }
 
 static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
-		     int plen, int scope)
+		     int plen, int scope, u8 proto)
 {
 	struct inet6_ifaddr *ifp;
 	struct ifa6_config cfg = {
@@ -3078,7 +3080,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 		.ifa_flags = IFA_F_PERMANENT,
 		.valid_lft = INFINITY_LIFE_TIME,
 		.preferred_lft = INFINITY_LIFE_TIME,
-		.scope = scope
+		.scope = scope,
+		.ifa_proto = proto
 	};
 
 	ifp = ipv6_add_addr(idev, &cfg, true, NULL);
@@ -3123,7 +3126,7 @@ static void add_v4_addrs(struct inet6_dev *idev)
 	}
 
 	if (addr.s6_addr32[3]) {
-		add_addr(idev, &addr, plen, scope);
+		add_addr(idev, &addr, plen, scope, IFAPROT_UNSPEC);
 		addrconf_prefix_route(&addr, plen, 0, idev->dev, 0, pflags,
 				      GFP_KERNEL);
 		return;
@@ -3146,7 +3149,8 @@ static void add_v4_addrs(struct inet6_dev *idev)
 					flag |= IFA_HOST;
 				}
 
-				add_addr(idev, &addr, plen, flag);
+				add_addr(idev, &addr, plen, flag,
+					 IFAPROT_UNSPEC);
 				addrconf_prefix_route(&addr, plen, 0, idev->dev,
 						      0, pflags, GFP_KERNEL);
 			}
@@ -3169,7 +3173,7 @@ static void init_loopback(struct net_device *dev)
 		return;
 	}
 
-	add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
+	add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFAPROT_KERNEL_LO);
 }
 
 void addrconf_add_linklocal(struct inet6_dev *idev,
@@ -3181,7 +3185,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
 		.ifa_flags = flags | IFA_F_PERMANENT,
 		.valid_lft = INFINITY_LIFE_TIME,
 		.preferred_lft = INFINITY_LIFE_TIME,
-		.scope = IFA_LINK
+		.scope = IFA_LINK,
+		.ifa_proto = IFAPROT_KERNEL_LL
 	};
 	struct inet6_ifaddr *ifp;
 
@@ -4626,6 +4631,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
 	[IFA_FLAGS]		= { .len = sizeof(u32) },
 	[IFA_RT_PRIORITY]	= { .len = sizeof(u32) },
 	[IFA_TARGET_NETNSID]	= { .type = NLA_S32 },
+	[IFA_PROTO]             = { .len = sizeof(u8) },
 };
 
 static int
@@ -4750,6 +4756,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
 	ifp->tstamp = jiffies;
 	ifp->valid_lft = cfg->valid_lft;
 	ifp->prefered_lft = cfg->preferred_lft;
+	ifp->ifa_proto = cfg->ifa_proto;
 
 	if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority)
 		ifp->rt_priority = cfg->rt_priority;
@@ -4843,6 +4850,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
 	if (tb[IFA_RT_PRIORITY])
 		cfg.rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
 
+	if (tb[IFA_PROTO])
+		cfg.ifa_proto = nla_get_u8(tb[IFA_PROTO]);
+
 	cfg.valid_lft = INFINITY_LIFE_TIME;
 	cfg.preferred_lft = INFINITY_LIFE_TIME;
 
@@ -4946,6 +4956,7 @@ static inline int inet6_ifaddr_msgsize(void)
 	       + nla_total_size(16) /* IFA_ADDRESS */
 	       + nla_total_size(sizeof(struct ifa_cacheinfo))
 	       + nla_total_size(4)  /* IFA_FLAGS */
+	       + nla_total_size(1)  /* IFA_PROTO */
 	       + nla_total_size(4)  /* IFA_RT_PRIORITY */;
 }
 
@@ -5023,6 +5034,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
 	if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
 		goto error;
 
+	if (nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto))
+		goto error;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2 net-next 1/1] net: Add new protocol attribute to IP addresses
  2022-02-09 16:34 [PATCH v2 net-next 1/1] net: Add new protocol attribute to IP addresses Jacques de Laval
@ 2022-02-10 17:47 ` David Ahern
  0 siblings, 0 replies; 2+ messages in thread
From: David Ahern @ 2022-02-10 17:47 UTC (permalink / raw)
  To: Jacques de Laval, David S. Miller, Jakub Kicinski,
	Hideaki YOSHIFUJI, David Ahern
  Cc: netdev

On 2/9/22 8:34 AM, Jacques de Laval wrote:
> diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
> index dfcf3ce0097f..2c487a9de658 100644
> --- a/include/uapi/linux/if_addr.h
> +++ b/include/uapi/linux/if_addr.h
> @@ -35,6 +35,7 @@ enum {
>  	IFA_FLAGS,
>  	IFA_RT_PRIORITY,  /* u32, priority/metric for prefix route */
>  	IFA_TARGET_NETNSID,
> +	IFA_PROTO,

Good to self-document attributes for userspace. See IFA_RT_PRIORITY above.


>  	__IFA_MAX,
>  };
>  
> @@ -69,4 +70,12 @@ struct ifa_cacheinfo {
>  #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
>  #endif
>  
> +/* ifa_protocol */
> +#define IFAPROT_UNSPEC		0
> +#define IFAPROT_KERNEL_LO	1       /* loopback */
> +#define IFAPROT_KERNEL_RA	2       /* auto assigned by kernel from router
> +					   announcement
> +					 */

comment style should be:
/* auto assigned by kernel from router
 * announcement
 */

but I think the comment can be shortened to:
/* set by kernel from router announcement */


> +#define IFAPROT_KERNEL_LL	3       /* link-local set by kernel*/

space between kernel and '*'

> +
>  #endif
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index 4744c7839de5..4c72ccd72ceb 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -102,6 +102,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 {
> @@ -577,8 +578,10 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
>  		in_dev_hold(in_dev);
>  		ifa->ifa_dev = in_dev;
>  	}
> -	if (ipv4_is_loopback(ifa->ifa_local))
> +	if (ipv4_is_loopback(ifa->ifa_local)) {
>  		ifa->ifa_scope = RT_SCOPE_HOST;
> +		ifa->ifa_proto = IFAPROT_KERNEL_LO;

inet_set_ifa is used by the old ioctl interface. Even if this is a
loopback address, there is no guarantee this particular assignment is
done by the kernel so the ifa_proto should not be set here.

> +	}
>  	return inet_insert_ifa(ifa);
>  }
>  
> @@ -887,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;
>  
> @@ -1623,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 */
>  }
> @@ -1697,6 +1704,7 @@ 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)) ||
> +	    nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto) ||

if (ifa->ifa_proto && nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto

only set attribute if protocol is set.


>  	    nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
>  	    (ifa->ifa_rt_priority &&
>  	     nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||



> @@ -4946,6 +4956,7 @@ static inline int inet6_ifaddr_msgsize(void)
>  	       + nla_total_size(16) /* IFA_ADDRESS */
>  	       + nla_total_size(sizeof(struct ifa_cacheinfo))
>  	       + nla_total_size(4)  /* IFA_FLAGS */
> +	       + nla_total_size(1)  /* IFA_PROTO */
>  	       + nla_total_size(4)  /* IFA_RT_PRIORITY */;
>  }
>  
> @@ -5023,6 +5034,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
>  	if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
>  		goto error;
>  
> +	if (nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto))

only add attribute if proto set.

> +		goto error;
> +
>  	nlmsg_end(skb, nlh);
>  	return 0;
>  


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-02-10 17:47 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-09 16:34 [PATCH v2 net-next 1/1] net: Add new protocol attribute to IP addresses Jacques de Laval
2022-02-10 17:47 ` David Ahern

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.