mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2026-01-08 19:47:40 +00:00
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:
commit
65745eae83
@ -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;
|
||||
}
|
||||
|
||||
56
ip/ipfou.c
56
ip/ipfou.c
@ -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);
|
||||
}
|
||||
|
||||
138
ip/ipneigh.c
138
ip/ipneigh.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
404
ip/ipntable.c
404
ip/ipntable.c
@ -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;
|
||||
}
|
||||
|
||||
184
ip/iprule.c
184
ip/iprule.c
@ -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;
|
||||
}
|
||||
|
||||
93
ip/ipseg6.c
93
ip/ipseg6.c
@ -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;
|
||||
|
||||
18
ip/iptoken.c
18
ip/iptoken.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
188
ip/tcp_metrics.c
188
ip/tcp_metrics.c
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user