--- libmultipath/print.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++ libmultipath/print.h | 61 ++++++++++++ multipathd/cli.c | 3 multipathd/cli.h | 2 multipathd/cli_handlers.c | 93 +++++++++++++++++++ multipathd/cli_handlers.h | 2 multipathd/main.c | 2 multipathd/multipathd.8 | 9 + 8 files changed, 393 insertions(+), 1 deletion(-) Index: multipath-tools-130222/libmultipath/print.c =================================================================== --- multipath-tools-130222.orig/libmultipath/print.c +++ multipath-tools-130222/libmultipath/print.c @@ -269,6 +269,61 @@ snprint_multipath_vpr (char * buff, size pp->vendor_id, pp->product_id); } + +static int +snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp) +{ + struct pathgroup * pgp; + struct path * pp; + int i, j; + + vector_foreach_slot(mpp->pg, pgp, i) { + if (!pgp) + continue; + vector_foreach_slot(pgp->paths, pp, j) { + if (strlen(pp->vendor_id)) + return snprintf(buff, len, "%s", pp->vendor_id); + } + } + return snprintf(buff, len, "##"); +} + +static int +snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp) +{ + struct pathgroup * pgp; + struct path * pp; + int i, j; + + vector_foreach_slot(mpp->pg, pgp, i) { + if (!pgp) + continue; + vector_foreach_slot(pgp->paths, pp, j) { + if (strlen(pp->product_id)) + return snprintf(buff, len, "%s", pp->product_id); + } + } + return snprintf(buff, len, "##"); +} + +static int +snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp) +{ + struct pathgroup * pgp; + struct path * pp; + int i, j; + + vector_foreach_slot(mpp->pg, pgp, i) { + if (!pgp) + continue; + vector_foreach_slot(pgp->paths, pp, j) { + if (strlen(pp->rev)) + return snprintf(buff, len, "%s", pp->rev); + } + } + return snprintf(buff, len, "##"); +} + static int snprint_action (char * buff, size_t len, struct multipath * mpp) { @@ -561,6 +616,9 @@ struct multipath_data mpd[] = { {'3', "total_q_time", 0, snprint_total_q_time}, {'4', "q_timeouts", 0, snprint_q_timeouts}, {'s', "vend/prod/rev", 0, snprint_multipath_vpr}, + {'v', "vend", 0, snprint_multipath_vend}, + {'p', "prod", 0, snprint_multipath_prod}, + {'e', "rev", 0, snprint_multipath_rev}, {0, NULL, 0 , NULL} }; @@ -983,6 +1041,170 @@ snprint_multipath_topology (char * buff, return fwd; } +static int +snprint_json (char * buff, int len, int indent, char *json_str) +{ + int fwd = 0, i; + + for (i = 0; i < indent; i++) { + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); + if (fwd > len) + return fwd; + } + + fwd += snprintf(buff + fwd, len - fwd, "%s", json_str); + return fwd; +} + +static int +snprint_json_header (char * buff, int len) +{ + int fwd = 0; + + fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM); + if (fwd > len) + return fwd; + + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION, + PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION); + return fwd; +} + +static int +snprint_json_elem_footer (char * buff, int len, int indent, int last) +{ + int fwd = 0, i; + + for (i = 0; i < indent; i++) { + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); + if (fwd > len) + return fwd; + } + + if (last == 1) + fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM); + else + fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM); + return fwd; +} + +static int +snprint_multipath_fields_json (char * buff, int len, + struct multipath * mpp, int last) +{ + int i, j, fwd = 0; + struct path *pp; + struct pathgroup *pgp; + + fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0); + if (fwd > len) + return fwd; + + fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS); + if (fwd > len) + return fwd; + + vector_foreach_slot (mpp->pg, pgp, i) { + + pgp->selector = mpp->selector; + fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp); + if (fwd > len) + return fwd; + + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1); + if (fwd > len) + return fwd; + + fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS); + if (fwd > len) + return fwd; + + vector_foreach_slot (pgp->paths, pp, j) { + fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0); + if (fwd > len) + return fwd; + + fwd += snprint_json_elem_footer(buff + fwd, + len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths)); + if (fwd > len) + return fwd; + } + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); + if (fwd > len) + return fwd; + + fwd += snprint_json_elem_footer(buff + fwd, + len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg)); + if (fwd > len) + return fwd; + } + + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); + if (fwd > len) + return fwd; + + fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last); + return fwd; +} + +int +snprint_multipath_map_json (char * buff, int len, + struct multipath * mpp, int last){ + int fwd = 0; + + fwd += snprint_json_header(buff, len); + if (fwd > len) + return len; + + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP); + if (fwd > len) + return len; + + fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1); + if (fwd > len) + return len; + + fwd += snprint_json(buff + fwd, len - fwd, 0, "\n"); + if (fwd > len) + return len; + + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); + if (fwd > len) + return len; + return fwd; +} + +int +snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs) +{ + int i, fwd = 0; + struct multipath * mpp; + + fwd += snprint_json_header(buff, len); + if (fwd > len) + return len; + + fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS); + if (fwd > len) + return len; + + vector_foreach_slot(vecs->mpvec, mpp, i) { + fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, + mpp, i + 1 == VECTOR_SIZE(vecs->mpvec)); + if (fwd > len) + return len; + } + + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); + if (fwd > len) + return len; + + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); + if (fwd > len) + return len; + return fwd; +} + static int snprint_hwentry (char * buff, int len, struct hwentry * hwe) { Index: multipath-tools-130222/libmultipath/print.h =================================================================== --- multipath-tools-130222.orig/libmultipath/print.h +++ multipath-tools-130222/libmultipath/print.h @@ -7,6 +7,63 @@ #define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r" #define PRINT_PG_INDENT "policy='%s' prio=%p status=%t" +#define PRINT_JSON_MULTIPLIER 5 +#define PRINT_JSON_MAJOR_VERSION 0 +#define PRINT_JSON_MINOR_VERSION 1 +#define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \ + " \"minor_version\": %d,\n" +#define PRINT_JSON_START_ELEM "{\n" +#define PRINT_JSON_START_MAP " \"map\":" +#define PRINT_JSON_START_MAPS "\"maps\": [" +#define PRINT_JSON_START_PATHS "\"paths\": [" +#define PRINT_JSON_START_GROUPS "\"path_groups\": [" +#define PRINT_JSON_END_ELEM "}," +#define PRINT_JSON_END_LAST_ELEM "}" +#define PRINT_JSON_END_LAST "}\n" +#define PRINT_JSON_END_ARRAY "]\n" +#define PRINT_JSON_INDENT " " +#define PRINT_JSON_MAP "{\n" \ + " \"name\" : \"%n\",\n" \ + " \"uuid\" : \"%w\",\n" \ + " \"sysfs\" : \"%d\",\n" \ + " \"failback\" : \"%F\",\n" \ + " \"queueing\" : \"%Q\",\n" \ + " \"paths\" : %N,\n" \ + " \"write_prot\" : \"%r\",\n" \ + " \"dm_st\" : \"%t\",\n" \ + " \"features\" : \"%f\",\n" \ + " \"hwhandler\" : \"%h\",\n" \ + " \"action\" : \"%A\",\n" \ + " \"path_faults\" : %0,\n" \ + " \"vend\" : \"%v\",\n" \ + " \"prod\" : \"%p\",\n" \ + " \"rev\" : \"%e\",\n" \ + " \"switch_grp\" : %1,\n" \ + " \"map_loads\" : %2,\n" \ + " \"total_q_time\" : %3,\n" \ + " \"q_timeouts\" : %4," + +#define PRINT_JSON_GROUP "{\n" \ + " \"selector\" : \"%s\",\n" \ + " \"pri\" : %p,\n" \ + " \"dm_st\" : \"%t\"," + +#define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n" + +#define PRINT_JSON_PATH "{\n" \ + " \"dev\" : \"%d\",\n"\ + " \"dev_t\" : \"%D\",\n" \ + " \"dm_st\" : \"%t\",\n" \ + " \"dev_st\" : \"%o\",\n" \ + " \"chk_st\" : \"%T\",\n" \ + " \"checker\" : \"%c\",\n" \ + " \"pri\" : %p,\n" \ + " \"host_wwnn\" : \"%N\",\n" \ + " \"target_wwnn\" : \"%n\",\n" \ + " \"host_wwpn\" : \"%R\",\n" \ + " \"target_wwpn\" : \"%r\",\n" \ + " \"host_adapter\" : \"%a\"" + #define MAX_LINE_LEN 80 #define MAX_LINES 64 #define MAX_FIELD_LEN 64 @@ -41,6 +98,10 @@ int snprint_path (char *, int, char *, s int snprint_multipath (char *, int, char *, struct multipath *, int); int snprint_multipath_topology (char *, int, struct multipath * mpp, int verbosity); +int snprint_multipath_topology_json (char * buff, int len, + struct vectors * vecs); +int snprint_multipath_map_json (char * buff, int len, + struct multipath * mpp, int last); int snprint_defaults (char *, int); int snprint_blacklist (char *, int); int snprint_blacklist_except (char *, int); Index: multipath-tools-130222/multipathd/cli.c =================================================================== --- multipath-tools-130222.orig/multipathd/cli.c +++ multipath-tools-130222/multipathd/cli.c @@ -189,6 +189,7 @@ load_keys (void) r += add_key(keys, "setprstatus", SETPRSTATUS, 0); r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0); r += add_key(keys, "format", FMT, 1); + r += add_key(keys, "json", JSON, 0); if (r) { free_keys(keys); @@ -473,8 +474,10 @@ cli_init (void) { add_handler(LIST+MAPS+FMT, NULL); add_handler(LIST+MAPS+RAW+FMT, NULL); add_handler(LIST+MAPS+TOPOLOGY, NULL); + add_handler(LIST+MAPS+JSON, NULL); add_handler(LIST+TOPOLOGY, NULL); add_handler(LIST+MAP+TOPOLOGY, NULL); + add_handler(LIST+MAP+JSON, NULL); add_handler(LIST+CONFIG, NULL); add_handler(LIST+BLACKLIST, NULL); add_handler(LIST+DEVICES, NULL); Index: multipath-tools-130222/multipathd/cli.h =================================================================== --- multipath-tools-130222.orig/multipathd/cli.h +++ multipath-tools-130222/multipathd/cli.h @@ -36,6 +36,7 @@ enum { __SETPRSTATUS, __UNSETPRSTATUS, __FMT, + __JSON, }; #define LIST (1 << __LIST) @@ -74,6 +75,7 @@ enum { #define SETPRSTATUS (1ULL << __SETPRSTATUS) #define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) #define FMT (1ULL << __FMT) +#define JSON (1ULL << __JSON) #define INITIAL_REPLY_LEN 1200 Index: multipath-tools-130222/multipathd/cli_handlers.c =================================================================== --- multipath-tools-130222.orig/multipathd/cli_handlers.c +++ multipath-tools-130222/multipathd/cli_handlers.c @@ -127,6 +127,70 @@ show_maps_topology (char ** r, int * len } int +show_maps_json (char ** r, int * len, struct vectors * vecs) +{ + int i; + struct multipath * mpp; + char * c; + char * reply; + unsigned int maxlen = INITIAL_REPLY_LEN * + PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec); + int again = 1; + + vector_foreach_slot(vecs->mpvec, mpp, i) { + if (update_multipath(vecs, mpp->alias, 0)) { + return 1; + } + } + + reply = MALLOC(maxlen); + + while (again) { + if (!reply) + return 1; + + c = reply; + + c += snprint_multipath_topology_json(c, maxlen, vecs); + again = ((c - reply) == maxlen); + + REALLOC_REPLY(reply, again, maxlen); + } + *r = reply; + *len = (int)(c - reply); + return 0; +} + +int +show_map_json (char ** r, int * len, struct multipath * mpp, + struct vectors * vecs) +{ + char * c; + char * reply; + unsigned int maxlen = INITIAL_REPLY_LEN; + int again = 1; + + if (update_multipath(vecs, mpp->alias, 0)) + return 1; + reply = MALLOC(maxlen); + + while (again) { + if (!reply) + return 1; + + c = reply; + + c += snprint_multipath_map_json(c, maxlen, mpp, 1); + again = ((c - reply) == maxlen); + + REALLOC_REPLY(reply, again, maxlen); + } + *r = reply; + *len = (int)(c - reply); + return 0; +} + +int show_config (char ** r, int * len) { char * c; @@ -239,6 +303,35 @@ cli_list_maps_topology (void * v, char * } int +cli_list_map_json (void * v, char ** reply, int * len, void * data) +{ + struct multipath * mpp; + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); + + param = convert_dev(param, 0); + get_path_layout(vecs->pathvec, 0); + mpp = find_mp_by_str(vecs->mpvec, param); + + if (!mpp) + return 1; + + condlog(3, "list multipath json %s (operator)", param); + + return show_map_json(reply, len, mpp, vecs); +} + +int +cli_list_maps_json (void * v, char ** reply, int * len, void * data) +{ + struct vectors * vecs = (struct vectors *)data; + + condlog(3, "list multipaths json (operator)"); + + return show_maps_json(reply, len, vecs); +} + +int cli_list_wildcards (void * v, char ** reply, int * len, void * data) { char * c; Index: multipath-tools-130222/multipathd/cli_handlers.h =================================================================== --- multipath-tools-130222.orig/multipathd/cli_handlers.h +++ multipath-tools-130222/multipathd/cli_handlers.h @@ -10,6 +10,8 @@ int cli_list_maps_status (void * v, char int cli_list_maps_stats (void * v, char ** reply, int * len, void * data); int cli_list_map_topology (void * v, char ** reply, int * len, void * data); int cli_list_maps_topology (void * v, char ** reply, int * len, void * data); +int cli_list_map_json (void * v, char ** reply, int * len, void * data); +int cli_list_maps_json (void * v, char ** reply, int * len, void * data); int cli_list_config (void * v, char ** reply, int * len, void * data); int cli_list_blacklist (void * v, char ** reply, int * len, void * data); int cli_list_devices (void * v, char ** reply, int * len, void * data); Index: multipath-tools-130222/multipathd/main.c =================================================================== --- multipath-tools-130222.orig/multipathd/main.c +++ multipath-tools-130222/multipathd/main.c @@ -981,7 +981,9 @@ uxlsnrloop (void * ap) set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw); set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology); set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology); + set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json); set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology); + set_handler_callback(LIST+MAP+JSON, cli_list_map_json); set_handler_callback(LIST+CONFIG, cli_list_config); set_handler_callback(LIST+BLACKLIST, cli_list_blacklist); set_handler_callback(LIST+DEVICES, cli_list_devices); Index: multipath-tools-130222/multipathd/multipathd.8 =================================================================== --- multipath-tools-130222.orig/multipathd/multipathd.8 +++ multipath-tools-130222/multipathd/multipathd.8 @@ -53,11 +53,15 @@ using a format string with multipath for Show the status of all multipath devices that the multipathd is monitoring. .TP .B list|show maps|multipaths stats -Show some statistics of all multipath devices that the multipathd is monitoring. +Show some statistics of all multipath devices that multipathd is monitoring. .TP .B list|show maps|multipaths topology Show the current multipath topology. Same as "multipath \-ll". .TP +.B list|show maps|multipaths json +Show the multipath devices that multipathd is monitoring, using JSON +formatted output. +.TP .B list|show topology Show the current multipath topology. Same as "multipath \-ll". .TP @@ -65,6 +69,9 @@ Show the current multipath topology. Sam Show topology of a single multipath device specified by $map, e.g. 36005076303ffc56200000000000010aa. This map could be obtained from "list maps". .TP +.B list|show map|multipath $map json +Show a single multipath device specified by $map, using JSON formatted output. +.TP .B list|show wildcards Show the format wildcards used in interactive commands taking $format .TP