Merge branch 'more-json' into iproute2-next

Stephen Hemminger says:

====================

The ip command implementation of JSON was very spotty. Only address
and link were originally implemented. After doing route for next,
went ahead and implemented it for a bunch of the other sub commands.

Hopefully will reach full coverage soon.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2018-03-06 15:48:22 -08:00
commit 65745eae83
10 changed files with 744 additions and 503 deletions

View File

@ -38,6 +38,7 @@
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
#define IFAL_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg))
@ -55,7 +56,6 @@ static void usage(void)
int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[IFAL_MAX+1];
@ -69,28 +69,40 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
open_json_object(NULL);
if (n->nlmsg_type == RTM_DELADDRLABEL)
fprintf(fp, "Deleted ");
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (tb[IFAL_ADDRESS]) {
fprintf(fp, "prefix %s/%u ",
format_host_rta(ifal->ifal_family,
tb[IFAL_ADDRESS]),
ifal->ifal_prefixlen);
const char *host
= format_host_rta(ifal->ifal_family,
tb[IFAL_ADDRESS]);
print_string(PRINT_FP, NULL, "prefix ", NULL);
print_color_string(PRINT_ANY,
ifa_family_color(ifal->ifal_family),
"address", "%s", host);
print_uint(PRINT_ANY, "prefixlen", "/%u ",
ifal->ifal_prefixlen);
}
if (ifal->ifal_index)
fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
if (ifal->ifal_index) {
print_string(PRINT_FP, NULL, "dev ", NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"ifname", "%s ",
ll_index_to_name(ifal->ifal_index));
}
if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
uint32_t label;
uint32_t label = rta_getattr_u32(RTA_DATA(tb[IFAL_LABEL]));
memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
fprintf(fp, "label %u ", label);
print_uint(PRINT_ANY,
"label", "label %u ", label);
}
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fprintf(fp, "\n");
fflush(fp);
return 0;
}
@ -111,10 +123,12 @@ static int ipaddrlabel_list(int argc, char **argv)
return 1;
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return 1;
}
delete_json_obj();
return 0;
}

View File

@ -22,16 +22,17 @@
#include "libgenl.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
static void usage(void)
{
fprintf(stderr, "Usage: ip fou add port PORT "
"{ ipproto PROTO | gue } [ -6 ]\n");
fprintf(stderr, " ip fou del port PORT [ -6 ]\n");
fprintf(stderr, " ip fou show\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n");
fprintf(stderr, " PORT { 1..65535 }\n");
fprintf(stderr,
"Usage: ip fou add port PORT { ipproto PROTO | gue } [ -6 ]\n"
" ip fou del port PORT [ -6 ]\n"
" ip fou show\n"
"\n"
"Where: PROTO { ipproto-name | 1..255 }\n"
" PORT { 1..65535 }\n");
exit(-1);
}
@ -77,7 +78,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
} else if (!matches(*argv, "-6")) {
family = AF_INET6;
} else {
fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
fprintf(stderr
, "fou: unknown command \"%s\"?\n", *argv);
usage();
return -1;
}
@ -138,11 +140,9 @@ static int do_del(int argc, char **argv)
static int print_fou_mapping(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct genlmsghdr *ghdr;
struct rtattr *tb[FOU_ATTR_MAX + 1];
int len = n->nlmsg_len;
unsigned family;
if (n->nlmsg_type != genl_family)
return 0;
@ -154,18 +154,30 @@ static int print_fou_mapping(const struct sockaddr_nl *who,
ghdr = NLMSG_DATA(n);
parse_rtattr(tb, FOU_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
open_json_object(NULL);
if (tb[FOU_ATTR_PORT])
fprintf(fp, "port %u", ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
if (tb[FOU_ATTR_TYPE] && rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
fprintf(fp, " gue");
print_uint(PRINT_ANY, "port", "port %u",
ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
if (tb[FOU_ATTR_TYPE] &&
rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
print_null(PRINT_ANY, "gue", " gue", NULL);
else if (tb[FOU_ATTR_IPPROTO])
fprintf(fp, " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
print_uint(PRINT_ANY, "ipproto",
" ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
if (tb[FOU_ATTR_AF]) {
family = rta_getattr_u8(tb[FOU_ATTR_AF]);
__u8 family = rta_getattr_u8(tb[FOU_ATTR_AF]);
print_string(PRINT_JSON, "family", NULL,
family_name(family));
if (family == AF_INET6)
fprintf(fp, " -6");
print_string(PRINT_FP, NULL,
" -6", NULL);
}
fprintf(fp, "\n");
print_string(PRINT_FP, NULL, "\n", NULL);
close_json_object();
return 0;
}
@ -175,7 +187,8 @@ static int do_show(int argc, char **argv)
FOU_REQUEST(req, 4096, FOU_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP);
if (argc > 0) {
fprintf(stderr, "\"ip fou show\" does not take any arguments.\n");
fprintf(stderr,
"\"ip fou show\" does not take any arguments.\n");
return -1;
}
@ -184,10 +197,13 @@ static int do_show(int argc, char **argv)
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&genl_rth, print_fou_mapping, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return 1;
}
delete_json_obj();
fflush(stdout);
return 0;
}
@ -209,6 +225,8 @@ int do_ipfou(int argc, char **argv)
return do_del(argc-1, argv+1);
if (matches(*argv, "show") == 0)
return do_show(argc-1, argv+1);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
fprintf(stderr,
"Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
exit(-1);
}

View File

@ -23,6 +23,7 @@
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
#define MAX_ROUNDS 10
@ -189,6 +190,46 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
return 0;
}
static void print_cacheinfo(const struct nda_cacheinfo *ci)
{
static int hz;
if (!hz)
hz = get_user_hz();
if (ci->ndm_refcnt)
print_uint(PRINT_ANY, "refcnt",
" ref %u", ci->ndm_refcnt);
print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz);
print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz);
print_uint(PRINT_ANY, "updated", "/u", ci->ndm_updated / hz);
}
static void print_neigh_state(unsigned int nud)
{
open_json_array(PRINT_JSON,
is_json_context() ? "state" : "");
#define PRINT_FLAG(f) \
if (nud & NUD_##f) { \
nud &= ~NUD_##f; \
print_string(PRINT_ANY, NULL, " %s", #f); \
}
PRINT_FLAG(INCOMPLETE);
PRINT_FLAG(REACHABLE);
PRINT_FLAG(STALE);
PRINT_FLAG(DELAY);
PRINT_FLAG(PROBE);
PRINT_FLAG(FAILED);
PRINT_FLAG(NOARP);
PRINT_FLAG(PERMANENT);
#undef PRINT_FLAG
close_json_array(PRINT_JSON, NULL);
}
int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
@ -221,7 +262,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (!(filter.state&r->ndm_state) &&
!(r->ndm_flags & NTF_PROXY) &&
(r->ndm_state || !(filter.state&0x100)) &&
(r->ndm_family != AF_DECnet))
(r->ndm_family != AF_DECnet))
return 0;
if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
@ -262,65 +303,68 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
return 0;
}
open_json_object(NULL);
if (n->nlmsg_type == RTM_DELNEIGH)
fprintf(fp, "Deleted ");
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
else if (n->nlmsg_type == RTM_GETNEIGH)
fprintf(fp, "miss ");
print_null(PRINT_ANY, "miss", "%s ", "miss");
if (tb[NDA_DST]) {
fprintf(fp, "%s ",
format_host_rta(r->ndm_family, tb[NDA_DST]));
const char *dst;
dst = format_host_rta(r->ndm_family, tb[NDA_DST]);
print_color_string(PRINT_ANY,
ifa_family_color(r->ndm_family),
"dst", "%s ", dst);
}
if (!filter.index && r->ndm_ifindex)
fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
if (!filter.index && r->ndm_ifindex) {
if (!is_json_context())
fprintf(fp, "dev ");
print_color_string(PRINT_ANY, COLOR_IFNAME,
"dev", "%s ",
ll_index_to_name(r->ndm_ifindex));
}
if (tb[NDA_LLADDR]) {
const char *lladdr;
SPRINT_BUF(b1);
fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
RTA_PAYLOAD(tb[NDA_LLADDR]),
ll_index_to_type(r->ndm_ifindex),
b1, sizeof(b1)));
}
if (r->ndm_flags & NTF_ROUTER) {
fprintf(fp, " router");
}
if (r->ndm_flags & NTF_PROXY) {
fprintf(fp, " proxy");
}
if (tb[NDA_CACHEINFO] && show_stats) {
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
int hz = get_user_hz();
if (ci->ndm_refcnt)
printf(" ref %d", ci->ndm_refcnt);
fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
ci->ndm_confirmed/hz, ci->ndm_updated/hz);
lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
RTA_PAYLOAD(tb[NDA_LLADDR]),
ll_index_to_type(r->ndm_ifindex),
b1, sizeof(b1));
if (!is_json_context())
fprintf(fp, "lladdr ");
print_color_string(PRINT_ANY, COLOR_MAC,
"lladdr", "%s", lladdr);
}
if (tb[NDA_PROBES] && show_stats) {
__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
if (r->ndm_flags & NTF_ROUTER)
print_null(PRINT_ANY, "router", " %s", "router");
fprintf(fp, " probes %u", p);
if (r->ndm_flags & NTF_PROXY)
print_null(PRINT_ANY, "proxy", " %s", "proxy");
if (show_stats) {
if (tb[NDA_CACHEINFO])
print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
if (tb[NDA_PROBES])
print_uint(PRINT_ANY, "probes", " probes %u",
rta_getattr_u32(tb[NDA_PROBES]));
}
if (r->ndm_state) {
int nud = r->ndm_state;
if (r->ndm_state)
print_neigh_state(r->ndm_state);
fprintf(fp, " ");
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(stdout);
#define PRINT_FLAG(f) if (nud & NUD_##f) { \
nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
PRINT_FLAG(INCOMPLETE);
PRINT_FLAG(REACHABLE);
PRINT_FLAG(STALE);
PRINT_FLAG(DELAY);
PRINT_FLAG(PROBE);
PRINT_FLAG(FAILED);
PRINT_FLAG(NOARP);
PRINT_FLAG(PERMANENT);
#undef PRINT_FLAG
}
fprintf(fp, "\n");
fflush(fp);
return 0;
}
@ -479,10 +523,12 @@ static int do_show_or_flush(int argc, char **argv, int flush)
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
return 0;
}

View File

@ -29,6 +29,10 @@ static struct {
int ifindex;
} filter;
static const char * const rp_filter_names[] = {
"off", "strict", "loose"
};
static void usage(void) __attribute__((noreturn));
static void usage(void)
@ -37,9 +41,12 @@ static void usage(void)
exit(-1);
}
static void print_onoff(FILE *f, const char *flag, __u32 val)
static void print_onoff(FILE *fp, const char *flag, __u32 val)
{
fprintf(f, "%s %s ", flag, val ? "on" : "off");
if (is_json_context())
print_bool(PRINT_JSON, flag, NULL, val);
else
fprintf(fp, "%s %s ", flag, val ? "on" : "off");
}
static struct rtattr *netconf_rta(struct netconfmsg *ncm)
@ -83,50 +90,44 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
if (filter.ifindex && filter.ifindex != ifindex)
return 0;
switch (ncm->ncm_family) {
case AF_INET:
fprintf(fp, "ipv4 ");
break;
case AF_INET6:
fprintf(fp, "ipv6 ");
break;
case AF_MPLS:
fprintf(fp, "mpls ");
break;
default:
fprintf(fp, "unknown ");
break;
}
open_json_object(NULL);
print_string(PRINT_ANY, "family",
"%s ", family_name(ncm->ncm_family));
if (tb[NETCONFA_IFINDEX]) {
const char *dev;
switch (ifindex) {
case NETCONFA_IFINDEX_ALL:
fprintf(fp, "all ");
dev = "all";
break;
case NETCONFA_IFINDEX_DEFAULT:
fprintf(fp, "default ");
dev = "default";
break;
default:
fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
dev = ll_index_to_name(ifindex);
break;
}
print_color_string(PRINT_ANY, COLOR_IFNAME,
"interface", "%s ", dev);
}
if (tb[NETCONFA_FORWARDING])
print_onoff(fp, "forwarding",
rta_getattr_u32(tb[NETCONFA_FORWARDING]));
if (tb[NETCONFA_RP_FILTER]) {
__u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]);
if (rp_filter == 0)
fprintf(fp, "rp_filter off ");
else if (rp_filter == 1)
fprintf(fp, "rp_filter strict ");
else if (rp_filter == 2)
fprintf(fp, "rp_filter loose ");
if (rp_filter < ARRAY_SIZE(rp_filter_names))
print_string(PRINT_ANY, "rp_filter",
"rp_filter %s ",
rp_filter_names[rp_filter]);
else
fprintf(fp, "rp_filter unknown mode ");
print_uint(PRINT_ANY, "rp_filter",
"rp_filter %u ", rp_filter);
}
if (tb[NETCONFA_MC_FORWARDING])
print_onoff(fp, "mc_forwarding",
rta_getattr_u32(tb[NETCONFA_MC_FORWARDING]));
@ -142,7 +143,8 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
if (tb[NETCONFA_INPUT])
print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT]));
fprintf(fp, "\n");
close_json_object();
print_string(PRINT_FP, NULL, "\n", NULL);
fflush(fp);
return 0;
}
@ -179,7 +181,8 @@ static int do_show(int argc, char **argv)
NEXT_ARG();
filter.ifindex = ll_name_to_index(*argv);
if (filter.ifindex <= 0) {
fprintf(stderr, "Device \"%s\" does not exist.\n",
fprintf(stderr,
"Device \"%s\" does not exist.\n",
*argv);
return -1;
}
@ -202,10 +205,13 @@ static int do_show(int argc, char **argv)
} else {
rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR;
dump:
if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) {
if (rtnl_wilddump_request(&rth, filter.family,
RTM_GETNETCONF) < 0) {
perror("Cannot send dump request");
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
/* kernel does not support netconf dump on AF_UNSPEC;
* fall back to requesting by family
@ -219,6 +225,7 @@ dump:
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
if (preferred_family == AF_UNSPEC && filter.family == AF_INET) {
preferred_family = AF_INET6;
filter.family = AF_INET6;
@ -240,6 +247,8 @@ int do_ipnetconf(int argc, char **argv)
} else
return do_show(0, NULL);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv);
fprintf(stderr,
"Command \"%s\" is unknown, try \"ip netconf help\".\n",
*argv);
exit(-1);
}

View File

@ -31,6 +31,7 @@
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
static struct
{
@ -338,7 +339,191 @@ static const char *ntable_strtime_delta(__u32 msec)
return str;
}
static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
static void print_ndtconfig(const struct ndt_config *ndtc)
{
print_uint(PRINT_ANY, "key_length",
" config key_len %u ", ndtc->ndtc_key_len);
print_uint(PRINT_ANY, "entry_size",
"entry_size %u ", ndtc->ndtc_entry_size);
print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_string(PRINT_ANY, "last_flush",
" last_flush %s ",
ntable_strtime_delta(ndtc->ndtc_last_flush));
print_string(PRINT_ANY, "last_rand",
"last_rand %s ",
ntable_strtime_delta(ndtc->ndtc_last_rand));
print_string(PRINT_FP, NULL, "%s", _SL_);
print_uint(PRINT_ANY, "hash_rnd",
" hash_rnd %u ", ndtc->ndtc_hash_rnd);
print_0xhex(PRINT_ANY, "hash_mask",
"hash_mask %08x ", ndtc->ndtc_hash_mask);
print_uint(PRINT_ANY, "hash_chain_gc",
"hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
print_uint(PRINT_ANY, "proxy_qlen",
"proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
print_string(PRINT_FP, NULL, "%s", _SL_);
}
static void print_ndtparams(struct rtattr *tpb[])
{
if (tpb[NDTPA_IFINDEX]) {
__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
print_string(PRINT_FP, NULL, " dev ", NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"dev", "%s ", ll_index_to_name(ifindex));
print_string(PRINT_FP, NULL, "%s", _SL_);
}
print_string(PRINT_FP, NULL, " ", NULL);
if (tpb[NDTPA_REFCNT]) {
__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt);
}
if (tpb[NDTPA_REACHABLE_TIME]) {
__u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
print_uint(PRINT_ANY, "reachable",
"reachable %llu ", reachable);
}
if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
__u64 breachable
= rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
print_uint(PRINT_ANY, "base_reachable",
"base_reachable %llu ", breachable);
}
if (tpb[NDTPA_RETRANS_TIME]) {
__u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
print_uint(PRINT_ANY, "retrans", "retrans %llu ", retrans);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_GC_STALETIME]) {
__u64 gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
print_uint(PRINT_ANY, "gc_stale", "gc_stale %llu ", gc_stale);
}
if (tpb[NDTPA_DELAY_PROBE_TIME]) {
__u64 delay_probe
= rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
print_uint(PRINT_ANY, "delay_probe",
"delay_probe %llu ", delay_probe);
}
if (tpb[NDTPA_QUEUE_LEN]) {
__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
print_uint(PRINT_ANY, "queue", "queue %u ", queue);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_APP_PROBES]) {
__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
print_uint(PRINT_ANY, "app_probes", "app_probes %u ", aprobe);
}
if (tpb[NDTPA_UCAST_PROBES]) {
__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
print_uint(PRINT_ANY, "ucast_probes",
"ucast_probes %u ", uprobe);
}
if (tpb[NDTPA_MCAST_PROBES]) {
__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
print_uint(PRINT_ANY, "mcast_probes",
"mcast_probes %u ", mprobe);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_ANYCAST_DELAY]) {
__u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
print_uint(PRINT_ANY, "anycast_delay",
"anycast_delay %llu ", anycast_delay);
}
if (tpb[NDTPA_PROXY_DELAY]) {
__u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
print_uint(PRINT_ANY, "proxy_delay",
"proxy_delay %llu ", proxy_delay);
}
if (tpb[NDTPA_PROXY_QLEN]) {
__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue);
}
if (tpb[NDTPA_LOCKTIME]) {
__u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
print_uint(PRINT_ANY, "locktime", "locktime %llu ", locktime);
}
print_string(PRINT_FP, NULL, "%s", _SL_);
}
static void print_ndtstats(const struct ndt_stats *ndts)
{
print_string(PRINT_FP, NULL, " stats ", NULL);
print_uint(PRINT_ANY, "allocs", "allocs %llu ", ndts->ndts_allocs);
print_uint(PRINT_ANY, "destroys", "destroys %llu ",
ndts->ndts_destroys);
print_uint(PRINT_ANY, "hash_grows", "hash_grows %llu ",
ndts->ndts_hash_grows);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_uint(PRINT_ANY, "res_failed", "res_failed %llu ",
ndts->ndts_res_failed);
print_uint(PRINT_ANY, "lookups", "lookups %llu ", ndts->ndts_lookups);
print_uint(PRINT_ANY, "hits", "hits %llu ", ndts->ndts_hits);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_uint(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
ndts->ndts_rcv_probes_mcast);
print_uint(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
ndts->ndts_rcv_probes_ucast);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_uint(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ",
ndts->ndts_periodic_gc_runs);
print_uint(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ",
ndts->ndts_forced_gc_runs);
print_string(PRINT_FP, NULL, "%s", _SL_);
}
static int print_ntable(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct ndtmsg *ndtm = NLMSG_DATA(n);
@ -370,6 +555,7 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void
if (filter.name && strcmp(filter.name, name))
return 0;
}
if (tb[NDTA_PARMS]) {
parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
RTA_PAYLOAD(tb[NDTA_PARMS]));
@ -385,227 +571,63 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void
}
}
if (ndtm->ndtm_family == AF_INET)
fprintf(fp, "inet ");
else if (ndtm->ndtm_family == AF_INET6)
fprintf(fp, "inet6 ");
else if (ndtm->ndtm_family == AF_DECnet)
fprintf(fp, "dnet ");
else
fprintf(fp, "(%d) ", ndtm->ndtm_family);
open_json_object(NULL);
print_string(PRINT_ANY, "family",
"%s ", family_name(ndtm->ndtm_family));
if (tb[NDTA_NAME]) {
const char *name = rta_getattr_str(tb[NDTA_NAME]);
fprintf(fp, "%s ", name);
print_string(PRINT_ANY, "name", "%s ", name);
}
fprintf(fp, "%s", _SL_);
print_string(PRINT_FP, NULL, "%s", _SL_);
ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
tb[NDTA_GC_INTERVAL]);
if (ret)
fprintf(fp, " ");
print_string(PRINT_FP, NULL, " ", NULL);
if (tb[NDTA_THRESH1]) {
__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
fprintf(fp, "thresh1 %u ", thresh1);
print_uint(PRINT_ANY, "thresh1", "thresh1 %u ", thresh1);
}
if (tb[NDTA_THRESH2]) {
__u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
fprintf(fp, "thresh2 %u ", thresh2);
print_uint(PRINT_ANY, "thresh2", "thresh2 %u ", thresh2);
}
if (tb[NDTA_THRESH3]) {
__u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
fprintf(fp, "thresh3 %u ", thresh3);
print_uint(PRINT_ANY, "thresh3", "thresh3 %u ", thresh3);
}
if (tb[NDTA_GC_INTERVAL]) {
unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
fprintf(fp, "gc_int %llu ", gc_int);
if (tb[NDTA_GC_INTERVAL]) {
__u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
print_uint(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int);
}
if (ret)
fprintf(fp, "%s", _SL_);
print_string(PRINT_FP, NULL, "%s", _SL_);
if (tb[NDTA_CONFIG] && show_stats) {
struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]);
if (tb[NDTA_CONFIG] && show_stats)
print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG]));
fprintf(fp, " ");
fprintf(fp, "config ");
if (tb[NDTA_PARMS])
print_ndtparams(tpb);
fprintf(fp, "key_len %u ", ndtc->ndtc_key_len);
fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size);
fprintf(fp, "entries %u ", ndtc->ndtc_entries);
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
fprintf(fp, "last_flush %s ",
ntable_strtime_delta(ndtc->ndtc_last_flush));
fprintf(fp, "last_rand %s ",
ntable_strtime_delta(ndtc->ndtc_last_rand));
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);
fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
fprintf(fp, "%s", _SL_);
}
if (tb[NDTA_PARMS]) {
if (tpb[NDTPA_IFINDEX]) {
__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
fprintf(fp, " ");
fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
fprintf(fp, "%s", _SL_);
}
fprintf(fp, " ");
if (tpb[NDTPA_REFCNT]) {
__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
fprintf(fp, "refcnt %u ", refcnt);
}
if (tpb[NDTPA_REACHABLE_TIME]) {
unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
fprintf(fp, "reachable %llu ", reachable);
}
if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
fprintf(fp, "base_reachable %llu ", breachable);
}
if (tpb[NDTPA_RETRANS_TIME]) {
unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
fprintf(fp, "retrans %llu ", retrans);
}
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
if (tpb[NDTPA_GC_STALETIME]) {
unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
fprintf(fp, "gc_stale %llu ", gc_stale);
}
if (tpb[NDTPA_DELAY_PROBE_TIME]) {
unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
fprintf(fp, "delay_probe %llu ", delay_probe);
}
if (tpb[NDTPA_QUEUE_LEN]) {
__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
fprintf(fp, "queue %u ", queue);
}
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
if (tpb[NDTPA_APP_PROBES]) {
__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
fprintf(fp, "app_probes %u ", aprobe);
}
if (tpb[NDTPA_UCAST_PROBES]) {
__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
fprintf(fp, "ucast_probes %u ", uprobe);
}
if (tpb[NDTPA_MCAST_PROBES]) {
__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
fprintf(fp, "mcast_probes %u ", mprobe);
}
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
if (tpb[NDTPA_ANYCAST_DELAY]) {
unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
fprintf(fp, "anycast_delay %llu ", anycast_delay);
}
if (tpb[NDTPA_PROXY_DELAY]) {
unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
fprintf(fp, "proxy_delay %llu ", proxy_delay);
}
if (tpb[NDTPA_PROXY_QLEN]) {
__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
fprintf(fp, "proxy_queue %u ", pqueue);
}
if (tpb[NDTPA_LOCKTIME]) {
unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
fprintf(fp, "locktime %llu ", locktime);
}
fprintf(fp, "%s", _SL_);
}
if (tb[NDTA_STATS] && show_stats) {
struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);
fprintf(fp, " ");
fprintf(fp, "stats ");
fprintf(fp, "allocs %llu ",
(unsigned long long) ndts->ndts_allocs);
fprintf(fp, "destroys %llu ",
(unsigned long long) ndts->ndts_destroys);
fprintf(fp, "hash_grows %llu ",
(unsigned long long) ndts->ndts_hash_grows);
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
fprintf(fp, "res_failed %llu ",
(unsigned long long) ndts->ndts_res_failed);
fprintf(fp, "lookups %llu ",
(unsigned long long) ndts->ndts_lookups);
fprintf(fp, "hits %llu ",
(unsigned long long) ndts->ndts_hits);
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
fprintf(fp, "rcv_probes_mcast %llu ",
(unsigned long long) ndts->ndts_rcv_probes_mcast);
fprintf(fp, "rcv_probes_ucast %llu ",
(unsigned long long) ndts->ndts_rcv_probes_ucast);
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
fprintf(fp, "periodic_gc_runs %llu ",
(unsigned long long) ndts->ndts_periodic_gc_runs);
fprintf(fp, "forced_gc_runs %llu ",
(unsigned long long) ndts->ndts_forced_gc_runs);
fprintf(fp, "%s", _SL_);
}
fprintf(fp, "\n");
if (tb[NDTA_STATS] && show_stats)
print_ndtstats(RTA_DATA(tb[NDTA_STATS]));
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(fp);
return 0;
}
@ -643,10 +665,12 @@ static int ipntable_show(int argc, char **argv)
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
return 0;
}

View File

@ -26,6 +26,7 @@
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
enum list_action {
IPRULE_LIST,
@ -179,13 +180,12 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
FILE *fp = arg;
struct fib_rule_hdr *frh = NLMSG_DATA(n);
int len = n->nlmsg_len;
int host_len = -1;
__u32 table;
__u32 table, prio = 0;
struct rtattr *tb[FRA_MAX+1];
SPRINT_BUF(b1);
if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
@ -202,50 +202,54 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (!filter_nlmsg(n, tb, host_len))
return 0;
open_json_object(NULL);
if (n->nlmsg_type == RTM_DELRULE)
fprintf(fp, "Deleted ");
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (tb[FRA_PRIORITY])
fprintf(fp, "%u:\t",
rta_getattr_u32(tb[FRA_PRIORITY]));
else
fprintf(fp, "0:\t");
prio = rta_getattr_u32(tb[FRA_PRIORITY]);
print_uint(PRINT_ANY, "priority", "%u:\t", prio);
if (frh->flags & FIB_RULE_INVERT)
fprintf(fp, "not ");
print_null(PRINT_ANY, "not", "not ", NULL);
if (tb[FRA_SRC]) {
if (frh->src_len != host_len) {
fprintf(fp, "from %s/%u ",
rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
frh->src_len);
} else {
fprintf(fp, "from %s ",
format_host_rta(frh->family, tb[FRA_SRC]));
}
const char *src = rt_addr_n2a_rta(frh->family, tb[FRA_SRC]);
print_string(PRINT_FP, NULL, "from ", NULL);
print_color_string(PRINT_ANY, ifa_family_color(frh->family),
"src", "%s", src);
if (frh->src_len != host_len)
print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
else
print_string(PRINT_FP, NULL, " ", NULL);
} else if (frh->src_len) {
fprintf(fp, "from 0/%d ", frh->src_len);
print_string(PRINT_ANY, "src", "from %s", "0");
print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
} else {
fprintf(fp, "from all ");
print_string(PRINT_ANY, "src", "from %s ", "all");
}
if (tb[FRA_DST]) {
if (frh->dst_len != host_len) {
fprintf(fp, "to %s/%u ",
rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
frh->dst_len);
} else {
fprintf(fp, "to %s ",
format_host_rta(frh->family, tb[FRA_DST]));
}
const char *dst = rt_addr_n2a_rta(frh->family, tb[FRA_DST]);
print_string(PRINT_FP, NULL, "to ", NULL);
print_color_string(PRINT_ANY, ifa_family_color(frh->family),
"dst", "%s ", dst);
if (frh->dst_len != host_len)
print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
else
print_string(PRINT_FP, NULL, " ", NULL);
} else if (frh->dst_len) {
fprintf(fp, "to 0/%d ", frh->dst_len);
print_string(PRINT_ANY, "dst", "to %s", "0");
print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
}
if (frh->tos) {
SPRINT_BUF(b1);
fprintf(fp, "tos %s ",
rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
print_string(PRINT_ANY, "tos",
"tos %s ",
rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
}
if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@ -255,53 +259,76 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
mark = rta_getattr_u32(tb[FRA_FWMARK]);
if (tb[FRA_FWMASK] &&
(mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
else
fprintf(fp, "fwmark 0x%x ", mark);
(mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) {
print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x", mark);
print_0xhex(PRINT_ANY, "fwmask", "/0x%x ", mask);
} else {
print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x ", mark);
}
}
if (tb[FRA_IFNAME]) {
fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
if (!is_json_context())
fprintf(fp, "iif ");
print_color_string(PRINT_ANY, COLOR_IFNAME,
"iif", "%s ",
rta_getattr_str(tb[FRA_IFNAME]));
if (frh->flags & FIB_RULE_IIF_DETACHED)
fprintf(fp, "[detached] ");
print_null(PRINT_ANY, "iif_detached", "[detached] ",
NULL);
}
if (tb[FRA_OIFNAME]) {
fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
if (!is_json_context())
fprintf(fp, "oif ");
print_color_string(PRINT_ANY, COLOR_IFNAME, "oif", "%s ",
rta_getattr_str(tb[FRA_OIFNAME]));
if (frh->flags & FIB_RULE_OIF_DETACHED)
fprintf(fp, "[detached] ");
print_null(PRINT_ANY, "oif_detached", "[detached] ",
NULL);
}
if (tb[FRA_L3MDEV]) {
if (rta_getattr_u8(tb[FRA_L3MDEV]))
fprintf(fp, "lookup [l3mdev-table] ");
__u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]);
if (mdev)
print_null(PRINT_ANY, "l3mdev",
"lookup [l3mdev-table] ", NULL);
}
if (tb[FRA_UID_RANGE]) {
struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
fprintf(fp, "uidrange %u-%u ", r->start, r->end);
print_uint(PRINT_ANY, "uid_start", "uidrange %u", r->start);
print_uint(PRINT_ANY, "uid_end", "-%u ", r->end);
}
table = frh_get_table(frh, tb);
if (table) {
fprintf(fp, "lookup %s ",
rtnl_rttable_n2a(table, b1, sizeof(b1)));
print_string(PRINT_ANY, "table",
"lookup %s ",
rtnl_rttable_n2a(table, b1, sizeof(b1)));
if (tb[FRA_SUPPRESS_PREFIXLEN]) {
int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
if (pl != -1)
fprintf(fp, "suppress_prefixlength %d ", pl);
print_int(PRINT_ANY, "suppress_prefixlen",
"suppress_prefixlength %d ", pl);
}
if (tb[FRA_SUPPRESS_IFGROUP]) {
int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]);
if (group != -1) {
SPRINT_BUF(b1);
fprintf(fp, "suppress_ifgroup %s ",
rtnl_group_n2a(group, b1, sizeof(b1)));
const char *grname
= rtnl_group_n2a(group, b1, sizeof(b1));
print_string(PRINT_ANY, "suppress_ifgroup",
"suppress_ifgroup %s ", grname);
}
}
}
@ -311,47 +338,52 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
__u32 from = to>>16;
to &= 0xFFFF;
if (from) {
fprintf(fp, "realms %s/",
rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
}
fprintf(fp, "%s ",
rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
if (from)
print_string(PRINT_ANY,
"flow_from", "realms %s/",
rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
print_string(PRINT_ANY, "flow_to", "%s ",
rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
}
if (frh->action == RTN_NAT) {
if (tb[RTA_GATEWAY]) {
fprintf(fp, "map-to %s ",
format_host_rta(frh->family,
tb[RTA_GATEWAY]));
} else
fprintf(fp, "masquerade");
const char *gateway;
gateway = format_host_rta(frh->family, tb[RTA_GATEWAY]);
print_string(PRINT_ANY, "nat_gateway",
"map-to %s ", gateway);
} else {
print_null(PRINT_ANY, "masquerade", "masquerade", NULL);
}
} else if (frh->action == FR_ACT_GOTO) {
fprintf(fp, "goto ");
if (tb[FRA_GOTO])
fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
print_uint(PRINT_ANY, "goto", "goto %u",
rta_getattr_u32(tb[FRA_GOTO]));
else
fprintf(fp, "none");
print_string(PRINT_ANY, "goto", "goto %s", "none");
if (frh->flags & FIB_RULE_UNRESOLVED)
fprintf(fp, " [unresolved]");
} else if (frh->action == FR_ACT_NOP)
fprintf(fp, "nop");
else if (frh->action != FR_ACT_TO_TBL)
fprintf(fp, "%s",
rtnl_rtntype_n2a(frh->action,
b1, sizeof(b1)));
print_null(PRINT_ANY, "unresolved", "unresolved", NULL);
} else if (frh->action == FR_ACT_NOP) {
print_null(PRINT_ANY, "nop", "nop", NULL);
} else if (frh->action != FR_ACT_TO_TBL) {
print_string(PRINT_ANY, "to_tbl", "%s",
rtnl_rtntype_n2a(frh->action, b1, sizeof(b1)));
}
if (tb[FRA_PROTOCOL]) {
__u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
if ((protocol && protocol != RTPROT_KERNEL) ||
show_details > 0) {
fprintf(fp, " proto %s ",
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
if ((protocol && protocol != RTPROT_KERNEL) || show_details > 0) {
print_string(PRINT_ANY, "protocol", " proto %s ",
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
}
}
fprintf(fp, "\n");
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(fp);
return 0;
}
@ -554,10 +586,12 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
return 1;
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return 1;
}
delete_json_obj();
return 0;
}

View File

@ -26,6 +26,7 @@
#include "utils.h"
#include "ip_common.h"
#include "libgenl.h"
#include "json_print.h"
#define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): "
@ -55,12 +56,54 @@ static struct {
__u8 alg_id;
} opts;
static void print_dumphmac(struct rtattr *attrs[])
{
char secret[64];
char *algstr;
__u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
__u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
memset(secret, 0, 64);
if (slen > 63) {
fprintf(stderr, "HMAC secret length %d > 63, truncated\n", slen);
slen = 63;
}
memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
switch (alg_id) {
case SEG6_HMAC_ALGO_SHA1:
algstr = "sha1";
break;
case SEG6_HMAC_ALGO_SHA256:
algstr = "sha256";
break;
default:
algstr = "<unknown>";
}
print_uint(PRINT_ANY, "hmac", "hmac %u ",
rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
print_string(PRINT_ANY, "algo", "algo %s ", algstr);
print_string(PRINT_ANY, "secret", "secret \"%s\"\n", secret);
}
static void print_tunsrc(struct rtattr *attrs[])
{
const char *dst
= rt_addr_n2a(AF_INET6, 16,
RTA_DATA(attrs[SEG6_ATTR_DST]));
print_string(PRINT_ANY, "tunsrc",
"tunsrc addr %s\n", dst);
}
static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
void *arg)
{
struct rtattr *attrs[SEG6_ATTR_MAX + 1];
struct genlmsghdr *ghdr;
FILE *fp = (FILE *)arg;
int len = n->nlmsg_len;
if (n->nlmsg_type != genl_family)
@ -74,50 +117,17 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
open_json_object(NULL);
switch (ghdr->cmd) {
case SEG6_CMD_DUMPHMAC:
{
char secret[64];
char *algstr;
__u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
__u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
memset(secret, 0, 64);
if (slen > 63) {
fprintf(stderr, "HMAC secret length %d > 63, "
"truncated\n", slen);
slen = 63;
}
memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
switch (alg_id) {
case SEG6_HMAC_ALGO_SHA1:
algstr = "sha1";
break;
case SEG6_HMAC_ALGO_SHA256:
algstr = "sha256";
break;
default:
algstr = "<unknown>";
}
fprintf(fp, "hmac %u ",
rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
fprintf(fp, "algo %s ", algstr);
fprintf(fp, "secret \"%s\" ", secret);
fprintf(fp, "\n");
print_dumphmac(attrs);
break;
}
case SEG6_CMD_GET_TUNSRC:
{
fprintf(fp, "tunsrc addr %s\n",
rt_addr_n2a(AF_INET6, 16,
RTA_DATA(attrs[SEG6_ATTR_DST])));
print_tunsrc(attrs);
break;
}
}
close_json_object();
return 0;
}
@ -169,10 +179,12 @@ static int seg6_do_cmd(void)
} else if (repl) {
if (rtnl_talk(&grth, &req.n, &answer) < 0)
return -2;
new_json_obj(json);
if (process_msg(NULL, answer, stdout) < 0) {
fprintf(stderr, "Error parsing reply\n");
exit(1);
}
delete_json_obj();
free(answer);
} else {
req.n.nlmsg_flags |= NLM_F_DUMP;
@ -182,10 +194,13 @@ static int seg6_do_cmd(void)
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
fflush(stdout);
}
return 0;

View File

@ -25,6 +25,7 @@
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
extern struct rtnl_handle rth;
@ -77,9 +78,17 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void *
return -1;
}
fprintf(fp, "token %s dev %s\n",
format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]),
ll_index_to_name(ifi->ifi_index));
open_json_object(NULL);
print_string(PRINT_FP, NULL, "token ", NULL);
print_color_string(PRINT_ANY,
ifa_family_color(ifi->ifi_family),
"token", "%s",
format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]));
print_string(PRINT_FP, NULL, " dev ", NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"ifname", "%s\n",
ll_index_to_name(ifi->ifi_index));
close_json_object();
fflush(fp);
return 0;
@ -105,10 +114,13 @@ static int iptoken_list(int argc, char **argv)
return -1;
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_token, &da) < 0) {
delete_json_obj();
fprintf(stderr, "Dump terminated\n");
return -1;
}
delete_json_obj();
return 0;
}

View File

@ -228,24 +228,35 @@ static int do_del(int argc, char **argv)
static void print_flags(long flags)
{
open_json_array(PRINT_JSON, "flags");
if (flags & IFF_TUN)
printf(" tun");
print_string(PRINT_ANY, NULL, " %s", "tun");
if (flags & IFF_TAP)
printf(" tap");
print_string(PRINT_ANY, NULL, " %s", "tap");
if (!(flags & IFF_NO_PI))
printf(" pi");
print_string(PRINT_ANY, NULL, " %s", "pi");
if (flags & IFF_ONE_QUEUE)
printf(" one_queue");
print_string(PRINT_ANY, NULL, " %s", "one_queue");
if (flags & IFF_VNET_HDR)
printf(" vnet_hdr");
print_string(PRINT_ANY, NULL, " %s", "vnet_hdr");
flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR);
if (flags & IFF_PERSIST)
print_string(PRINT_ANY, NULL, " %s", "persist");
if (!(flags & IFF_NOFILTER))
print_string(PRINT_ANY, NULL, " %s", "filter");
flags &= ~(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
IFF_VNET_HDR | IFF_PERSIST | IFF_NOFILTER);
if (flags)
printf(" UNKNOWN_FLAGS:%lx", flags);
print_0xhex(PRINT_ANY, NULL, "%#x", flags);
close_json_array(PRINT_JSON, NULL);
}
static char *pid_name(pid_t pid)
@ -288,6 +299,8 @@ static void show_processes(const char *name)
if (err)
return;
open_json_array(PRINT_JSON, "processes");
fd_path = globbuf.gl_pathv;
while (*fd_path) {
const char *dev_net_tun = "/dev/net/tun";
@ -334,7 +347,11 @@ static void show_processes(const char *name)
!strcmp(name, value)) {
char *pname = pid_name(pid);
printf(" %s(%d)", pname ? : "<NULL>", pid);
print_string(PRINT_ANY, "name",
"%s", pname ? : "<NULL>");
print_uint(PRINT_ANY, "pid",
"(%d)", pid);
free(pname);
}
@ -347,6 +364,7 @@ static void show_processes(const char *name)
next:
++fd_path;
}
close_json_array(PRINT_JSON, NULL);
globfree(&globbuf);
}
@ -417,18 +435,24 @@ static int print_tuntap(const struct sockaddr_nl *who,
if (read_prop(name, "group", &group))
return 0;
printf("%s:", name);
open_json_object(NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"ifname", "%s:", name);
print_flags(flags);
if (owner != -1)
printf(" user %ld", owner);
print_uint(PRINT_ANY, "user",
" user %ld", owner);
if (group != -1)
printf(" group %ld", group);
fputc('\n', stdout);
print_uint(PRINT_ANY, "group",
" group %ld", group);
if (show_details) {
printf("\tAttached to processes:");
print_string(PRINT_FP, NULL,
"%s\tAttached to processes:", _SL_);
show_processes(name);
fputc('\n', stdout);
}
close_json_object();
print_string(PRINT_FP, NULL, "%s", "\n");
return 0;
}
@ -441,11 +465,16 @@ static int do_show(int argc, char **argv)
return -1;
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
delete_json_obj();
fflush(stdout);
return 0;
}

View File

@ -38,6 +38,7 @@ static void usage(void)
/* netlink socket */
static struct rtnl_handle grth = { .fd = -1 };
static int genl_family = -1;
static const double usec_per_sec = 1000000.;
#define TCPM_REQUEST(_req, _bufsiz, _cmd, _flags) \
GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
@ -47,8 +48,8 @@ static int genl_family = -1;
#define CMD_DEL 0x0002 /* delete, remove */
#define CMD_FLUSH 0x0004 /* flush */
static struct {
char *name;
static const struct {
const char *name;
int code;
} cmds[] = {
{ "list", CMD_LIST },
@ -59,7 +60,7 @@ static struct {
{ "flush", CMD_FLUSH },
};
static char *metric_name[TCP_METRIC_MAX + 1] = {
static const char *metric_name[TCP_METRIC_MAX + 1] = {
[TCP_METRIC_RTT] = "rtt",
[TCP_METRIC_RTTVAR] = "rttvar",
[TCP_METRIC_SSTHRESH] = "ssthresh",
@ -67,8 +68,7 @@ static char *metric_name[TCP_METRIC_MAX + 1] = {
[TCP_METRIC_REORDERING] = "reordering",
};
static struct
{
static struct {
int flushed;
char *flushb;
int flushp;
@ -88,15 +88,84 @@ static int flush_update(void)
return 0;
}
static void print_tcp_metrics(struct rtattr *a)
{
struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
unsigned long rtt = 0, rttvar = 0;
int i;
parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
const char *name;
__u32 val;
SPRINT_BUF(b1);
a = m[i + 1];
if (!a)
continue;
val = rta_getattr_u32(a);
switch (i) {
case TCP_METRIC_RTT:
if (!rtt)
rtt = (val * 1000UL) >> 3;
continue;
case TCP_METRIC_RTTVAR:
if (!rttvar)
rttvar = (val * 1000UL) >> 2;
continue;
case TCP_METRIC_RTT_US:
rtt = val >> 3;
continue;
case TCP_METRIC_RTTVAR_US:
rttvar = val >> 2;
continue;
case TCP_METRIC_SSTHRESH:
case TCP_METRIC_CWND:
case TCP_METRIC_REORDERING:
name = metric_name[i];
break;
default:
snprintf(b1, sizeof(b1),
" metric_%d ", i);
name = b1;
}
print_uint(PRINT_JSON, name, NULL, val);
print_string(PRINT_FP, NULL, " %s ", name);
print_uint(PRINT_FP, NULL, "%lu", val);
}
if (rtt) {
print_float(PRINT_JSON, "rtt", NULL,
(double)rtt / usec_per_sec);
print_uint(PRINT_FP, NULL,
" rtt %luus", rtt);
}
if (rttvar) {
print_float(PRINT_JSON, "rttvar", NULL,
(double) rttvar / usec_per_sec);
print_uint(PRINT_FP, NULL,
" rttvar %luus", rttvar);
}
}
static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
void *arg)
{
FILE *fp = (FILE *) arg;
struct genlmsghdr *ghdr;
struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a;
const char *h;
int len = n->nlmsg_len;
inet_prefix daddr, saddr;
int i, atype, stype;
int atype, stype;
if (n->nlmsg_type != genl_family)
return -1;
@ -186,96 +255,60 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
return 0;
}
open_json_object(NULL);
if (f.cmd & (CMD_DEL | CMD_FLUSH))
fprintf(fp, "Deleted ");
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
fprintf(fp, "%s",
format_host(daddr.family, daddr.bytelen, daddr.data));
h = format_host(daddr.family, daddr.bytelen, daddr.data);
print_color_string(PRINT_ANY,
ifa_family_color(daddr.family),
"dst", "%s", h);
a = attrs[TCP_METRICS_ATTR_AGE];
if (a) {
unsigned long long val = rta_getattr_u64(a);
__u64 val = rta_getattr_u64(a);
double age = val / 1000.;
fprintf(fp, " age %llu.%03llusec",
val / 1000, val % 1000);
print_float(PRINT_ANY, "age",
" age %.03fsec", age);
}
a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP];
if (a) {
__s32 val = (__s32) rta_getattr_u32(a);
__u32 tsval;
char tw_ts[64];
a = attrs[TCP_METRICS_ATTR_TW_TSVAL];
tsval = a ? rta_getattr_u32(a) : 0;
fprintf(fp, " tw_ts %u/%dsec ago", tsval, val);
snprintf(tw_ts, sizeof(tw_ts),
"%u/%d", tsval, val);
print_string(PRINT_ANY, "tw_ts_stamp",
" tw_ts %s ago", tw_ts);
}
a = attrs[TCP_METRICS_ATTR_VALS];
if (a) {
struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
unsigned long rtt = 0, rttvar = 0;
parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
unsigned long val;
a = m[i + 1];
if (!a)
continue;
if (i != TCP_METRIC_RTT &&
i != TCP_METRIC_RTT_US &&
i != TCP_METRIC_RTTVAR &&
i != TCP_METRIC_RTTVAR_US) {
if (metric_name[i])
fprintf(fp, " %s ", metric_name[i]);
else
fprintf(fp, " metric_%d ", i);
}
val = rta_getattr_u32(a);
switch (i) {
case TCP_METRIC_RTT:
if (!rtt)
rtt = (val * 1000UL) >> 3;
break;
case TCP_METRIC_RTTVAR:
if (!rttvar)
rttvar = (val * 1000UL) >> 2;
break;
case TCP_METRIC_RTT_US:
rtt = val >> 3;
break;
case TCP_METRIC_RTTVAR_US:
rttvar = val >> 2;
break;
case TCP_METRIC_SSTHRESH:
case TCP_METRIC_CWND:
case TCP_METRIC_REORDERING:
default:
fprintf(fp, "%lu", val);
break;
}
}
if (rtt)
fprintf(fp, " rtt %luus", rtt);
if (rttvar)
fprintf(fp, " rttvar %luus", rttvar);
}
if (attrs[TCP_METRICS_ATTR_VALS])
print_tcp_metrics(attrs[TCP_METRICS_ATTR_VALS]);
a = attrs[TCP_METRICS_ATTR_FOPEN_MSS];
if (a)
fprintf(fp, " fo_mss %u", rta_getattr_u16(a));
if (a) {
print_uint(PRINT_ANY, "fopen_miss", " fo_mss %u",
rta_getattr_u16(a));
}
a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS];
if (a) {
__u16 syn_loss = rta_getattr_u16(a);
unsigned long long ts;
double ts;
a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS];
ts = a ? rta_getattr_u64(a) : 0;
fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago",
syn_loss, ts / 1000, ts % 1000);
print_uint(PRINT_ANY, "fopen_syn_drops",
" fo_syn_drops %u", syn_loss);
print_float(PRINT_ANY, "fopen_syn_drop_ts",
"/%.03fusec ago",
ts / 1000000.);
}
a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE];
@ -289,16 +322,21 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
cookie[0] = 0;
for (i = 0; i < max; i++)
sprintf(cookie + i + i, "%02x", ptr[i]);
fprintf(fp, " fo_cookie %s", cookie);
print_string(PRINT_ANY, "fo_cookie",
" fo_cookie %s", cookie);
}
if (saddr.family) {
fprintf(fp, " source %s",
format_host(saddr.family, saddr.bytelen, saddr.data));
const char *src;
src = format_host(saddr.family, saddr.bytelen, saddr.data);
print_string(PRINT_ANY, "source",
" source %s", src);
}
fprintf(fp, "\n");
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(fp);
return 0;
}
@ -475,10 +513,12 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
}
return 0;
}