Whamcloud - gitweb
LU-10391 lnet: support IPv6 in lnet_inet_enumerate() 72/48572/2
authorMr NeilBrown <neilb@suse.de>
Fri, 16 Sep 2022 00:57:13 +0000 (10:57 +1000)
committerOleg Drokin <green@whamcloud.com>
Sat, 15 Oct 2022 05:54:49 +0000 (05:54 +0000)
lnet_inet_enumerate() can now optionally report IPv6 addresses on
interfaces.  We use this in socklnd to determine the address of the
interface.

Unlike IPv4, different IPv6 addresses associated with a single
interface cannot be associated with different labels (e.g. eth0:2).
This means that lnet_inet_enumerate() must report the same name for
each address.  For now, we only report the first non-temporary address
to avoid any confusion.

The network mask provided with IPv4 is only use for reporting
information for an ioctl.  It isn't clear this will be useful for
IPv6, so no netmask is collected.

To save a bit of space in struct lnet_inetdev{} which much now hold a
16byte address, we replace he 4byte flag with a 1byte bool as only the
IFF_MASTER flag is ever of interest.  Another bool is needed to report
of the address is IPv6.

Test-Parameters: trivial testlist=sanity-lnet
Test-Parameters: serverversion=2.12 serverdistro=el7.9 testlist=runtests
Test-Parameters: clientversion=2.12 testlist=runtests
Signed-off-by: Mr NeilBrown <neilb@suse.de>
Change-Id: I7a73033f40cc83a8993281696f17332a9101db1e
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/48572
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Serguei Smirnov <ssmirnov@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lnet/include/lnet/lib-lnet.h
lnet/klnds/o2iblnd/o2iblnd.c
lnet/klnds/socklnd/socklnd.c
lnet/lnet/config.c

index 119b1f4..f3caecd 100644 (file)
@@ -900,14 +900,21 @@ void lnet_acceptor_stop(void);
 
 struct lnet_inetdev {
        u32     li_cpt;
-       u32     li_flags;
-       u32     li_ipaddr;
-       u32     li_netmask;
+       union {
+               struct {
+                       u32     li_ipaddr;
+                       u32     li_netmask;
+               };
+               u32     li_ipv6addr[4];
+       };
        u32     li_index;
+       bool    li_iff_master;
+       bool    li_ipv6;
        char    li_name[IFNAMSIZ];
 };
 
-int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns);
+int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns,
+                       bool v6);
 void lnet_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize);
 void lnet_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize);
 int lnet_sock_getaddr(struct socket *socket, bool remote,
index 53f5c70..e31d0d6 100644 (file)
@@ -3485,7 +3485,7 @@ kiblnd_startup(struct lnet_ni *ni)
                goto failed;
        }
 
-       rc = lnet_inet_enumerate(&ifaces, ni->ni_net_ns);
+       rc = lnet_inet_enumerate(&ifaces, ni->ni_net_ns, false);
        if (rc < 0)
                goto failed;
 
@@ -3513,7 +3513,7 @@ kiblnd_startup(struct lnet_ni *ni)
                ibdev->ibd_ifip = ifaces[i].li_ipaddr;
                strlcpy(ibdev->ibd_ifname, ifaces[i].li_name,
                        sizeof(ibdev->ibd_ifname));
-               ibdev->ibd_can_failover = !!(ifaces[i].li_flags & IFF_MASTER);
+               ibdev->ibd_can_failover = ifaces[i].li_iff_master;
 
                INIT_LIST_HEAD(&ibdev->ibd_nets);
                INIT_LIST_HEAD(&ibdev->ibd_list); /* not yet in kib_devs */
index 7d991a1..216a578 100644 (file)
@@ -1729,11 +1729,13 @@ ksocknal_ctl(struct lnet_ni *ni, unsigned int cmd, void *arg)
                        iface = &net->ksnn_interface;
 
                        sa = (void *)&iface->ksni_addr;
-                       if (sa->sin_family == AF_INET)
+                       if (sa->sin_family == AF_INET) {
                                data->ioc_u32[0] = ntohl(sa->sin_addr.s_addr);
-                       else
+                               data->ioc_u32[1] = iface->ksni_netmask;
+                       } else {
                                data->ioc_u32[0] = 0xFFFFFFFF;
-                       data->ioc_u32[1] = iface->ksni_netmask;
+                               data->ioc_u32[1] = 0;
+                       }
                        data->ioc_u32[2] = iface->ksni_npeers;
                        data->ioc_u32[3] = iface->ksni_nroutes;
                }
@@ -2430,16 +2432,15 @@ ksocknal_startup(struct lnet_ni *ni)
        struct ksock_net *net;
        struct ksock_interface *ksi = NULL;
        struct lnet_inetdev *ifaces = NULL;
-       struct sockaddr_in *sa;
        int i = 0;
        int rc;
 
-        LASSERT (ni->ni_net->net_lnd == &the_ksocklnd);
-        if (ksocknal_data.ksnd_init == SOCKNAL_INIT_NOTHING) {
-                rc = ksocknal_base_startup();
-                if (rc != 0)
-                        return rc;
-        }
+       LASSERT (ni->ni_net->net_lnd == &the_ksocklnd);
+       if (ksocknal_data.ksnd_init == SOCKNAL_INIT_NOTHING) {
+               rc = ksocknal_base_startup();
+               if (rc != 0)
+                       return rc;
+       }
        LIBCFS_ALLOC(net, sizeof(*net));
        if (net == NULL)
                goto fail_0;
@@ -2448,7 +2449,7 @@ ksocknal_startup(struct lnet_ni *ni)
 
        ksocknal_tunables_setup(ni);
 
-       rc = lnet_inet_enumerate(&ifaces, ni->ni_net_ns);
+       rc = lnet_inet_enumerate(&ifaces, ni->ni_net_ns, true);
        if (rc < 0)
                goto fail_1;
 
@@ -2470,11 +2471,26 @@ ksocknal_startup(struct lnet_ni *ni)
 
        ni->ni_dev_cpt = ifaces[i].li_cpt;
        ksi->ksni_index = ifaces[i].li_index;
-       sa = (void *)&ksi->ksni_addr;
-       memset(sa, 0, sizeof(*sa));
-       sa->sin_family = AF_INET;
-       sa->sin_addr.s_addr = htonl(ifaces[i].li_ipaddr);
-       ksi->ksni_netmask = ifaces[i].li_netmask;
+       if (ifaces[i].li_ipv6) {
+               struct sockaddr_in6 *sa;
+               sa = (void *)&ksi->ksni_addr;
+               memset(sa, 0, sizeof(*sa));
+               sa->sin6_family = AF_INET6;
+               memcpy(&sa->sin6_addr, ifaces[i].li_ipv6addr,
+                      sizeof(struct in6_addr));
+               ni->ni_nid.nid_size = sizeof(struct in6_addr) - 4;
+               memcpy(&ni->ni_nid.nid_addr, ifaces[i].li_ipv6addr,
+                      sizeof(struct in6_addr));
+       } else {
+               struct sockaddr_in *sa;
+               sa = (void *)&ksi->ksni_addr;
+               memset(sa, 0, sizeof(*sa));
+               sa->sin_family = AF_INET;
+               sa->sin_addr.s_addr = htonl(ifaces[i].li_ipaddr);
+               ksi->ksni_netmask = ifaces[i].li_netmask;
+               ni->ni_nid.nid_size = 4 - 4;
+               ni->ni_nid.nid_addr[0] = sa->sin_addr.s_addr;
+       }
        strlcpy(ksi->ksni_name, ifaces[i].li_name, sizeof(ksi->ksni_name));
 
        /* call it before add it to ksocknal_data.ksnd_nets */
@@ -2482,10 +2498,6 @@ ksocknal_startup(struct lnet_ni *ni)
        if (rc != 0)
                goto fail_1;
 
-       LASSERT(ksi);
-       LASSERT(ksi->ksni_addr.ss_family == AF_INET);
-       ni->ni_nid.nid_addr[0] =
-               ((struct sockaddr_in *)&ksi->ksni_addr)->sin_addr.s_addr;
        list_add(&net->ksnn_list, &ksocknal_data.ksnd_nets);
        net->ksnn_ni = ni;
        ksocknal_data.ksnd_nnets++;
index f9285d4..d01bfb2 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 #include <lnet/lib-lnet.h>
+#include <net/addrconf.h>
 
 /* tmp struct for parsing routes */
 struct lnet_text_buf {
@@ -1505,7 +1506,7 @@ lnet_match_networks(const char **networksp, const char *ip2nets,
        return count;
 }
 
-int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
+int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns, bool v6)
 {
        struct lnet_inetdev *ifaces = NULL;
        struct net_device *dev;
@@ -1517,6 +1518,8 @@ int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
        for_each_netdev(ns, dev) {
                int flags = dev_get_flags(dev);
                struct in_device *in_dev;
+               struct inet6_dev *in6_dev;
+               const struct inet6_ifaddr *ifa6;
                int node_id;
                int cpt;
 
@@ -1529,16 +1532,17 @@ int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
                        continue;
                }
 
+               node_id = dev_to_node(&dev->dev);
+               cpt = cfs_cpt_of_node(lnet_cpt_table(), node_id);
+
                in_dev = __in_dev_get_rtnl(dev);
                if (!in_dev) {
-                       CWARN("lnet: Interface %s has no IPv4 status.\n",
-                             dev->name);
-                       continue;
+                       if (!v6)
+                               CWARN("lnet: Interface %s has no IPv4 status.\n",
+                                     dev->name);
+                       goto try_v6;
                }
 
-               node_id = dev_to_node(&dev->dev);
-               cpt = cfs_cpt_of_node(lnet_cpt_table(), node_id);
-
                in_dev_for_each_ifa_rtnl(ifa, in_dev) {
                        if (nip >= nalloc) {
                                struct lnet_inetdev *tmp;
@@ -1556,7 +1560,8 @@ int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
                        }
 
                        ifaces[nip].li_cpt = cpt;
-                       ifaces[nip].li_flags = flags;
+                       ifaces[nip].li_iff_master = !!(flags & IFF_MASTER);
+                       ifaces[nip].li_ipv6 = false;
                        ifaces[nip].li_index = dev->ifindex;
                        ifaces[nip].li_ipaddr = ntohl(ifa->ifa_local);
                        ifaces[nip].li_netmask = ntohl(ifa->ifa_mask);
@@ -1565,6 +1570,54 @@ int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
                        nip++;
                }
                endfor_ifa(in_dev);
+
+       try_v6:
+               if (!v6)
+                       continue;
+#if IS_ENABLED(CONFIG_IPV6)
+               in6_dev = __in6_dev_get(dev);
+               if (!in6_dev) {
+                       if (!in_dev)
+                               CWARN("lnet: Interface %s has no IP status.\n",
+                                     dev->name);
+                       continue;
+               }
+
+               list_for_each_entry_rcu(ifa6, &in6_dev->addr_list, if_list) {
+                       if (ifa6->flags & IFA_F_TEMPORARY)
+                               continue;
+                       if (nip >= nalloc) {
+                               struct lnet_inetdev *tmp;
+
+                               nalloc += LNET_INTERFACES_NUM;
+                               tmp = krealloc(ifaces, nalloc * sizeof(*tmp),
+                                              GFP_KERNEL);
+                               if (!tmp) {
+                                       kfree(ifaces);
+                                       ifaces = NULL;
+                                       nip = -ENOMEM;
+                                       goto unlock_rtnl;
+                               }
+                               ifaces = tmp;
+                       }
+
+                       ifaces[nip].li_cpt = cpt;
+                       ifaces[nip].li_iff_master = !!(flags & IFF_MASTER);
+                       ifaces[nip].li_ipv6 = true;
+                       ifaces[nip].li_index = dev->ifindex;
+                       memcpy(ifaces[nip].li_ipv6addr,
+                              &ifa6->addr, sizeof(struct in6_addr));
+                       strlcpy(ifaces[nip].li_name, dev->name,
+                               sizeof(ifaces[nip].li_name));
+                       nip++;
+                       /* As different IPv6 addresses don't have unique
+                        * labels, it is safest just to use the first
+                        * and ignore the rest.
+                        */
+                       break;
+               }
+#endif /* IS_ENABLED(CONFIG_IPV6) */
+
        }
 unlock_rtnl:
        rtnl_unlock();
@@ -1589,9 +1642,10 @@ lnet_parse_ip2nets(const char **networksp, const char *ip2nets)
        int i;
 
        if (current->nsproxy && current->nsproxy->net_ns)
-               nip = lnet_inet_enumerate(&ifaces, current->nsproxy->net_ns);
+               nip = lnet_inet_enumerate(&ifaces, current->nsproxy->net_ns,
+                                         false);
        else
-               nip = lnet_inet_enumerate(&ifaces, &init_net);
+               nip = lnet_inet_enumerate(&ifaces, &init_net, false);
        if (nip < 0) {
                if (nip != -ENOENT) {
                        LCONSOLE_ERROR_MSG(0x117,