Whamcloud - gitweb
LU-17367 utils: improved hostname and IPv6 NID support 06/55706/9
authorMaximilian Dilger <mdilger@whamcloud.com>
Thu, 11 Jul 2024 19:07:17 +0000 (15:07 -0400)
committerOleg Drokin <green@whamcloud.com>
Tue, 23 Jul 2024 04:42:34 +0000 (04:42 +0000)
Improved NID parsing to accept hostnames, IPv4 and IPv6 addresses.
IPv6 addresses need @network to be parsed properly. The following
is a valid IPv6 address: "6699:7654::1234:1234:d84@tcp"

All other non IPv6 addresses can be passed in without a network
identifier.

Signed-off-by: Maximilian Dilger <mdilger@whamcloud.com>
Change-Id: I131c8b2d1f7b0fe593564af90308d2d3ea278a0c
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55706
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Mikhail Pershin <mpershin@whamcloud.com>
lustre/tests/conf-sanity.sh
lustre/utils/mount_utils.c
lustre/utils/mount_utils.h

index 76036ce..fd4bd67 100755 (executable)
@@ -11216,6 +11216,83 @@ test_153a() {
 }
 run_test 153a "bypass invalid NIDs quickly"
 
+#LU-17367
+test_153b() {
+       reformat_and_config
+       setupall
+
+       local IPv6_1="6699:7654::1234:1234:d84@tcp"
+       local IPv6_2="2001:0db8:85a3:0000:0000:8a2e:0370:7334@tcp"
+       local IPv6_3="5031:db8:85a3:8d3:1319:8a2e:370:7348@tcp"
+       local IPv4_1="127.0.0.5"
+       local IPv4_2="193.168.0.240@tcp"
+       local IPv4_3="162.32.0.100"
+
+       local mgslist
+
+       umount $MOUNT
+
+       mgslist="$IPv6_1:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$mgs_HOST:$mgs_HOST:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$mgs_HOST:$IPv6_1"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$mgs_HOST:$IPv4_1"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv4_1:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv4_2:$IPv4_1:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv6_1,$IPv4_2,$IPv4_1:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1\
+:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1\
+:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1\
+:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1\
+:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1:$IPv4_1\
+:$IPv4_1:$IPv4_1:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv6_1,$IPv4_2,$IPv4_1:$IPv6_3,$IPv4_3,$IPv6_2:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+
+       mgslist="$IPv4_2,$IPv6_1,$IPv4_2,$IPv4_1:$IPv6_3,$IPv4_3:$IPv6_2\
+,$IPv6_1,$IPv4_2,$IPv4_1:$IPv6_3,$IPv4_3:$IPv6_2,$IPv6_1,$IPv4_2\
+,$IPv4_1:$IPv6_3,$IPv4_3:$IPv6_2,$IPv6_1,$IPv4_2,$IPv4_1:$IPv6_3\
+,$IPv4_3:$IPv6_2,$IPv6_1,$IPv4_2,$IPv4_1:$IPv6_3,$IPv4_3:$IPv6_2\
+:$mgs_HOST"
+       mount -t lustre $mgslist:/$FSNAME $MOUNT ||
+               error "mount failed with $mgslist:/$FSNAME $MOUNT"
+       umount $MOUNT
+}
+run_test 153b "added IPv6 NID support"
+
 test_154() {
        [ "$mds1_FSTYPE" == "ldiskfs" ] || skip "ldiskfs only test"
        (( $MDS1_VERSION >= $(version_code 2.15.63.1) )) ||
index 89842be..cbe2c5f 100644 (file)
@@ -948,11 +948,15 @@ int file_create(char *path, __u64 size)
 /* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
 #define MAXNIDSTR 1024
 
-char *convert_hostnames(char *s1, bool mount)
+char *convert_hostnames(char *buf, bool mount)
 {
-       char *converted, *s2 = 0, *c, *end, sep;
+       char *converted, *c, *end, sep;
+       char *delimiter = buf;
        int left = MAXNIDSTR;
        struct lnet_nid nid;
+       int hex_count = 0;
+       int hex_sections = 0;
+       bool is_ipv6 = true;
 
        converted = malloc(left);
        if (!converted) {
@@ -963,53 +967,75 @@ char *convert_hostnames(char *s1, bool mount)
 
        /* end is different between mount and mkfs case */
        if (mount) {
-               end = strchr(s1, '/');
+               end = strchr(buf, '/');
                if (!end) {
                        fprintf(stderr, "%s: Invalid mount string: %s\n",
-                               progname, s1);
+                               progname, buf);
                        goto out_bad_mnt_str;
                }
                end--;
        } else {
-               end = s1 + strlen(s1);
+               end = buf + strlen(buf);
        }
 
        c = converted;
-       while ((left > 0) && (s1 < end)) {
+       /* parse all NIDs */
+       while ((left > 0) && (delimiter < end)) {
                int rc;
+               hex_count = 0;
+               hex_sections = 0;
+               is_ipv6 = true;
+
+               /* previous delimiter */
+               if (*delimiter == ',' || *delimiter == ':')
+                       delimiter++;
+
+               /* address parsing */
+               while (*delimiter != ',' && *delimiter != ' ' && *delimiter != '\0') {
+                       /* Need to skip : in IPv6 / GUID NIDs. Lustre also uses
+                        * ':' as a separator, which makes this complicated.
+                        */
+                       if (*delimiter == '@') {
+                               while (*delimiter != ':' && *delimiter != ','
+                                   && *delimiter != ' ' && *delimiter != '\0')
+                                       delimiter++;
+                               break;
+                       }
+                       /* IPv6 addresses are in 0-4 hex digit groups */
+                       else if ((isxdigit(*delimiter) || *delimiter == ':') &&
+                                hex_count <= 4 && is_ipv6) {
+                               if (*delimiter == ':') {
+                                       hex_sections++;
+                                       hex_count = 0;
+                               } else {
+                                       hex_count++;
+                               }
+                       } else { /* NID is not IPv6 */
+                               is_ipv6 = false;
+                               if (*delimiter == ':')
+                                       break;
 
-               /* 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;
+                       }
+                       delimiter++;
                }
-               sep = *s2;
-               *s2 = '\0';
+               /* sets the position of the found delimiter to null
+                * temporarily so when we pass it into parse_nid
+                * or parse_net it only uses the found NID
+                */
+               sep = *delimiter;
+               *delimiter = '\0';
 
-               rc = libcfs_strnid(&nid, s1);
+               rc = libcfs_strnid(&nid, buf);
                if (rc < 0) {
                        fprintf(stderr, "%s: Unsupported NID '%s': rc = %s.\n",
-                               progname, s1, strerror(rc));
+                               progname, buf, strerror(rc));
                        goto out_free;
                }
-               *s2 = sep;      /* back to original string */
+               *delimiter = sep;      /* back to original string */
 
                if (LNET_NID_IS_ANY(&nid)) {
                        fprintf(stderr, "%s: Cannot resolve hostname '%s'.\n",
-                               progname, s1);
+                               progname, buf);
                        goto out_free;
                }
 
@@ -1018,16 +1044,17 @@ char *convert_hostnames(char *s1, bool mount)
                                       sep);
                else
                        c += scnprintf(c, left, "%s", libcfs_nidstr(&nid));
+
                left = converted + MAXNIDSTR - c;
-               s1 = s2 + 1;
+               buf = delimiter + 1;
        }
 
        if (mount)
-               snprintf(c, left, "%s", s1);
+               snprintf(c, left, "%s", buf);
 
        return converted;
 out_free:
-       fprintf(stderr, "%s: Can't parse NID '%s'\n", progname, s1);
+       fprintf(stderr, "%s: Can't parse NID '%s'\n", progname, buf);
 out_bad_mnt_str:
        free(converted);
        return NULL;
index c51cf1f..a1d2173 100644 (file)
@@ -178,7 +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);
+char *convert_hostnames(char *buf, bool mount);
 #ifdef HAVE_SERVER_SUPPORT
 __u64 get_device_size(char* device);
 int lustre_rename_fsname(struct mkfs_opts *mop, const char *mntpt,