Commit 33d97a07 authored by Yuyang Huang's avatar Yuyang Huang Committed by Paolo Abeni
Browse files

netlink: add IPv6 anycast join/leave notifications



This change introduces a mechanism for notifying userspace
applications about changes to IPv6 anycast addresses via netlink. It
includes:

* Addition and deletion of IPv6 anycast addresses are reported using
  RTM_NEWANYCAST and RTM_DELANYCAST.
* A new netlink group (RTNLGRP_IPV6_ACADDR) for subscribing to these
  notifications.

This enables user space applications(e.g. ip monitor) to efficiently
track anycast addresses through netlink messages, improving metrics
collection and system monitoring. It also unlocks the potential for
advanced anycast management in user space, such as hardware offload
control and fine grained network control.

Cc: Maciej Żenczykowski <maze@google.com>
Cc: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: default avatarYuyang Huang <yuyanghuang@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250107114355.1766086-1-yuyanghuang@google.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent e61e6c41
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -546,4 +546,7 @@ int inet6_fill_ifmcaddr(struct sk_buff *skb,
			const struct ifmcaddr6 *ifmca,
			struct inet6_fill_args *args);

int inet6_fill_ifacaddr(struct sk_buff *skb,
			const struct ifacaddr6 *ifaca,
			struct inet6_fill_args *args);
#endif
+7 −1
Original line number Diff line number Diff line
@@ -100,7 +100,11 @@ enum {
	RTM_GETMULTICAST,
#define RTM_GETMULTICAST RTM_GETMULTICAST

	RTM_GETANYCAST	= 62,
	RTM_NEWANYCAST	= 60,
#define RTM_NEWANYCAST RTM_NEWANYCAST
	RTM_DELANYCAST,
#define RTM_DELANYCAST RTM_DELANYCAST
	RTM_GETANYCAST,
#define RTM_GETANYCAST	RTM_GETANYCAST

	RTM_NEWNEIGHTBL	= 64,
@@ -783,6 +787,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV4_MCADDR	RTNLGRP_IPV4_MCADDR
	RTNLGRP_IPV6_MCADDR,
#define RTNLGRP_IPV6_MCADDR	RTNLGRP_IPV6_MCADDR
	RTNLGRP_IPV6_ACADDR,
#define RTNLGRP_IPV6_ACADDR	RTNLGRP_IPV6_ACADDR
	__RTNLGRP_MAX
};
#define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
+3 −3
Original line number Diff line number Diff line
@@ -5240,7 +5240,7 @@ int inet6_fill_ifmcaddr(struct sk_buff *skb,
	return 0;
}

static int inet6_fill_ifacaddr(struct sk_buff *skb,
int inet6_fill_ifacaddr(struct sk_buff *skb,
			const struct ifacaddr6 *ifaca,
			struct inet6_fill_args *args)
{
+35 −0
Original line number Diff line number Diff line
@@ -278,6 +278,37 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *f6i,
	return aca;
}

static void inet6_ifacaddr_notify(struct net_device *dev,
				  const struct ifacaddr6 *ifaca, int event)
{
	struct inet6_fill_args fillargs = {
		.event = event,
		.netnsid = -1,
	};
	struct net *net = dev_net(dev);
	struct sk_buff *skb;
	int err = -ENOMEM;

	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
			nla_total_size(sizeof(struct in6_addr)) +
			nla_total_size(sizeof(struct ifa_cacheinfo)),
			GFP_KERNEL);
	if (!skb)
		goto error;

	err = inet6_fill_ifacaddr(skb, ifaca, &fillargs);
	if (err < 0) {
		pr_err("Failed to fill in anycast addresses (err %d)\n", err);
		nlmsg_free(skb);
		goto error;
	}

	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_ACADDR, NULL, GFP_KERNEL);
	return;
error:
	rtnl_set_sk_err(net, RTNLGRP_IPV6_ACADDR, err);
}

/*
 *	device anycast group inc (add if not found)
 */
@@ -333,6 +364,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)

	addrconf_join_solict(idev->dev, &aca->aca_addr);

	inet6_ifacaddr_notify(idev->dev, aca, RTM_NEWANYCAST);

	aca_put(aca);
	return 0;
out:
@@ -375,6 +408,8 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)

	ip6_del_rt(dev_net(idev->dev), aca->aca_rt, false);

	inet6_ifacaddr_notify(idev->dev, aca, RTM_DELANYCAST);

	aca_put(aca);
	return 0;
}