:p
atchew
Login
With this series, the command 'ip [-t[s]] mptcp monitor' produces an output with the JSON format. - Patch 1: a small refactoring to uniform the code. - Patch 2: add JSON support in print_timestamp() helper. - Patch 3: add JSON support to 'ip mptcp monitor' as requested by Stephen. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- Matthieu Baerts (NGI0) (3): mptcp: uniform stream closure utils: timestamp: add JSON support mptcp: monitor: add JSON support ip/ipmptcp.c | 96 +++++++++++++++++++++++++++++++++++++++++------------------- lib/utils.c | 19 ++++++++---- 2 files changed, 80 insertions(+), 35 deletions(-) --- base-commit: f120cdb35da76ca99932d0428a0917bd01a843da change-id: 20260220-ipr-monitor-json-1573371524c1 Best regards, -- Matthieu Baerts (NGI0) <matttbe@kernel.org>
Use print_nl() instead of print_string(), close the json object, then flush the stream to flush the end of the JSON object ASAP. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- ip/ipmptcp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c index XXXXXXX..XXXXXXX 100644 --- a/ip/ipmptcp.c +++ b/ip/ipmptcp.c @@ -XXX,XX +XXX,XX @@ static int print_mptcp_addrinfo(struct rtattr *addrinfo) } } + print_nl(); close_json_object(); - print_string(PRINT_FP, NULL, "\n", NULL); fflush(stdout); return 0; @@ -XXX,XX +XXX,XX @@ static int print_mptcp_limit(struct nlmsghdr *n, void *arg) print_uint(PRINT_ANY, "subflows", "subflows %d ", val); } - print_string(PRINT_FP, NULL, "%s", "\n"); - fflush(stdout); + + print_nl(); close_json_object(); + fflush(stdout); + return 0; } -- 2.51.0
Only if the output stream is 'stdout', because all JSON helpers like print_string() only write on 'stdout'. Supporting JSON is easy with the helpers. The biggest modification is to extract the end value. No behavioural changes intended for the moment, this is a preparation for a future usage of print_timestamp() within a JSON context. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- lib/utils.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index XXXXXXX..XXXXXXX 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -XXX,XX +XXX,XX @@ int print_timestamp(FILE *fp) { struct timeval tv; struct tm *tm; + char ts[40]; gettimeofday(&tv, NULL); tm = localtime(&tv.tv_sec); if (timestamp_short) { - char tshort[40]; + size_t len; - strftime(tshort, sizeof(tshort), "%Y-%m-%dT%H:%M:%S", tm); - fprintf(fp, "[%s.%06ld] ", tshort, tv.tv_usec); + len = strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tm); + snprintf(ts + len, sizeof(ts) - len, ".%06ld", tv.tv_usec); + if (fp == stdout) + print_string(PRINT_ANY, "timestamp_short", "[%s] ", ts); + else + fprintf(fp, "[%s] ", ts); } else { char *tstr = asctime(tm); tstr[strlen(tstr)-1] = 0; - fprintf(fp, "Timestamp: %s %ld usec\n", - tstr, tv.tv_usec); + snprintf(ts, sizeof(ts), "%s %ld usec", tstr, tv.tv_usec); + if (fp == stdout) + print_string(PRINT_ANY, "timestamp", + "Timestamp: %s\n", ts); + else + fprintf(fp, "Timestamp: %s\n", ts); } return 0; -- 2.51.0
The command 'ip [-t[s]] mptcp monitor' now produces an output with the JSON format. The previous text output has been preserved. The JSON support has been added thanks to the print_*() helpers. Note that it is also needed to add a signal handler to close the JSON and print the final ']' when stopping 'ip mptcp monitor' which can only be done via a SIGINT or a SIGTERM. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- ip/ipmptcp.c | 88 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c index XXXXXXX..XXXXXXX 100644 --- a/ip/ipmptcp.c +++ b/ip/ipmptcp.c @@ -XXX,XX +XXX,XX @@ #include <arpa/inet.h> #include <netinet/in.h> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -XXX,XX +XXX,XX @@ static void print_addr(const char *key, int af, struct rtattr *value) char str[INET6_ADDRSTRLEN]; if (inet_ntop(af, data, str, sizeof(str))) { - printf(" %s=", key); - color_fprintf(stdout, ifa_family_color(af), "%s", str); + print_string(PRINT_FP, NULL, " %s=", key); + print_color_string(PRINT_ANY, ifa_family_color(af), key, "%s", + str); } } @@ -XXX,XX +XXX,XX @@ static void print_iface(int index) { const char *ifname; - printf(" ifindex=%d", index); + print_int(PRINT_ANY, "ifindex", " ifindex=%d", index); ifname = index ? ll_index_to_name(index) : NULL; if (ifname) { - printf(" dev="); - color_fprintf(stdout, COLOR_IFNAME, "%s", ifname); + print_string(PRINT_FP, NULL, " dev=", NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, "dev", "%s", + ifname); } } @@ -XXX,XX +XXX,XX @@ static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl, if (n->nlmsg_type != genl_family) return 0; + open_json_object(NULL); + if (timestamp) print_timestamp(stdout); - if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) { - printf("[UNKNOWN %u]\n", ghdr->cmd); + if (ghdr->cmd >= ARRAY_SIZE(event_to_str) || + event_to_str[ghdr->cmd] == NULL) { + char event[40]; + + snprintf(event, sizeof(event), "UNKNOWN %u", ghdr->cmd); + print_string(PRINT_ANY, "event", "[%s]", event); goto out; } - if (event_to_str[ghdr->cmd] == NULL) { - printf("[UNKNOWN %u]\n", ghdr->cmd); - goto out; - } - - printf("[%16s]", event_to_str[ghdr->cmd]); + print_string(PRINT_ANY, "event", "[%16s]", event_to_str[ghdr->cmd]); parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); if (tb[MPTCP_ATTR_TOKEN]) - printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN])); + print_uint(PRINT_ANY, "token"," token=%08x", + rta_getattr_u32(tb[MPTCP_ATTR_TOKEN])); if (tb[MPTCP_ATTR_REM_ID]) - printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID])); + print_uint(PRINT_ANY, "remid", " remid=%u", + rta_getattr_u8(tb[MPTCP_ATTR_REM_ID])); if (tb[MPTCP_ATTR_LOC_ID]) - printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID])); + print_uint(PRINT_ANY, "locid", " locid=%u", + rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID])); if (tb[MPTCP_ATTR_SADDR4]) print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]); @@ -XXX,XX +XXX,XX @@ static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl, if (tb[MPTCP_ATTR_DADDR6]) print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]); if (tb[MPTCP_ATTR_SPORT]) - printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT])); + print_uint(PRINT_ANY, "sport", " sport=%u", + rta_getattr_be16(tb[MPTCP_ATTR_SPORT])); if (tb[MPTCP_ATTR_DPORT]) - printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT])); + print_uint(PRINT_ANY, "dport", " dport=%u", + rta_getattr_be16(tb[MPTCP_ATTR_DPORT])); if (tb[MPTCP_ATTR_BACKUP]) - printf(" backup=%u", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP])); + print_uint(PRINT_ANY, "backup", " backup=%u", + rta_getattr_u8(tb[MPTCP_ATTR_BACKUP])); if (tb[MPTCP_ATTR_ERROR]) - printf(" error=%u", rta_getattr_u8(tb[MPTCP_ATTR_ERROR])); + print_uint(PRINT_ANY, "error", " error=%u", + rta_getattr_u8(tb[MPTCP_ATTR_ERROR])); if (tb[MPTCP_ATTR_TIMEOUT]) - printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT])); + print_uint(PRINT_ANY, "timeout", " timeout=%u", + rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT])); if (tb[MPTCP_ATTR_IF_IDX]) print_iface(rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX])); if (tb[MPTCP_ATTR_RESET_REASON]) - printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON])); + print_uint(PRINT_ANY, "reset_reason", " reset_reason=%u", + rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON])); if (tb[MPTCP_ATTR_RESET_FLAGS]) - printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS])); + print_0xhex(PRINT_ANY, "reset_flags", " reset_flags=%#x", + rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS])); if (tb[MPTCP_ATTR_FLAGS]) flags = rta_getattr_u16(tb[MPTCP_ATTR_FLAGS]); if ((flags & MPTCP_PM_EV_FLAG_SERVER_SIDE) || (tb[MPTCP_ATTR_SERVER_SIDE] && rta_getattr_u8(tb[MPTCP_ATTR_SERVER_SIDE]))) { flags &= ~MPTCP_PM_EV_FLAG_SERVER_SIDE; - printf(" server_side"); + print_string(PRINT_FP, NULL, " server_side", NULL); + print_bool(PRINT_JSON, "server_side", NULL, true); } if (flags & MPTCP_PM_EV_FLAG_DENY_JOIN_ID0) { flags &= ~MPTCP_PM_EV_FLAG_DENY_JOIN_ID0; - printf(" deny_join_id0"); + print_string(PRINT_FP, NULL, " deny_join_id0", NULL); + print_bool(PRINT_JSON, "deny_join_id0", NULL, true); } if (flags) /* remaining bits */ - printf(" flags=0x%x", flags); + print_0xhex(PRINT_ANY, "flags", " flags=%#x", flags); - puts(""); out: + print_nl(); + close_json_object(); fflush(stdout); + return 0; } +static void sig_exit_json(int signo) +{ + delete_json_obj(); + rtnl_close(&genl_rth); + exit(0); +} + static int mptcp_monitor(void) { if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) { @@ -XXX,XX +XXX,XX @@ static int mptcp_monitor(void) return 1; } + new_json_obj(json); + + if (is_json_context()) { + struct sigaction sa = { .sa_handler = sig_exit_json }; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + } + if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0) return 2; -- 2.51.0
With this series, the command 'ip [-t[s]] mptcp monitor' produces an output with the JSON format. - Patch 1: a small refactoring to uniform the code. - Patch 2: add JSON support in print_timestamp() helper. - Patch 3: add JSON support to 'ip mptcp monitor' as requested by Stephen. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- Changes in v2: - Patch 1: clearly mention the "fix". - Patch 2: ignore argument. - Patch 3: print token with 0xhex, use atexit(). - Link to v1: https://patch.msgid.link/20260220-ipr-monitor-json-v1-0-eb4b0d5f7820@kernel.org --- Matthieu Baerts (NGI0) (3): mptcp: uniform stream closure utils: timestamp: add JSON support mptcp: monitor: add JSON support ip/ipmptcp.c | 94 +++++++++++++++++++++++++++++++++++++++++------------------- lib/utils.c | 12 ++++---- 2 files changed, 71 insertions(+), 35 deletions(-) --- base-commit: f120cdb35da76ca99932d0428a0917bd01a843da change-id: 20260220-ipr-monitor-json-1573371524c1 Best regards, -- Matthieu Baerts (NGI0) <matttbe@kernel.org>
Use print_nl() instead of print_string(), close the json object, then flush the stream to flush the end of the JSON object ASAP. Note that in print_mptcp_limit(), the flush should have been done before closing the JSON object, but because there is only one object and the closure was done just before exiting, there was no visual impact. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- ip/ipmptcp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c index XXXXXXX..XXXXXXX 100644 --- a/ip/ipmptcp.c +++ b/ip/ipmptcp.c @@ -XXX,XX +XXX,XX @@ static int print_mptcp_addrinfo(struct rtattr *addrinfo) } } + print_nl(); close_json_object(); - print_string(PRINT_FP, NULL, "\n", NULL); fflush(stdout); return 0; @@ -XXX,XX +XXX,XX @@ static int print_mptcp_limit(struct nlmsghdr *n, void *arg) print_uint(PRINT_ANY, "subflows", "subflows %d ", val); } - print_string(PRINT_FP, NULL, "%s", "\n"); - fflush(stdout); + + print_nl(); close_json_object(); + fflush(stdout); + return 0; } -- 2.51.0
Supporting JSON is easy with the helpers. The biggest modification is to extract the end value. Different keys are used depending on the short or long timestamp option being used, to ease the parsing. No behavioural changes intended for the moment, this is a preparation for a future usage of print_timestamp() within a JSON context. Like in other helpers supporting JSON, the output stream 'fp' is ignored, which is fine, because it is always set to 'stdout'. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: ignore 'fp' which is always set to 'stdout' (Stephen) --- lib/utils.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index XXXXXXX..XXXXXXX 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -XXX,XX +XXX,XX @@ int print_timestamp(FILE *fp) { struct timeval tv; struct tm *tm; + char ts[40]; gettimeofday(&tv, NULL); tm = localtime(&tv.tv_sec); if (timestamp_short) { - char tshort[40]; + size_t len; - strftime(tshort, sizeof(tshort), "%Y-%m-%dT%H:%M:%S", tm); - fprintf(fp, "[%s.%06ld] ", tshort, tv.tv_usec); + len = strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tm); + snprintf(ts + len, sizeof(ts) - len, ".%06ld", tv.tv_usec); + print_string(PRINT_ANY, "timestamp_short", "[%s] ", ts); } else { char *tstr = asctime(tm); tstr[strlen(tstr)-1] = 0; - fprintf(fp, "Timestamp: %s %ld usec\n", - tstr, tv.tv_usec); + snprintf(ts, sizeof(ts), "%s %ld usec", tstr, tv.tv_usec); + print_string(PRINT_ANY, "timestamp", "Timestamp: %s\n", ts); } return 0; -- 2.51.0
The command 'ip [-t[s]] mptcp monitor' now produces an output with the JSON format. The previous text output has been preserved. The JSON support has been added thanks to the print_*() helpers. Note that it is also needed to add a signal handler to exit without errors in case of SIGINT or SIGTERM, and close the JSON. This last step will print the final ']' when stopping 'ip -j mptcp monitor'. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: - print token with print_0xhex(), and add missing space after ',' (AI) - use atexit() to close the JSON (Stephen) - always call delete_json_obj(): nothing is done when JSON is not used. --- ip/ipmptcp.c | 86 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c index XXXXXXX..XXXXXXX 100644 --- a/ip/ipmptcp.c +++ b/ip/ipmptcp.c @@ -XXX,XX +XXX,XX @@ #include <arpa/inet.h> #include <netinet/in.h> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -XXX,XX +XXX,XX @@ static void print_addr(const char *key, int af, struct rtattr *value) char str[INET6_ADDRSTRLEN]; if (inet_ntop(af, data, str, sizeof(str))) { - printf(" %s=", key); - color_fprintf(stdout, ifa_family_color(af), "%s", str); + print_string(PRINT_FP, NULL, " %s=", key); + print_color_string(PRINT_ANY, ifa_family_color(af), key, "%s", + str); } } @@ -XXX,XX +XXX,XX @@ static void print_iface(int index) { const char *ifname; - printf(" ifindex=%d", index); + print_int(PRINT_ANY, "ifindex", " ifindex=%d", index); ifname = index ? ll_index_to_name(index) : NULL; if (ifname) { - printf(" dev="); - color_fprintf(stdout, COLOR_IFNAME, "%s", ifname); + print_string(PRINT_FP, NULL, " dev=", NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, "dev", "%s", + ifname); } } @@ -XXX,XX +XXX,XX @@ static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl, if (n->nlmsg_type != genl_family) return 0; + open_json_object(NULL); + if (timestamp) print_timestamp(stdout); - if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) { - printf("[UNKNOWN %u]\n", ghdr->cmd); + if (ghdr->cmd >= ARRAY_SIZE(event_to_str) || + event_to_str[ghdr->cmd] == NULL) { + char event[40]; + + snprintf(event, sizeof(event), "UNKNOWN %u", ghdr->cmd); + print_string(PRINT_ANY, "event", "[%s]", event); goto out; } - if (event_to_str[ghdr->cmd] == NULL) { - printf("[UNKNOWN %u]\n", ghdr->cmd); - goto out; - } - - printf("[%16s]", event_to_str[ghdr->cmd]); + print_string(PRINT_ANY, "event", "[%16s]", event_to_str[ghdr->cmd]); parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); if (tb[MPTCP_ATTR_TOKEN]) - printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN])); + print_0xhex(PRINT_ANY, "token", " token=%08x", + rta_getattr_u32(tb[MPTCP_ATTR_TOKEN])); if (tb[MPTCP_ATTR_REM_ID]) - printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID])); + print_uint(PRINT_ANY, "remid", " remid=%u", + rta_getattr_u8(tb[MPTCP_ATTR_REM_ID])); if (tb[MPTCP_ATTR_LOC_ID]) - printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID])); + print_uint(PRINT_ANY, "locid", " locid=%u", + rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID])); if (tb[MPTCP_ATTR_SADDR4]) print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]); @@ -XXX,XX +XXX,XX @@ static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl, if (tb[MPTCP_ATTR_DADDR6]) print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]); if (tb[MPTCP_ATTR_SPORT]) - printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT])); + print_uint(PRINT_ANY, "sport", " sport=%u", + rta_getattr_be16(tb[MPTCP_ATTR_SPORT])); if (tb[MPTCP_ATTR_DPORT]) - printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT])); + print_uint(PRINT_ANY, "dport", " dport=%u", + rta_getattr_be16(tb[MPTCP_ATTR_DPORT])); if (tb[MPTCP_ATTR_BACKUP]) - printf(" backup=%u", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP])); + print_uint(PRINT_ANY, "backup", " backup=%u", + rta_getattr_u8(tb[MPTCP_ATTR_BACKUP])); if (tb[MPTCP_ATTR_ERROR]) - printf(" error=%u", rta_getattr_u8(tb[MPTCP_ATTR_ERROR])); + print_uint(PRINT_ANY, "error", " error=%u", + rta_getattr_u8(tb[MPTCP_ATTR_ERROR])); if (tb[MPTCP_ATTR_TIMEOUT]) - printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT])); + print_uint(PRINT_ANY, "timeout", " timeout=%u", + rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT])); if (tb[MPTCP_ATTR_IF_IDX]) print_iface(rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX])); if (tb[MPTCP_ATTR_RESET_REASON]) - printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON])); + print_uint(PRINT_ANY, "reset_reason", " reset_reason=%u", + rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON])); if (tb[MPTCP_ATTR_RESET_FLAGS]) - printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS])); + print_0xhex(PRINT_ANY, "reset_flags", " reset_flags=%#x", + rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS])); if (tb[MPTCP_ATTR_FLAGS]) flags = rta_getattr_u16(tb[MPTCP_ATTR_FLAGS]); if ((flags & MPTCP_PM_EV_FLAG_SERVER_SIDE) || (tb[MPTCP_ATTR_SERVER_SIDE] && rta_getattr_u8(tb[MPTCP_ATTR_SERVER_SIDE]))) { flags &= ~MPTCP_PM_EV_FLAG_SERVER_SIDE; - printf(" server_side"); + print_string(PRINT_FP, NULL, " server_side", NULL); + print_bool(PRINT_JSON, "server_side", NULL, true); } if (flags & MPTCP_PM_EV_FLAG_DENY_JOIN_ID0) { flags &= ~MPTCP_PM_EV_FLAG_DENY_JOIN_ID0; - printf(" deny_join_id0"); + print_string(PRINT_FP, NULL, " deny_join_id0", NULL); + print_bool(PRINT_JSON, "deny_join_id0", NULL, true); } if (flags) /* remaining bits */ - printf(" flags=0x%x", flags); + print_0xhex(PRINT_ANY, "flags", " flags=%#x", flags); - puts(""); out: + print_nl(); + close_json_object(); fflush(stdout); + return 0; } +static void sig_exit(int signo) +{ + exit(0); +} + static int mptcp_monitor(void) { + struct sigaction sa = { .sa_handler = sig_exit, + .sa_flags = SA_RESTART }; + if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) { perror("can't subscribe to mptcp events"); return 1; } + new_json_obj(json); + atexit(delete_json_obj); + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0) return 2; -- 2.51.0