]> www.infradead.org Git - users/hch/misc.git/commitdiff
netlink: add IPv6 anycast join/leave notifications
authorYuyang Huang <yuyanghuang@google.com>
Tue, 7 Jan 2025 11:43:55 +0000 (20:43 +0900)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 9 Jan 2025 11:54:45 +0000 (12:54 +0100)
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: Yuyang Huang <yuyanghuang@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250107114355.1766086-1-yuyanghuang@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/addrconf.h
include/uapi/linux/rtnetlink.h
net/ipv6/addrconf.c
net/ipv6/anycast.c

index 58337898fa21d5e72666c88c8feb81f61a780997..f8f91b2038eafd645d1b8d28c6515ea4a670fa6c 100644 (file)
@@ -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
index 5ee94c511a28a9312d9ac6573cdd7c9b649d22c7..66c3903d29cf64479be8b0c914ffdc9ebe986f71 100644 (file)
@@ -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)
index 4da409bc45777f60fd37bdee541c61165a51d22c..c3729382be3bd4c2d680f21201fdf1b86c72817c 100644 (file)
@@ -5240,9 +5240,9 @@ int inet6_fill_ifmcaddr(struct sk_buff *skb,
        return 0;
 }
 
-static int inet6_fill_ifacaddr(struct sk_buff *skb,
-                              const struct ifacaddr6 *ifaca,
-                              struct inet6_fill_args *args)
+int inet6_fill_ifacaddr(struct sk_buff *skb,
+                       const struct ifacaddr6 *ifaca,
+                       struct inet6_fill_args *args)
 {
        struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt);
        int ifindex = dev ? dev->ifindex : 1;
index 562cace50ca9ae635dd0762e147b452be44c729c..21e01695b48cde49f36ee466d75d97842c16f652 100644 (file)
@@ -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;
 }