Whamcloud - gitweb
LU-10391 obdclass: handle large NIDs for mount strings 62/50362/17
authorJames Simmons <jsimmons@infradead.org>
Thu, 3 Aug 2023 20:57:02 +0000 (16:57 -0400)
committerOleg Drokin <green@whamcloud.com>
Thu, 24 Aug 2023 04:32:05 +0000 (04:32 +0000)
Mount strings support using ':' as a delimiter but this is also
a part of the some NID strings like IPv6, so rework class_parse_value()
to only look at ':' when it occurs after '@'.

The mount utilities use the function convert_hostnames() to ensure
the mount string containing an NID is valid. This only works for
small size nids so migrate the function to handle large NIDs. This
should allow mounting with IPv6 or other large NID addresses.

In testing the userland  libcfs_ip_str2addr_size() had bugs that
rendered incorrect NID strings. Fix those issues.

Fixes: b6c702df5d4 ("LU-10391 libcfs: add large-nid string conversion functions.")
Change-Id: Ic9b2a368456ba75ceb5911ac7f75ae00d6123870
Signed-off-by: James Simmons <jsimmons@infradead.org>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50362
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Nathaniel Clark <nclark@whamcloud.com>
Reviewed-by: Chris Horn <chris.horn@hpe.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
libcfs/libcfs/util/nidstrings.c
lustre/obdclass/obd_config.c
lustre/utils/mkfs_lustre.c
lustre/utils/mount_lustre.c
lustre/utils/mount_utils.c
lustre/utils/mount_utils.h

index dfcd8c4..e9fab1c 100644 (file)
@@ -172,19 +172,33 @@ libcfs_ip_str2addr_size(const char *str, int nob,
                        __be32 *addr, size_t *alen)
 {
        char *tmp = malloc(nob+1);
-       int ret = 1;
 
        if (!tmp)
                return 0;
        memcpy(tmp, str, nob);
-       tmp[nob] = 0;
+       tmp[nob] = '\0';
 
-       if (inet_pton(AF_INET, tmp, (struct in_addr *)addr) == 0) {
-               *alen = 4;
+       *alen = 0;
+       if (inet_pton(AF_INET, tmp, (struct in_addr *)addr) == 1) {
+               struct in_addr *ipv4 = (struct in_addr *)addr;
+
+               /* Don't allow using loopback */
+               if (ipv4->s_addr != htonl(INADDR_LOOPBACK))
+                       *alen = 4;
                goto out;
        }
-       if (inet_pton(AF_INET6, tmp, (struct in6_addr *)addr) == 0) {
-               *alen = 16;
+       if (inet_pton(AF_INET6, tmp, (struct in6_addr *)addr) == 1) {
+               struct in6_addr *ipv6 = (struct in6_addr *)addr;
+
+               /* Since link local doesn't allow forwarding packets
+                * for router don't allow those addresses as well.
+                * Site local is allowed since it similar to 10.0.0.0/8.
+                * Be aware site local is deprecated by unique local
+                * addresses.
+                */
+               if (!IN6_IS_ADDR_LOOPBACK(ipv6->s6_addr) &&
+                   !IN6_IS_ADDR_LINKLOCAL(ipv6->s6_addr))
+                       *alen = 16;
                goto out;
        }
 #ifdef HAVE_GETADDRINFO
@@ -223,10 +237,9 @@ libcfs_ip_str2addr_size(const char *str, int nob,
                freeaddrinfo(ai);
        }
 #endif
-       ret = 0;
 out:
        free(tmp);
-       return ret;
+       return *alen != 0;
 }
 
 int
index 51cc601..d9e0e62 100644 (file)
@@ -449,13 +449,20 @@ static int class_parse_value(char *buf, int opc, void *value, char **endh,
 
        if (!buf)
                return 1;
+
        while (*buf == ',' || *buf == ':')
                buf++;
        if (*buf == ' ' || *buf == '/' || *buf == '\0')
                return 1;
 
-       /* NID separators or end of NIDs */
-       endp = strpbrk(buf, ",: /");
+       /* NID separators or end of NIDs. Large NIDs can contain ':' so
+        * skip ahead to @ and then look for one of the delimiters.
+        */
+       endp = strchr(buf, '@');
+       if (!endp)
+               return 1;
+
+       endp = strpbrk(endp, ",: /");
        if (!endp)
                endp = buf + strlen(buf);
 
index 68fd09e..f906230 100644 (file)
@@ -63,6 +63,7 @@
 #include <linux/lnet/lnetctl.h>
 #include <linux/lustre/lustre_user.h>
 #include <linux/lustre/lustre_ver.h>
+#include <libcfs/util/string.h>
 
 #include "mount_utils.h"
 
@@ -322,52 +323,6 @@ static int erase_param(const char *const buf, const char *const param,
 }
 #endif
 
-/* from mount_lustre */
-/* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
-#define MAXNIDSTR 1024
-static char *convert_hostnames(char *s1)
-{
-       char *converted, *s2 = 0, *c, *end, sep;
-       int left = MAXNIDSTR;
-       lnet_nid_t nid;
-
-       converted = malloc(left);
-       if (!converted)
-               return NULL;
-
-       end = s1 + strlen(s1);
-       c = converted;
-       while ((left > 0) && (s1 < end)) {
-               s2 = strpbrk(s1, ",:");
-               if (!s2)
-                       s2 = end;
-               sep = *s2;
-               *s2 = '\0';
-               nid = libcfs_str2nid(s1);
-               *s2 = sep;
-
-               if (nid == LNET_NID_ANY) {
-                       fprintf(stderr, "%s: Cannot resolve hostname '%s'.\n",
-                               progname, s1);
-                       free(converted);
-                       return NULL;
-               }
-               if (strncmp(libcfs_nid2str(nid), "127.0.0.1",
-                           strlen("127.0.0.1")) == 0) {
-                       fprintf(stderr,
-                               "%s: The NID '%s' resolves to the loopback address '%s'.  Lustre requires a non-loopback address.\n",
-                               progname, s1, libcfs_nid2str(nid));
-                       free(converted);
-                       return NULL;
-               }
-
-               c += snprintf(c, left, "%s%c", libcfs_nid2str(nid), sep);
-               left = converted + MAXNIDSTR - c;
-               s1 = s2 + 1;
-       }
-       return converted;
-}
-
 int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop,
               char **mountopts, char *old_fsname)
 {
@@ -470,7 +425,7 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop,
                                return 1;
                        }
 
-                       nids = convert_hostnames(optarg);
+                       nids = convert_hostnames(optarg, false);
                        if (!nids)
                                return 1;
 
@@ -554,7 +509,7 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop,
                        break;
                }
                case 'm': {
-                       char *nids = convert_hostnames(optarg);
+                       char *nids = convert_hostnames(optarg, false);
 
                        if (!nids)
                                return 1;
index 3ce3ed0..970643a 100644 (file)
@@ -124,44 +124,6 @@ void usage(FILE *out)
        exit((out != stdout) ? EINVAL : 0);
 }
 
-/* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
-#define MAXNIDSTR 1024
-static char *convert_hostnames(char *s1)
-{
-       char *converted, *s2 = 0, *c;
-       char sep;
-       int left = MAXNIDSTR;
-       lnet_nid_t nid;
-
-       converted = malloc(left);
-       if (!converted) {
-               fprintf(stderr, "out of memory: needed %d bytes\n",
-                       MAXNIDSTR);
-               return NULL;
-       }
-       c = converted;
-       while ((left > 0) && (*s1 != '/')) {
-               s2 = strpbrk(s1, ",:");
-               if (!s2)
-                       goto out_free;
-               sep = *s2;
-               *s2 = '\0';
-               nid = libcfs_str2nid(s1);
-               *s2 = sep;                      /* back to original string */
-               if (nid == LNET_NID_ANY)
-                       goto out_free;
-               c += scnprintf(c, left, "%s%c", libcfs_nid2str(nid), sep);
-               left = converted + MAXNIDSTR - c;
-               s1 = s2 + 1;
-       }
-       snprintf(c, left, "%s", s1);
-       return converted;
-out_free:
-       fprintf(stderr, "%s: Can't parse NID '%s'\n", progname, s1);
-       free(converted);
-       return NULL;
-}
-
 /*****************************************************************************
  *
  * This part was cribbed from util-linux/mount/mount.c.  There was no clear
@@ -786,7 +748,7 @@ static int parse_opts(int argc, char *const argv[], struct mount_opts *mop)
 
        ptr = strstr(mop->mo_usource, ":/");
        if (ptr) {
-               mop->mo_source = convert_hostnames(mop->mo_usource);
+               mop->mo_source = convert_hostnames(mop->mo_usource, true);
                if (!mop->mo_source)
                        usage(stderr);
        } else {
index 6ba4e4a..41e8713 100644 (file)
@@ -41,6 +41,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <config.h>
+#include <linux/lnet/nidstr.h>
 #include <linux/lustre/lustre_ver.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
@@ -54,6 +55,7 @@
 #include <sys/types.h>
 #include <sys/xattr.h>
 #include <libmount/libmount.h>
+#include <libcfs/util/string.h>
 
 #ifdef HAVE_GSS
 #ifdef HAVE_LIBKEYUTILS
@@ -943,6 +945,93 @@ int file_create(char *path, __u64 size)
        return 0;
 }
 
+/* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
+#define MAXNIDSTR 1024
+
+char *convert_hostnames(char *s1, bool mount)
+{
+       char *converted, *s2 = 0, *c, *end, sep;
+       int left = MAXNIDSTR;
+       struct lnet_nid nid;
+
+       converted = malloc(left);
+       if (!converted) {
+               fprintf(stderr, "%s: cannot allocate %u bytes for NID: %s\n",
+                       progname, left, strerror(ENOMEM));
+               return NULL;
+       }
+
+       /* end is different between mount and mkfs case */
+       if (mount) {
+               end = strchr(s1, '/');
+               if (!end) {
+                       fprintf(stderr, "%s: Invalid mount string: %s\n",
+                               progname, s1);
+                       return NULL;
+               }
+               end--;
+       } else {
+               end = s1 + strlen(s1);
+       }
+
+       c = converted;
+       while ((left > 0) && (s1 < end)) {
+               int rc;
+
+               /* Needed to skip : in IPv6 / GUID strings. Lustre uses
+                * ':' as a seperator as well which makes this complicated.
+                */
+               s2 = strchr(s1, '@');
+               if (!s2 || s2 > end) {
+                       fprintf(stderr, "%s: Invalid NID string '%s'\n",
+                               progname, s1);
+                       goto out_free;
+               }
+
+               s2 = strpbrk(s2, ",:");
+               if (!s2) {
+                       s2 = end;
+               } else if (s2 > end) {
+                       fprintf(stderr, "%s: Invalid NID string '%s'\n",
+                               progname, s1);
+                       goto out_free;
+               }
+               sep = *s2;
+               *s2 = '\0';
+
+               rc = libcfs_strnid(&nid, s1);
+               if (rc < 0) {
+                       fprintf(stderr, "%s: Unsupported NID '%s': rc = %s.\n",
+                               progname, s1, strerror(rc));
+                       goto out_free;
+               }
+               *s2 = sep;      /* back to original string */
+
+               if (LNET_NID_IS_ANY(&nid)) {
+                       fprintf(stderr, "%s: Cannot resolve hostname '%s'.\n",
+                               progname, s1);
+                       goto out_free;
+               }
+
+               if (sep != '\0')
+                       c += scnprintf(c, left, "%s%c", libcfs_nidstr(&nid),
+                                      sep);
+               else
+                       c += scnprintf(c, left, "%s", libcfs_nidstr(&nid));
+               left = converted + MAXNIDSTR - c;
+               s1 = s2 + 1;
+       }
+
+       if (mount)
+               snprintf(c, left, "%s", s1);
+
+       return converted;
+out_free:
+       fprintf(stderr, "%s: Can't parse NID '%s'\n", progname, s1);
+       free(converted);
+       return NULL;
+}
+
 #ifdef HAVE_SERVER_SUPPORT
 struct lustre_cfg_entry {
        struct list_head lce_list;
index 0acbb59..c51cf1f 100644 (file)
@@ -178,6 +178,7 @@ int update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
 int update_utab_entry(struct mount_opts *mop);
 int check_mountfsoptions(char *mountopts, char *wanted_mountopts);
 void trim_mountfsoptions(char *s);
+char *convert_hostnames(char *s1, bool mount);
 #ifdef HAVE_SERVER_SUPPORT
 __u64 get_device_size(char* device);
 int lustre_rename_fsname(struct mkfs_opts *mop, const char *mntpt,