Whamcloud - gitweb
LU-10003 lnet: Update lctl ping to work with large NIDs
[fs/lustre-release.git] / lustre / utils / portals.c
index 6be4c15..c29c334 100644 (file)
@@ -32,6 +32,9 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <time.h>
 #include <linux/types.h>
 
@@ -97,31 +100,6 @@ lnet_parse_port(int *port, char *str)
        return -1;
 }
 
-#ifdef HAVE_GETHOSTBYNAME
-static struct hostent *
-ptl_gethostbyname(char *hname)
-{
-       struct hostent *he;
-
-       he = gethostbyname(hname);
-       if (!he) {
-               switch (h_errno) {
-               case HOST_NOT_FOUND:
-               case NO_ADDRESS:
-                       fprintf(stderr, "Unable to resolve hostname: %s\n",
-                               hname);
-                       break;
-               default:
-                       fprintf(stderr, "gethostbyname error for %s: %s\n",
-                               hname, strerror(h_errno));
-                       break;
-               }
-               return NULL;
-       }
-       return he;
-}
-#endif
-
 int
 lnet_parse_ipquad(__u32 *ipaddrp, char *str)
 {
@@ -141,9 +119,11 @@ lnet_parse_ipquad(__u32 *ipaddrp, char *str)
 int
 lnet_parse_ipaddr(__u32 *ipaddrp, char *str)
 {
-#ifdef HAVE_GETHOSTBYNAME
-       struct hostent *he;
-#endif
+       struct addrinfo *ai = NULL;
+       struct addrinfo *aip = NULL;
+       struct addrinfo hints;
+       int err = 0;
+       int rc = -1;
 
        if (!strcmp(str, "_all_")) {
                *ipaddrp = 0;
@@ -153,40 +133,67 @@ lnet_parse_ipaddr(__u32 *ipaddrp, char *str)
        if (lnet_parse_ipquad(ipaddrp, str) == 0)
                return 0;
 
-#ifdef HAVE_GETHOSTBYNAME
-       if ((('a' <= str[0] && str[0] <= 'z') ||
-            ('A' <= str[0] && str[0] <= 'Z')) &&
-             (he = ptl_gethostbyname(str)) != NULL) {
-               __u32 addr = *(__u32 *)he->h_addr;
+       memset(&hints, 0, sizeof(struct addrinfo));
+       hints.ai_family = AF_INET;
 
-               *ipaddrp = ntohl(addr);         /* HOST byte order */
-               return 0;
+       if (('a' <= str[0] && str[0] <= 'z') ||
+           ('A' <= str[0] && str[0] <= 'Z')) {
+               err = getaddrinfo(str, NULL, &hints, &ai);
+               if (err != 0) {
+                       fprintf(stderr,
+                               "failed to get addrinfo for %s: %s\n",
+                               str, gai_strerror(err));
+                       return -1;
+               }
+
+               for (aip = ai; aip; aip = aip->ai_next) {
+                       if (aip->ai_family == AF_INET && aip->ai_addr) {
+                               struct sockaddr_in *sin =
+                                       (void *)ai->ai_addr;
+
+                               __u32 addr = (__u32)sin->sin_addr.s_addr;
+                               *ipaddrp = ntohl(addr);
+                               break;
+                       }
+               }
+               /* FIXME: handle AF_INET6 */
+
+               if (!aip) {
+                       fprintf(stderr, "failed to get IP address for %s\n",
+                               str);
+                       rc = -1;
+                       goto out;
+               }
+
+               rc = 0;
+               goto out;
        }
-#endif
 
-       return -1;
+out:
+       if (ai != NULL)
+               freeaddrinfo(ai);
+       return rc;
 }
 
 char *
 ptl_ipaddr_2_str(__u32 ipaddr, char *str, size_t strsize, int lookup)
 {
-#ifdef HAVE_GETHOSTBYNAME
-       __u32 net_ip;
-       struct hostent *he;
+       struct sockaddr_in srcaddr;
 
        if (lookup) {
-               net_ip = htonl(ipaddr);
-               he = gethostbyaddr(&net_ip, sizeof(net_ip), AF_INET);
-               if (he) {
-                       snprintf(str, strsize, "%s", he->h_name);
-                       return str;
-               }
+               memset(&srcaddr, 0, sizeof(srcaddr));
+               srcaddr.sin_family = AF_INET;
+               srcaddr.sin_addr.s_addr = (in_addr_t)htonl(ipaddr);
+
+               if (getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr),
+                                 str, strsize, NULL, 0, 0) == 0)
+                       goto out;
        }
-#endif
 
-       sprintf(str, "%d.%d.%d.%d",
-               (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff,
-               (ipaddr >> 8) & 0xff, ipaddr & 0xff);
+       snprintf(str, strsize, "%d.%d.%d.%d",
+                (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff,
+                (ipaddr >> 8) & 0xff, ipaddr & 0xff);
+out:
        return str;
 }
 
@@ -220,12 +227,12 @@ lnet_parse_time(time_t *t, char *str)
 }
 
 int
-lnet_parse_nid(char *nid_str, struct lnet_process_id *id_ptr)
+lnet_parse_nid(char *nid_str, struct lnet_processid *id_ptr)
 {
        id_ptr->pid = LNET_PID_ANY;
-       id_ptr->nid = libcfs_str2nid(nid_str);
-       if (id_ptr->nid == LNET_NID_ANY) {
-               fprintf(stderr, "Can't parse nid \"%s\"\n", nid_str);
+       if (libcfs_strnid(&id_ptr->nid, nid_str) < 0 ||
+           LNET_NID_IS_ANY(&id_ptr->nid)) {
+               fprintf(stderr, "Invalid NID argument \"%s\"\n", nid_str);
                return -1;
        }
 
@@ -577,13 +584,16 @@ old_api: {
 int
 jt_ptl_which_nid(int argc, char **argv)
 {
-       struct libcfs_ioctl_data data;
+       struct lnet_nid best_nid = LNET_ANY_NID;
+       yaml_emitter_t request;
+       yaml_parser_t reply;
+       yaml_event_t event;
+       struct nl_sock *sk;
        int best_dist = 0;
        int best_order = 0;
-       lnet_nid_t   best_nid = LNET_NID_ANY;
-       int dist;
-       int order;
-       lnet_nid_t nid;
+       bool done = false;
+       int dist = 0;
+       int order = 0;
        char *nidstr;
        int rc;
        int i;
@@ -593,16 +603,188 @@ jt_ptl_which_nid(int argc, char **argv)
                return 0;
        }
 
+       /* Create Netlink emitter to send request to kernel */
+       sk = nl_socket_alloc();
+       if (!sk)
+               goto old_api;
+
+       /* Setup parser to recieve Netlink packets */
+       rc = yaml_parser_initialize(&reply);
+       if (rc == 0)
+               goto old_api;
+
+       rc = yaml_parser_set_input_netlink(&reply, sk, false);
+       if (rc == 0)
+               goto free_reply;
+
+       /* Create Netlink emitter to send request to kernel */
+       rc = yaml_emitter_initialize(&request);
+       if (rc == 0)
+               goto free_reply;
+
+       rc = yaml_emitter_set_output_netlink(&request, sk, LNET_GENL_NAME,
+                                            LNET_GENL_VERSION,
+                                            LNET_CMD_PEER_DIST, NLM_F_DUMP);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_emitter_open(&request);
+       yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_mapping_start_event_initialize(&event, NULL,
+                                           (yaml_char_t *)YAML_MAP_TAG,
+                                           1, YAML_ANY_MAPPING_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_scalar_event_initialize(&event, NULL,
+                                    (yaml_char_t *)YAML_STR_TAG,
+                                    (yaml_char_t *)"peer",
+                                    strlen("peer"), 1, 0,
+                                    YAML_PLAIN_SCALAR_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_sequence_start_event_initialize(&event, NULL,
+                                            (yaml_char_t *)YAML_SEQ_TAG,
+                                            1, YAML_BLOCK_SEQUENCE_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       for (i = 1; i < argc; i++) {
+               struct lnet_nid nid;
+
+               nidstr = argv[i];
+               if (strcmp(nidstr, "*") == 0)
+                       nidstr = "<?>";
+
+               rc = libcfs_strnid(&nid, nidstr);
+               if (rc < 0 || nid_same(&nid, &LNET_ANY_NID)) {
+                       fprintf(stderr, "Can't parse NID %s\n", nidstr);
+                       return -1;
+               }
+
+               yaml_scalar_event_initialize(&event, NULL,
+                                            (yaml_char_t *)YAML_STR_TAG,
+                                            (yaml_char_t *)nidstr,
+                                            strlen(nidstr), 1, 0,
+                                            YAML_PLAIN_SCALAR_STYLE);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto emitter_error;
+       }
+
+       yaml_sequence_end_event_initialize(&event);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_mapping_end_event_initialize(&event);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       yaml_document_end_event_initialize(&event, 0);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto emitter_error;
+
+       rc = yaml_emitter_close(&request);
+emitter_error:
+       if (rc == 0) {
+               yaml_emitter_log_error(&request, stderr);
+               rc = -EINVAL;
+       }
+       yaml_emitter_delete(&request);
+
+       while (!done) {
+               rc = yaml_parser_parse(&reply, &event);
+               if (rc == 0)
+                       break;
+
+               if (event.type != YAML_SCALAR_EVENT)
+                       goto not_scalar;
+
+
+               if (strcmp((char *)event.data.scalar.value, "nid") == 0) {
+                       yaml_event_delete(&event);
+                       rc = yaml_parser_parse(&reply, &event);
+                       if (rc == 0) {
+                               yaml_event_delete(&event);
+                               break;
+                       }
+
+                       nidstr = (char *)event.data.scalar.value;
+
+                       if (nid_same(&best_nid, &LNET_ANY_NID) ||
+                           dist < best_dist ||
+                           (dist == best_dist && order < best_order)) {
+                               best_dist = dist;
+                               best_order = order;
+                               libcfs_strnid(&best_nid, nidstr);
+                       }
+               } else if (strcmp((char *)event.data.scalar.value,
+                                 "distance") == 0) {
+                       yaml_event_delete(&event);
+                       rc = yaml_parser_parse(&reply, &event);
+                       if (rc == 0) {
+                               yaml_event_delete(&event);
+                               break;
+                       }
+
+                       dist = strtol((char *)event.data.scalar.value, NULL, 10);
+               } else if (strcmp((char *)event.data.scalar.value,
+                                 "order") == 0) {
+                       yaml_event_delete(&event);
+                       rc = yaml_parser_parse(&reply, &event);
+                       if (rc == 0) {
+                               yaml_event_delete(&event);
+                               break;
+                       }
+
+                       order = strtol((char *)event.data.scalar.value, NULL, 10);
+               }
+not_scalar:
+               done = (event.type == YAML_STREAM_END_EVENT);
+               yaml_event_delete(&event);
+       }
+
+free_reply:
+       if (rc == 0) {
+               /* yaml_* functions return 0 for error */
+               const char *msg = yaml_parser_get_reader_error(&reply);
+
+               fprintf(stderr, "Unexpected distance: %s\n", msg);
+               rc = -1;
+       } else if (rc == 1) {
+               /* yaml_* functions return 1 for success */
+               rc = 0;
+       }
+
+       yaml_parser_delete(&reply);
+       nl_socket_free(sk);
+       goto finished;
+
+old_api:
        for (i = 1; i < argc; i++) {
+               struct libcfs_ioctl_data data;
+               lnet_nid_t nid4;
+
                nidstr = argv[i];
-               nid = libcfs_str2nid(nidstr);
-               if (nid == LNET_NID_ANY) {
+               nid4 = libcfs_str2nid(nidstr);
+               if (nid4 == LNET_NID_ANY) {
                        fprintf(stderr, "Can't parse NID %s\n", nidstr);
                        return -1;
                }
 
                LIBCFS_IOC_INIT(data);
-               data.ioc_nid = nid;
+               data.ioc_nid = nid4;
 
                rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNET_DIST, &data);
                if (rc != 0) {
@@ -623,21 +805,21 @@ jt_ptl_which_nid(int argc, char **argv)
                        return -1;
                }
 
-               if (best_nid == LNET_NID_ANY ||
+               if (nid_same(&best_nid, &LNET_ANY_NID) ||
                    dist < best_dist ||
                    (dist == best_dist && order < best_order)) {
                        best_dist = dist;
                        best_order = order;
-                       best_nid = nid;
+                       lnet_nid4_to_nid(nid4, &best_nid);
                }
        }
-
-       if (best_nid == LNET_NID_ANY) {
+finished:
+       if (nid_same(&best_nid, &LNET_ANY_NID)) {
                fprintf(stderr, "No reachable NID\n");
                return -1;
        }
 
-       printf("%s\n", libcfs_nid2str(best_nid));
+       printf("%s\n", libcfs_nidstr(&best_nid));
        return 0;
 }
 
@@ -1091,7 +1273,7 @@ int jt_ptl_ping(int argc, char **argv)
        bool done = false, print = true;
        int rc;
        int timeout;
-       struct lnet_process_id id;
+       struct lnet_processid id;
        yaml_emitter_t request;
        yaml_parser_t reply;
        yaml_event_t event;
@@ -1122,11 +1304,10 @@ int jt_ptl_ping(int argc, char **argv)
                        if (rc != 0)
                                return -EINVAL;
                } else {
-                       id.nid = libcfs_str2nid(sep + 1);
-
-                       if (id.nid == LNET_NID_ANY) {
+                       if (libcfs_strnid(&id.nid, (sep + 1)) < 0 ||
+                           LNET_NID_IS_ANY(&id.nid)) {
                                fprintf(stderr,
-                                       "Can't parse process id \"%s\"\n",
+                                       "Invalid PID argument \"%s\"\n",
                                        argv[1]);
                                return -EINVAL;
                        }
@@ -1237,8 +1418,8 @@ int jt_ptl_ping(int argc, char **argv)
        /* convert NID to string, in case libcfs_str2nid() did name lookup */
        yaml_scalar_event_initialize(&event, NULL,
                                     (yaml_char_t *)YAML_STR_TAG,
-                                    (yaml_char_t *)libcfs_nid2str(id.nid),
-                                    strlen(libcfs_nid2str(id.nid)), 1, 0,
+                                    (yaml_char_t *)libcfs_nidstr(&id.nid),
+                                    strlen(libcfs_nidstr(&id.nid)), 1, 0,
                                     YAML_PLAIN_SCALAR_STYLE);
        rc = yaml_emitter_emit(&request, &event);
        if (rc == 0)
@@ -1345,7 +1526,7 @@ old_api:
 
        LIBCFS_IOC_INIT_V2(ping, ping_hdr);
        ping.ping_hdr.ioc_len = sizeof(ping);
-       ping.ping_id = id;
+       ping.ping_id = lnet_pid_to_pid4(&id);
        ping.ping_src = LNET_NID_ANY;
        ping.op_param = timeout;
        ping.ping_count = maxids;