SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man
-LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
+LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a
LDLIBS += $(LIBNETLINK)
all: config.mk
#define MDB_RTR_RTA(r) \
((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
-extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
+extern void print_vlan_info(FILE *fp, struct rtattr *tb);
extern int print_linkinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n,
void *arg);
extern int show_details;
extern int timestamp;
extern int compress_vlans;
-extern int json_output;
+extern int json;
extern struct rtnl_handle rth;
#include "utils.h"
#include "br_common.h"
#include "namespace.h"
+#include "color.h"
struct rtnl_handle rth = { .fd = -1 };
int preferred_family = AF_UNSPEC;
int oneline;
int show_stats;
int show_details;
+int show_pretty;
+int color;
int compress_vlans;
-int json_output;
+int json;
int timestamp;
char *batch_file;
int force;
"where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
" -o[neline] | -t[imestamp] | -n[etns] name |\n"
-" -c[ompressvlans] -j{son} }\n");
+" -c[ompressvlans] -color -p[retty] -j{son} }\n");
exit(-1);
}
NEXT_ARG();
if (netns_switch(argv[1]))
exit(-1);
+ } else if (matches(opt, "-color") == 0) {
+ enable_color();
} else if (matches(opt, "-compressvlans") == 0) {
++compress_vlans;
} else if (matches(opt, "-force") == 0) {
++force;
} else if (matches(opt, "-json") == 0) {
- ++json_output;
+ ++json;
+ } else if (matches(opt, "-pretty") == 0) {
+ ++pretty;
} else if (matches(opt, "-batch") == 0) {
argc--;
argv++;
_SL_ = oneline ? "\\" : "\n";
+ if (color && !json)
+ enable_color();
+
if (batch_file)
return batch(batch_file);
#include <linux/neighbour.h>
#include <string.h>
#include <limits.h>
-#include <json_writer.h>
#include <stdbool.h>
+#include "json_print.h"
#include "libnetlink.h"
#include "br_common.h"
#include "rt_names.h"
static unsigned int filter_index, filter_vlan, filter_state;
-json_writer_t *jw_global;
-
static void usage(void)
{
fprintf(stderr,
"Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
- " [ self ] [ master ] [ use ] [ router ]\n"
+ " [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n"
" [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n"
" [ port PORT] [ vni VNI ] [ via DEV ]\n"
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n");
return 0;
}
-static void start_json_fdb_flags_array(bool *fdb_flags)
+static void fdb_print_flags(FILE *fp, unsigned int flags)
{
- if (*fdb_flags)
- return;
- jsonw_name(jw_global, "flags");
- jsonw_start_array(jw_global);
- *fdb_flags = true;
+ open_json_array(PRINT_JSON,
+ is_json_context() ? "flags" : "");
+
+ if (flags & NTF_SELF)
+ print_string(PRINT_ANY, NULL, "%s ", "self");
+
+ if (flags & NTF_ROUTER)
+ print_string(PRINT_ANY, NULL, "%s ", "router");
+
+ if (flags & NTF_EXT_LEARNED)
+ print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
+
+ if (flags & NTF_OFFLOADED)
+ print_string(PRINT_ANY, NULL, "%s ", "offload");
+
+ if (flags & NTF_MASTER)
+ print_string(PRINT_ANY, NULL, "%s ", "master");
+
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
+{
+ static int hz;
+
+ if (!hz)
+ hz = get_user_hz();
+
+ if (is_json_context()) {
+ print_uint(PRINT_JSON, "used", NULL,
+ ci->ndm_used / hz);
+ print_uint(PRINT_JSON, "updated", NULL,
+ ci->ndm_updated / hz);
+ } else {
+ fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
+ ci->ndm_updated / hz);
+
+ }
}
int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
int len = n->nlmsg_len;
struct rtattr *tb[NDA_MAX+1];
__u16 vid = 0;
- bool fdb_flags = false;
- const char *state_s;
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
if (filter_vlan && filter_vlan != vid)
return 0;
- if (jw_global) {
- jsonw_pretty(jw_global, 1);
- jsonw_start_object(jw_global);
- }
-
- if (n->nlmsg_type == RTM_DELNEIGH) {
- if (jw_global)
- jsonw_string_field(jw_global, "opCode", "deleted");
- else
- fprintf(fp, "Deleted ");
- }
+ open_json_object(NULL);
+ if (n->nlmsg_type == RTM_DELNEIGH)
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (tb[NDA_LLADDR]) {
+ const char *lladdr;
SPRINT_BUF(b1);
- ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
- RTA_PAYLOAD(tb[NDA_LLADDR]),
- ll_index_to_type(r->ndm_ifindex),
- b1, sizeof(b1));
- if (jw_global)
- jsonw_string_field(jw_global, "mac", b1);
- else
- fprintf(fp, "%s ", b1);
+
+ lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+ RTA_PAYLOAD(tb[NDA_LLADDR]),
+ ll_index_to_type(r->ndm_ifindex),
+ b1, sizeof(b1));
+
+ print_color_string(PRINT_ANY, COLOR_MAC,
+ "mac", "%s ", lladdr);
}
if (!filter_index && r->ndm_ifindex) {
- if (jw_global)
- jsonw_string_field(jw_global, "dev",
- ll_index_to_name(r->ndm_ifindex));
- else
- fprintf(fp, "dev %s ",
- ll_index_to_name(r->ndm_ifindex));
+ if (!is_json_context())
+ fprintf(fp, "dev ");
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "ifname", "%s ",
+ ll_index_to_name(r->ndm_ifindex));
}
if (tb[NDA_DST]) {
int family = AF_INET;
- const char *abuf_s;
+ const char *dst;
if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
family = AF_INET6;
- abuf_s = format_host(family,
- RTA_PAYLOAD(tb[NDA_DST]),
- RTA_DATA(tb[NDA_DST]));
- if (jw_global)
- jsonw_string_field(jw_global, "dst", abuf_s);
- else
- fprintf(fp, "dst %s ", abuf_s);
- }
+ dst = format_host(family,
+ RTA_PAYLOAD(tb[NDA_DST]),
+ RTA_DATA(tb[NDA_DST]));
- if (vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vlan", vid);
- else
- fprintf(fp, "vlan %hu ", vid);
+ print_color_string(PRINT_ANY,
+ ifa_family_color(family),
+ "dst", "%s ", dst);
}
- if (tb[NDA_PORT]) {
- if (jw_global)
- jsonw_uint_field(jw_global, "port",
- rta_getattr_be16(tb[NDA_PORT]));
- else
- fprintf(fp, "port %d ",
- rta_getattr_be16(tb[NDA_PORT]));
- }
+ if (vid)
+ print_uint(PRINT_ANY,
+ "vlan", "vlan %hu ", vid);
- if (tb[NDA_VNI]) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vni",
- rta_getattr_u32(tb[NDA_VNI]));
- else
- fprintf(fp, "vni %d ",
- rta_getattr_u32(tb[NDA_VNI]));
- }
+ if (tb[NDA_PORT])
+ print_uint(PRINT_ANY,
+ "port", "port %u ",
+ rta_getattr_be16(tb[NDA_PORT]));
- if (tb[NDA_SRC_VNI]) {
- if (jw_global)
- jsonw_uint_field(jw_global, "src_vni",
- rta_getattr_u32(tb[NDA_SRC_VNI]));
- else
- fprintf(fp, "src_vni %d ",
+ if (tb[NDA_VNI])
+ print_uint(PRINT_ANY,
+ "vni", "vni %u ",
+ rta_getattr_u32(tb[NDA_VNI]));
+
+ if (tb[NDA_SRC_VNI])
+ print_uint(PRINT_ANY,
+ "src_vni", "src_vni %u ",
rta_getattr_u32(tb[NDA_SRC_VNI]));
- }
if (tb[NDA_IFINDEX]) {
unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
- if (ifindex) {
- if (!tb[NDA_LINK_NETNSID]) {
- const char *ifname = ll_index_to_name(ifindex);
-
- if (jw_global)
- jsonw_string_field(jw_global, "viaIf",
- ifname);
- else
- fprintf(fp, "via %s ", ifname);
- } else {
- if (jw_global)
- jsonw_uint_field(jw_global, "viaIfIndex",
- ifindex);
- else
- fprintf(fp, "via ifindex %u ", ifindex);
- }
- }
- }
-
- if (tb[NDA_LINK_NETNSID]) {
- if (jw_global)
- jsonw_uint_field(jw_global, "linkNetNsId",
- rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+ if (tb[NDA_LINK_NETNSID])
+ print_uint(PRINT_ANY,
+ "viaIfIndex", "via ifindex %u ",
+ ifindex);
else
- fprintf(fp, "link-netnsid %d ",
- rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+ print_string(PRINT_ANY,
+ "viaIf", "via %s ",
+ ll_index_to_name(ifindex));
}
- if (show_stats && tb[NDA_CACHEINFO]) {
- struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
- int hz = get_user_hz();
+ if (tb[NDA_LINK_NETNSID])
+ print_uint(PRINT_ANY,
+ "linkNetNsId", "link-netnsid %d ",
+ rta_getattr_u32(tb[NDA_LINK_NETNSID]));
- if (jw_global) {
- jsonw_uint_field(jw_global, "used",
- ci->ndm_used/hz);
- jsonw_uint_field(jw_global, "updated",
- ci->ndm_updated/hz);
- } else {
- fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
- ci->ndm_updated/hz);
- }
- }
+ if (show_stats && tb[NDA_CACHEINFO])
+ fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
- if (jw_global) {
- if (r->ndm_flags & NTF_SELF) {
- start_json_fdb_flags_array(&fdb_flags);
- jsonw_string(jw_global, "self");
- }
- if (r->ndm_flags & NTF_ROUTER) {
- start_json_fdb_flags_array(&fdb_flags);
- jsonw_string(jw_global, "router");
- }
- if (r->ndm_flags & NTF_EXT_LEARNED) {
- start_json_fdb_flags_array(&fdb_flags);
- jsonw_string(jw_global, "extern_learn");
- }
- if (r->ndm_flags & NTF_OFFLOADED) {
- start_json_fdb_flags_array(&fdb_flags);
- jsonw_string(jw_global, "offload");
- }
- if (r->ndm_flags & NTF_MASTER)
- jsonw_string(jw_global, "master");
- if (fdb_flags)
- jsonw_end_array(jw_global);
+ fdb_print_flags(fp, r->ndm_flags);
- if (tb[NDA_MASTER])
- jsonw_string_field(jw_global,
- "master",
- ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
- } else {
- if (r->ndm_flags & NTF_SELF)
- fprintf(fp, "self ");
- if (r->ndm_flags & NTF_ROUTER)
- fprintf(fp, "router ");
- if (r->ndm_flags & NTF_EXT_LEARNED)
- fprintf(fp, "extern_learn ");
- if (r->ndm_flags & NTF_OFFLOADED)
- fprintf(fp, "offload ");
- if (tb[NDA_MASTER]) {
- fprintf(fp, "master %s ",
- ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
- } else if (r->ndm_flags & NTF_MASTER) {
- fprintf(fp, "master ");
- }
- }
-
- state_s = state_n2a(r->ndm_state);
- if (jw_global) {
- if (state_s[0])
- jsonw_string_field(jw_global, "state", state_s);
-
- jsonw_end_object(jw_global);
- } else {
- fprintf(fp, "%s\n", state_s);
-
- fflush(fp);
- }
+ if (tb[NDA_MASTER])
+ print_string(PRINT_ANY, "master", "%s ",
+ ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
+ print_string(PRINT_ANY, "state", "%s\n",
+ state_n2a(r->ndm_state));
+ close_json_object();
+ fflush(fp);
return 0;
}
/*we'll keep around filter_dev for older kernels */
if (filter_dev) {
filter_index = ll_name_to_index(filter_dev);
- if (filter_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- filter_dev);
- return -1;
- }
+ if (!filter_index)
+ return nodev(filter_dev);
req.ifm.ifi_index = filter_index;
}
exit(1);
}
- if (json_output) {
- jw_global = jsonw_new(stdout);
- if (!jw_global) {
- fprintf(stderr, "Error allocation json object\n");
- exit(1);
- }
- jsonw_start_array(jw_global);
- }
+ new_json_obj(json);
if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
- if (jw_global) {
- jsonw_end_array(jw_global);
- jsonw_destroy(&jw_global);
- }
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
} else if (strcmp(*argv, "via") == 0) {
NEXT_ARG();
via = ll_name_to_index(*argv);
- if (via == 0)
- invarg("invalid device\n", *argv);
+ if (!via)
+ exit(nodev(*argv));
} else if (strcmp(*argv, "self") == 0) {
req.ndm.ndm_flags |= NTF_SELF;
} else if (matches(*argv, "master") == 0) {
vid = atoi(*argv);
} else if (matches(*argv, "use") == 0) {
req.ndm.ndm_flags |= NTF_USE;
+ } else if (matches(*argv, "extern_learn") == 0) {
+ req.ndm.ndm_flags |= NTF_EXT_LEARNED;
} else {
if (strcmp(*argv, "to") == 0)
NEXT_ARG();
addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);
req.ndm.ndm_ifindex = ll_name_to_index(d);
- if (req.ndm.ndm_ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ if (!req.ndm.ndm_ifindex)
+ return nodev(d);
if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -1;
#include <string.h>
#include <stdbool.h>
+#include "json_print.h"
#include "libnetlink.h"
#include "utils.h"
#include "br_common.h"
[BR_STATE_BLOCKING] = "blocking",
};
-static void print_link_flags(FILE *fp, unsigned int flags)
+static const char *hw_mode[] = {
+ "VEB", "VEPA"
+};
+
+static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
{
- fprintf(fp, "<");
+ open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
if (flags & IFF_UP && !(flags & IFF_RUNNING))
- fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+ print_string(PRINT_ANY, NULL,
+ flags ? "%s," : "%s", "NO-CARRIER");
flags &= ~IFF_RUNNING;
-#define _PF(f) if (flags&IFF_##f) { \
- flags &= ~IFF_##f ; \
- fprintf(fp, #f "%s", flags ? "," : ""); }
+
+#define _PF(f) if (flags&IFF_##f) { \
+ flags &= ~IFF_##f ; \
+ print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
_PF(LOOPBACK);
_PF(BROADCAST);
_PF(POINTOPOINT);
_PF(ECHO);
#undef _PF
if (flags)
- fprintf(fp, "%x", flags);
- fprintf(fp, "> ");
+ print_hex(PRINT_ANY, NULL, "%x", flags);
+ if (mdown)
+ print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+ close_json_array(PRINT_ANY, "> ");
}
-static const char *oper_states[] = {
- "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
- "TESTING", "DORMANT", "UP"
-};
-
-static const char *hw_mode[] = {"VEB", "VEPA"};
+static void print_portstate(__u8 state)
+{
+ if (state <= BR_STATE_BLOCKING)
+ print_string(PRINT_ANY, "state",
+ "state %s ", port_states[state]);
+ else
+ print_uint(PRINT_ANY, "state",
+ "state (%d) ", state);
+}
-static void print_operstate(FILE *f, __u8 state)
+static void print_onoff(FILE *fp, const char *flag, __u8 val)
{
- if (state >= ARRAY_SIZE(oper_states))
- fprintf(f, "state %#x ", state);
+ if (is_json_context())
+ print_bool(PRINT_JSON, flag, NULL, val);
else
- fprintf(f, "state %s ", oper_states[state]);
+ fprintf(fp, "%s %s ", flag, val ? "on" : "off");
}
-static void print_portstate(FILE *f, __u8 state)
+static void print_hwmode(__u16 mode)
{
- if (state <= BR_STATE_BLOCKING)
- fprintf(f, "state %s ", port_states[state]);
+ if (mode >= ARRAY_SIZE(hw_mode))
+ print_0xhex(PRINT_ANY, "hwmode",
+ "hwmode %#hx ", mode);
else
- fprintf(f, "state (%d) ", state);
+ print_string(PRINT_ANY, "hwmode",
+ "hwmode %s ", hw_mode[mode]);
}
-static void print_onoff(FILE *f, char *flag, __u8 val)
+static void print_protinfo(FILE *fp, struct rtattr *attr)
{
- fprintf(f, "%s %s ", flag, val ? "on" : "off");
+ if (attr->rta_type & NLA_F_NESTED) {
+ struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
+
+ parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
+
+ if (prtb[IFLA_BRPORT_STATE])
+ print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+
+ if (prtb[IFLA_BRPORT_PRIORITY])
+ print_uint(PRINT_ANY, "priority",
+ "priority %u ",
+ rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
+
+ if (prtb[IFLA_BRPORT_COST])
+ print_uint(PRINT_ANY, "cost",
+ "cost %u ",
+ rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
+
+ if (!show_details)
+ return;
+
+ if (!is_json_context())
+ fprintf(fp, "%s ", _SL_);
+
+ if (prtb[IFLA_BRPORT_MODE])
+ print_onoff(fp, "hairpin",
+ rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
+ if (prtb[IFLA_BRPORT_GUARD])
+ print_onoff(fp, "guard",
+ rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
+ if (prtb[IFLA_BRPORT_PROTECT])
+ print_onoff(fp, "root_block",
+ rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
+ if (prtb[IFLA_BRPORT_FAST_LEAVE])
+ print_onoff(fp, "fastleave",
+ rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
+ if (prtb[IFLA_BRPORT_LEARNING])
+ print_onoff(fp, "learning",
+ rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
+ if (prtb[IFLA_BRPORT_LEARNING_SYNC])
+ print_onoff(fp, "learning_sync",
+ rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
+ if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
+ print_onoff(fp, "flood",
+ rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
+ if (prtb[IFLA_BRPORT_MCAST_FLOOD])
+ print_onoff(fp, "mcast_flood",
+ rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
+ if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
+ print_onoff(fp, "neigh_suppress",
+ rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
+ if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
+ print_onoff(fp, "vlan_tunnel",
+ rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
+ } else
+ print_portstate(rta_getattr_u8(attr));
}
-static void print_hwmode(FILE *f, __u16 mode)
+
+/*
+ * This is reported by HW devices that have some bridging
+ * capabilities.
+ */
+static void print_af_spec(FILE *fp, struct rtattr *attr)
{
- if (mode >= ARRAY_SIZE(hw_mode))
- fprintf(f, "hwmode %#hx ", mode);
- else
- fprintf(f, "hwmode %s ", hw_mode[mode]);
+ struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
+
+ parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
+
+ if (aftb[IFLA_BRIDGE_MODE])
+ print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+
+ if (!show_details)
+ return;
+
+ if (aftb[IFLA_BRIDGE_VLAN_INFO])
+ print_vlan_info(fp, aftb[IFLA_BRIDGE_VLAN_INFO]);
}
int print_linkinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
FILE *fp = arg;
- int len = n->nlmsg_len;
struct ifinfomsg *ifi = NLMSG_DATA(n);
struct rtattr *tb[IFLA_MAX+1];
+ unsigned int m_flag = 0;
+ int len = n->nlmsg_len;
+ const char *name;
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0) {
parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
- if (tb[IFLA_IFNAME] == NULL) {
- fprintf(stderr, "BUG: nil ifname\n");
+ name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
+ if (!name)
return -1;
- }
+ open_json_object(NULL);
if (n->nlmsg_type == RTM_DELLINK)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
- fprintf(fp, "%d: %s ", ifi->ifi_index,
- tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
-
- if (tb[IFLA_OPERSTATE])
- print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
-
- if (tb[IFLA_LINK]) {
- int iflink = rta_getattr_u32(tb[IFLA_LINK]);
-
- fprintf(fp, "@%s: ",
- iflink ? ll_index_to_name(iflink) : "NONE");
- } else
- fprintf(fp, ": ");
-
- print_link_flags(fp, ifi->ifi_flags);
+ print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
+ m_flag = print_name_and_link("%s: ", name, tb);
+ print_link_flags(fp, ifi->ifi_flags, m_flag);
if (tb[IFLA_MTU])
- fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+ print_int(PRINT_ANY,
+ "mtu", "mtu %u ",
+ rta_getattr_u32(tb[IFLA_MTU]));
if (tb[IFLA_MASTER]) {
int master = rta_getattr_u32(tb[IFLA_MASTER]);
- fprintf(fp, "master %s ", ll_index_to_name(master));
+ print_string(PRINT_ANY, "master", "master %s ",
+ ll_index_to_name(master));
}
- if (tb[IFLA_PROTINFO]) {
- if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
- struct rtattr *prtb[IFLA_BRPORT_MAX+1];
-
- parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
- tb[IFLA_PROTINFO]);
-
- if (prtb[IFLA_BRPORT_STATE])
- print_portstate(fp,
- rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
- if (prtb[IFLA_BRPORT_PRIORITY])
- fprintf(fp, "priority %hu ",
- rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
- if (prtb[IFLA_BRPORT_COST])
- fprintf(fp, "cost %u ",
- rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
-
- if (show_details) {
- fprintf(fp, "%s ", _SL_);
-
- if (prtb[IFLA_BRPORT_MODE])
- print_onoff(fp, "hairpin",
- rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
- if (prtb[IFLA_BRPORT_GUARD])
- print_onoff(fp, "guard",
- rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
- if (prtb[IFLA_BRPORT_PROTECT])
- print_onoff(fp, "root_block",
- rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
- if (prtb[IFLA_BRPORT_FAST_LEAVE])
- print_onoff(fp, "fastleave",
- rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
- if (prtb[IFLA_BRPORT_LEARNING])
- print_onoff(fp, "learning",
- rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
- if (prtb[IFLA_BRPORT_LEARNING_SYNC])
- print_onoff(fp, "learning_sync",
- rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
- if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
- print_onoff(fp, "flood",
- rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
- if (prtb[IFLA_BRPORT_MCAST_FLOOD])
- print_onoff(fp, "mcast_flood",
- rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
- if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
- print_onoff(fp, "neigh_suppress",
- rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
- if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
- print_onoff(fp, "vlan_tunnel",
- rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
- }
- } else
- print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
- }
+ if (tb[IFLA_PROTINFO])
+ print_protinfo(fp, tb[IFLA_PROTINFO]);
- if (tb[IFLA_AF_SPEC]) {
- /* This is reported by HW devices that have some bridging
- * capabilities.
- */
- struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
-
- parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
-
- if (aftb[IFLA_BRIDGE_MODE])
- print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
- if (show_details) {
- if (aftb[IFLA_BRIDGE_VLAN_INFO]) {
- fprintf(fp, "\n");
- print_vlan_info(fp, tb[IFLA_AF_SPEC],
- ifi->ifi_index);
- }
- }
- }
+ if (tb[IFLA_AF_SPEC])
+ print_af_spec(fp, tb[IFLA_AF_SPEC]);
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "%s", "\n");
+ close_json_object();
fflush(fp);
return 0;
}
}
if (filter_dev) {
- if ((filter_index = ll_name_to_index(filter_dev)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- filter_dev);
- return -1;
- }
+ filter_index = ll_name_to_index(filter_dev);
+ if (!filter_index)
+ return nodev(filter_dev);
}
if (show_details) {
}
}
+ new_json_obj(json);
if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
#include <linux/if_ether.h>
#include <string.h>
#include <arpa/inet.h>
-#include <json_writer.h>
#include "libnetlink.h"
#include "br_common.h"
#include "rt_names.h"
#include "utils.h"
+#include "json_print.h"
#ifndef MDBA_RTA
#define MDBA_RTA(r) \
#endif
static unsigned int filter_index, filter_vlan;
-json_writer_t *jw_global;
-static bool print_mdb_entries = true;
-static bool print_mdb_router = true;
static void usage(void)
{
return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
}
+static const char *format_timer(__u32 ticks)
+{
+ struct timeval tv;
+ static char tbuf[32];
+
+ __jiffies_to_tv(&tv, ticks);
+ snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
+ (unsigned long)tv.tv_sec,
+ (unsigned long)tv.tv_usec / 10000);
+
+ return tbuf;
+}
+
static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
{
struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
- struct timeval tv;
- __u8 type;
parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
+
if (tb[MDBA_ROUTER_PATTR_TIMER]) {
- __jiffies_to_tv(&tv,
- rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
- if (jw_global) {
- char formatted_time[9];
-
- snprintf(formatted_time, sizeof(formatted_time),
- "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- jsonw_string_field(jw_global, "timer", formatted_time);
- } else {
- fprintf(f, " %4i.%.2i",
- (int)tv.tv_sec, (int)tv.tv_usec/10000);
- }
+ __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
+
+ print_string(PRINT_ANY, "timer", " %s",
+ format_timer(timer));
}
+
if (tb[MDBA_ROUTER_PATTR_TYPE]) {
- type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
- if (jw_global)
- jsonw_string_field(jw_global, "type",
- is_temp_mcast_rtr(type) ? "temp" : "permanent");
- else
- fprintf(f, " %s",
- is_temp_mcast_rtr(type) ? "temp" : "permanent");
+ __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
+
+ print_string(PRINT_ANY, "type", " %s",
+ is_temp_mcast_rtr(type) ? "temp" : "permanent");
}
}
-static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
+static void br_print_router_ports(FILE *f, struct rtattr *attr,
+ const char *brifname)
{
- uint32_t *port_ifindex;
+ int rem = RTA_PAYLOAD(attr);
struct rtattr *i;
- int rem;
- rem = RTA_PAYLOAD(attr);
- if (jw_global) {
- jsonw_name(jw_global, ll_index_to_name(brifidx));
- jsonw_start_array(jw_global);
- for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
- port_ifindex = RTA_DATA(i);
- jsonw_start_object(jw_global);
- jsonw_string_field(jw_global,
- "port",
- ll_index_to_name(*port_ifindex));
+ if (is_json_context())
+ open_json_array(PRINT_JSON, brifname);
+ else if (!show_stats)
+ fprintf(f, "router ports on %s: ", brifname);
+
+ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ uint32_t *port_ifindex = RTA_DATA(i);
+ const char *port_ifname = ll_index_to_name(*port_ifindex);
+
+ if (is_json_context()) {
+ open_json_object(NULL);
+ print_string(PRINT_JSON, "port", NULL, port_ifname);
+
if (show_stats)
__print_router_port_stats(f, i);
- jsonw_end_object(jw_global);
- }
- jsonw_end_array(jw_global);
- } else {
- if (!show_stats)
- fprintf(f, "router ports on %s: ",
- ll_index_to_name(brifidx));
- for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
- port_ifindex = RTA_DATA(i);
- if (show_stats) {
- fprintf(f, "router ports on %s: %s",
- ll_index_to_name(brifidx),
- ll_index_to_name(*port_ifindex));
- __print_router_port_stats(f, i);
- fprintf(f, "\n");
- } else{
- fprintf(f, "%s ",
- ll_index_to_name(*port_ifindex));
- }
- }
- if (!show_stats)
+ close_json_object();
+ } else if (show_stats) {
+ fprintf(f, "router ports on %s: %s",
+ brifname, port_ifname);
+
+ __print_router_port_stats(f, i);
fprintf(f, "\n");
+ } else {
+ fprintf(f, "%s ", port_ifname);
+ }
}
+ close_json_array(PRINT_JSON, NULL);
}
-static void start_json_mdb_flags_array(bool *mdb_flags)
-{
- if (*mdb_flags)
- return;
- jsonw_name(jw_global, "flags");
- jsonw_start_array(jw_global);
- *mdb_flags = true;
-}
-
-static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
+static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
struct nlmsghdr *n, struct rtattr **tb)
{
SPRINT_BUF(abuf);
+ const char *dev;
const void *src;
int af;
- bool mdb_flags = false;
if (filter_vlan && e->vid != filter_vlan)
return;
+
af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
(const void *)&e->addr.u.ip6;
- if (jw_global)
- jsonw_start_object(jw_global);
- if (n->nlmsg_type == RTM_DELMDB) {
- if (jw_global)
- jsonw_string_field(jw_global, "opCode", "deleted");
- else
- fprintf(f, "Deleted ");
- }
- if (jw_global) {
- jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
- jsonw_string_field(jw_global,
- "port",
- ll_index_to_name(e->ifindex));
- jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
- abuf, sizeof(abuf)));
- jsonw_string_field(jw_global, "state",
- (e->state & MDB_PERMANENT) ? "permanent" : "temp");
- if (e->flags & MDB_FLAGS_OFFLOAD) {
- start_json_mdb_flags_array(&mdb_flags);
- jsonw_string(jw_global, "offload");
- }
- if (mdb_flags)
- jsonw_end_array(jw_global);
- } else{
- fprintf(f, "dev %s port %s grp %s %s%s",
- ll_index_to_name(ifindex),
- ll_index_to_name(e->ifindex),
- inet_ntop(af, src, abuf, sizeof(abuf)),
- (e->state & MDB_PERMANENT) ? "permanent" : "temp",
- (e->flags & MDB_FLAGS_OFFLOAD) ? " offload" : "");
- }
- if (e->vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vid", e->vid);
- else
- fprintf(f, " vid %hu", e->vid);
+ dev = ll_index_to_name(ifindex);
+
+ open_json_object(NULL);
+
+ if (n->nlmsg_type == RTM_DELMDB)
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+
+ if (is_json_context()) {
+ print_int(PRINT_JSON, "index", NULL, ifindex);
+ print_string(PRINT_JSON, "dev", NULL, dev);
+ } else {
+ fprintf(f, "%u: ", ifindex);
+ color_fprintf(f, COLOR_IFNAME, "%s ", dev);
}
- if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
- struct timeval tv;
- __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
- if (jw_global) {
- char formatted_time[9];
+ print_string(PRINT_ANY, "port", " %s ",
+ ll_index_to_name(e->ifindex));
- snprintf(formatted_time, sizeof(formatted_time),
- "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- jsonw_string_field(jw_global, "timer", formatted_time);
- } else {
- fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- }
+ print_color_string(PRINT_ANY, ifa_family_color(af),
+ "grp", " %s ",
+ inet_ntop(af, src, abuf, sizeof(abuf)));
+
+ print_string(PRINT_ANY, "state", " %s ",
+ (e->state & MDB_PERMANENT) ? "permanent" : "temp");
+
+ open_json_array(PRINT_JSON, "flags");
+ if (e->flags & MDB_FLAGS_OFFLOAD)
+ print_string(PRINT_ANY, NULL, "%s ", "offload");
+ close_json_array(PRINT_JSON, NULL);
+
+ if (e->vid)
+ print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
+
+ if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
+ __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
+
+ print_string(PRINT_ANY, "timer", " %s",
+ format_timer(timer));
}
- if (jw_global)
- jsonw_end_object(jw_global);
- else
- fprintf(f, "\n");
+ close_json_object();
}
static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
}
}
+static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
+ int ifindex, struct rtattr *mdb)
+{
+ int rem = RTA_PAYLOAD(mdb);
+ struct rtattr *i;
+
+ open_json_array(PRINT_JSON, "mdb");
+ for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+ br_print_mdb_entry(fp, ifindex, i, n);
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_router_entries(FILE *fp, struct nlmsghdr *n,
+ int ifindex, struct rtattr *router)
+{
+ const char *brifname = ll_index_to_name(ifindex);
+
+ open_json_array(PRINT_JSON, "router");
+ if (n->nlmsg_type == RTM_GETMDB) {
+ if (show_details)
+ br_print_router_ports(fp, router, brifname);
+ } else {
+ struct rtattr *i = RTA_DATA(router);
+ uint32_t *port_ifindex = RTA_DATA(i);
+
+ if (is_json_context()) {
+ open_json_array(PRINT_JSON, brifname);
+ open_json_object(NULL);
+
+ print_string(PRINT_JSON, "port", NULL,
+ ll_index_to_name(*port_ifindex));
+ close_json_object();
+ close_json_array(PRINT_JSON, NULL);
+ } else {
+ fprintf(fp, "router port dev %s master %s\n",
+ ll_index_to_name(*port_ifindex),
+ brifname);
+ }
+ }
+ close_json_array(PRINT_JSON, NULL);
+}
+
int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = arg;
struct br_port_msg *r = NLMSG_DATA(n);
int len = n->nlmsg_len;
- struct rtattr *tb[MDBA_MAX+1], *i;
+ struct rtattr *tb[MDBA_MAX+1];
- if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
- fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
+ if (n->nlmsg_type != RTM_GETMDB &&
+ n->nlmsg_type != RTM_NEWMDB &&
+ n->nlmsg_type != RTM_DELMDB) {
+ fprintf(stderr,
+ "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- if (tb[MDBA_MDB] && print_mdb_entries) {
- int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
+ if (n->nlmsg_type == RTM_DELMDB)
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
- for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
- br_print_mdb_entry(fp, r->ifindex, i, n);
- }
-
- if (tb[MDBA_ROUTER] && print_mdb_router) {
- if (n->nlmsg_type == RTM_GETMDB) {
- if (show_details)
- br_print_router_ports(fp, tb[MDBA_ROUTER],
- r->ifindex);
- } else {
- uint32_t *port_ifindex;
-
- i = RTA_DATA(tb[MDBA_ROUTER]);
- port_ifindex = RTA_DATA(i);
- if (n->nlmsg_type == RTM_DELMDB) {
- if (jw_global)
- jsonw_string_field(jw_global,
- "opCode",
- "deleted");
- else
- fprintf(fp, "Deleted ");
- }
- if (jw_global) {
- jsonw_name(jw_global,
- ll_index_to_name(r->ifindex));
- jsonw_start_array(jw_global);
- jsonw_start_object(jw_global);
- jsonw_string_field(jw_global, "port",
- ll_index_to_name(*port_ifindex));
- jsonw_end_object(jw_global);
- jsonw_end_array(jw_global);
- } else {
- fprintf(fp, "router port dev %s master %s\n",
- ll_index_to_name(*port_ifindex),
- ll_index_to_name(r->ifindex));
- }
- }
- }
+ if (tb[MDBA_MDB])
+ print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
- if (!jw_global)
- fflush(fp);
+ if (tb[MDBA_ROUTER])
+ print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
return 0;
}
if (filter_dev) {
filter_index = ll_name_to_index(filter_dev);
- if (filter_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- filter_dev);
- return -1;
- }
+ if (!filter_index)
+ return nodev(filter_dev);
}
+ new_json_obj(json);
+
/* get mdb entries*/
if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
perror("Cannot send dump request");
return -1;
}
- if (!json_output) {
- /* Normal output */
- if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
- fprintf(stderr, "Dump terminated\n");
- return -1;
- }
- return 0;
- }
- /* Json output */
- jw_global = jsonw_new(stdout);
- jsonw_pretty(jw_global, 1);
- jsonw_start_object(jw_global);
- jsonw_name(jw_global, "mdb");
- jsonw_start_array(jw_global);
-
- /* print mdb entries */
- print_mdb_entries = true;
- print_mdb_router = false;
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
- jsonw_end_array(jw_global);
-
- /* get router ports */
- if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
- perror("Cannot send dump request");
- return -1;
- }
- jsonw_name(jw_global, "router");
- jsonw_start_object(jw_global);
- /* print router ports */
- print_mdb_entries = false;
- print_mdb_router = true;
- if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
- fprintf(stderr, "Dump terminated\n");
- return -1;
- }
- jsonw_end_object(jw_global);
- jsonw_end_object(jw_global);
- jsonw_destroy(&jw_global);
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
}
req.bpm.ifindex = ll_name_to_index(d);
- if (req.bpm.ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ if (!req.bpm.ifindex)
+ return nodev(d);
entry.ifindex = ll_name_to_index(p);
- if (entry.ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", p);
- return -1;
- }
+ if (!entry.ifindex)
+ return nodev(p);
if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
#include <netinet/in.h>
#include <linux/if_bridge.h>
#include <linux/if_ether.h>
-#include <json_writer.h>
#include <string.h>
+#include "json_print.h"
#include "libnetlink.h"
#include "br_common.h"
#include "utils.h"
static unsigned int filter_index, filter_vlan;
-static int last_ifidx = -1;
static int show_vlan_tunnel_info = 0;
-json_writer_t *jw_global;
-
static void usage(void)
{
fprintf(stderr,
static void print_vlan_port(FILE *fp, int ifi_index)
{
- if (jw_global) {
- jsonw_pretty(jw_global, 1);
- jsonw_name(jw_global,
- ll_index_to_name(ifi_index));
- jsonw_start_array(jw_global);
- } else {
- fprintf(fp, "%s",
- ll_index_to_name(ifi_index));
- }
+ print_string(PRINT_ANY, NULL, "%s",
+ ll_index_to_name(ifi_index));
}
-static void start_json_vlan_flags_array(bool *vlan_flags)
+static void print_range(const char *name, __u16 start, __u16 id)
{
- if (*vlan_flags)
- return;
- jsonw_name(jw_global, "flags");
- jsonw_start_array(jw_global);
- *vlan_flags = true;
+ char end[64];
+
+ snprintf(end, sizeof(end), "%sEnd", name);
+
+ print_hu(PRINT_ANY, name, "\t %hu", start);
+ if (start != id)
+ print_hu(PRINT_ANY, end, "-%hu", id);
+
}
static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
{
- bool jsonw_end_parray = false;
struct rtattr *i, *list = tb;
int rem = RTA_PAYLOAD(list);
__u16 last_vid_start = 0;
__u32 last_tunid_start = 0;
- if (!filter_vlan) {
+ if (!filter_vlan)
print_vlan_port(fp, ifindex);
- jsonw_end_parray = 1;
- }
+ open_json_array(PRINT_JSON, "tunnel");
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
__u32 tunnel_id = 0;
last_vid_start = tunnel_vid;
last_tunid_start = tunnel_id;
}
+
vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
if (vcheck_ret == -1)
break;
if (tunnel_flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
continue;
- if (filter_vlan) {
+ if (filter_vlan)
print_vlan_port(fp, ifindex);
- jsonw_end_parray = 1;
- }
- if (jw_global) {
- jsonw_start_object(jw_global);
- jsonw_uint_field(jw_global, "vlan",
- last_vid_start);
- } else {
- fprintf(fp, "\t %hu", last_vid_start);
- }
- if (last_vid_start != tunnel_vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vlanEnd",
- tunnel_vid);
- else
- fprintf(fp, "-%hu", tunnel_vid);
- }
-
- if (jw_global) {
- jsonw_uint_field(jw_global, "tunid",
- last_tunid_start);
- } else {
- fprintf(fp, "\t %hu", last_tunid_start);
- }
- if (last_vid_start != tunnel_vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "tunidEnd",
- tunnel_id);
- else
- fprintf(fp, "-%hu", tunnel_id);
- }
+ open_json_object(NULL);
+ print_range("vlan", last_vid_start, tunnel_vid);
+ print_range("tunid", last_tunid_start, tunnel_id);
+ close_json_object();
- if (jw_global)
- jsonw_end_object(jw_global);
- else
+ if (!is_json_context())
fprintf(fp, "\n");
- }
- if (jsonw_end_parray) {
- if (jw_global)
- jsonw_end_array(jw_global);
- else
- fprintf(fp, "\n");
}
+ close_json_array(PRINT_JSON, NULL);
}
static int print_vlan_tunnel(const struct sockaddr_nl *who,
/* if AF_SPEC isn't there, vlan table is not preset for this port */
if (!tb[IFLA_AF_SPEC]) {
- if (!filter_vlan && !jw_global)
- fprintf(fp, "%s\tNone\n",
- ll_index_to_name(ifm->ifi_index));
+ if (!filter_vlan && !is_json_context()) {
+ color_fprintf(fp, COLOR_IFNAME, "%s",
+ ll_index_to_name(ifm->ifi_index));
+ fprintf(fp, "\tNone\n");
+ }
return 0;
}
/* if AF_SPEC isn't there, vlan table is not preset for this port */
if (!tb[IFLA_AF_SPEC]) {
- if (!filter_vlan && !jw_global)
- fprintf(fp, "%s\tNone\n",
- ll_index_to_name(ifm->ifi_index));
+ if (!filter_vlan && !is_json_context()) {
+ color_fprintf(fp, COLOR_IFNAME, "%s",
+ ll_index_to_name(ifm->ifi_index));
+ fprintf(fp, "\tNone\n");
+ }
return 0;
}
- print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index);
+ print_vlan_port(fp, ifm->ifi_index);
+ print_vlan_info(fp, tb[IFLA_AF_SPEC]);
fflush(fp);
return 0;
}
-static void print_one_vlan_stats(FILE *fp,
- const struct bridge_vlan_xstats *vstats,
- int ifindex)
+static void print_vlan_flags(__u16 flags)
{
- const char *ifname = "";
+ if (flags & BRIDGE_VLAN_INFO_PVID)
+ print_null(PRINT_ANY, "pvid", " %s", "PVID");
- if (filter_vlan && filter_vlan != vstats->vid)
- return;
- /* skip pure port entries, they'll be dumped via the slave stats call */
- if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
- !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
- return;
+ if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+ print_null(PRINT_ANY, "untagged", " %s", "untagged");
+}
- if (last_ifidx != ifindex) {
- ifname = ll_index_to_name(ifindex);
- last_ifidx = ifindex;
- }
- fprintf(fp, "%-16s %hu", ifname, vstats->vid);
- if (vstats->flags & BRIDGE_VLAN_INFO_PVID)
- fprintf(fp, " PVID");
- if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED)
- fprintf(fp, " Egress Untagged");
- fprintf(fp, "\n");
- fprintf(fp, "%-16s RX: %llu bytes %llu packets\n",
- "", vstats->rx_bytes, vstats->rx_packets);
- fprintf(fp, "%-16s TX: %llu bytes %llu packets\n",
- "", vstats->tx_bytes, vstats->tx_packets);
+static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
+{
+ open_json_object(NULL);
+ print_hu(PRINT_ANY, "vid", " %hu", vstats->vid);
+
+ print_vlan_flags(vstats->flags);
+
+ print_lluint(PRINT_ANY, "rx_bytes",
+ "\n RX: %llu bytes",
+ vstats->rx_bytes);
+ print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
+ vstats->rx_packets);
+ print_lluint(PRINT_ANY, "tx_bytes",
+ " TX: %llu bytes",
+ vstats->tx_bytes);
+ print_lluint(PRINT_ANY, "tx_packets", " %llu packets",
+ vstats->tx_packets);
+ close_json_object();
}
-static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
+static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
{
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
struct rtattr *i, *list;
list = brtb[LINK_XSTATS_TYPE_BRIDGE];
rem = RTA_PAYLOAD(list);
+
+ open_json_object(NULL);
+
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "dev", "%-16s",
+ ll_index_to_name(ifindex));
+
+ open_json_array(PRINT_JSON, "xstats");
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
+
if (i->rta_type != BRIDGE_XSTATS_VLAN)
continue;
- print_one_vlan_stats(fp, RTA_DATA(i), ifindex);
+
+ if (filter_vlan && filter_vlan != vstats->vid)
+ continue;
+
+ /* skip pure port entries, they'll be dumped via the slave stats call */
+ if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
+ !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
+ continue;
+
+ print_one_vlan_stats(vstats);
}
+ close_json_array(PRINT_ANY, "\n");
+ close_json_object();
+
}
static int print_vlan_stats(const struct sockaddr_nl *who,
/* We have to check if any of the two attrs are usable */
if (tb[IFLA_STATS_LINK_XSTATS])
- print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
+ print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
ifsm->ifindex);
if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
- print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
+ print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
ifsm->ifindex);
fflush(fp);
if (filter_dev) {
filter_index = ll_name_to_index(filter_dev);
- if (filter_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- filter_dev);
- return -1;
- }
+ if (!filter_index)
+ return nodev(filter_dev);
}
+ new_json_obj(json);
+
if (!show_stats) {
if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
(compress_vlans ?
- RTEXT_FILTER_BRVLAN_COMPRESSED :
- RTEXT_FILTER_BRVLAN)) < 0) {
+ RTEXT_FILTER_BRVLAN_COMPRESSED :
+ RTEXT_FILTER_BRVLAN)) < 0) {
perror("Cannont send dump request");
exit(1);
}
- if (json_output) {
- jw_global = jsonw_new(stdout);
- if (!jw_global) {
- fprintf(stderr, "Error allocation json object\n");
- exit(1);
- }
- jsonw_start_object(jw_global);
- } else {
+
+ if (!is_json_context()) {
if (show_vlan_tunnel_info)
printf("port\tvlan ids\ttunnel id\n");
else
stdout);
else
ret = rtnl_dump_filter(&rth, print_vlan, stdout);
-
if (ret < 0) {
fprintf(stderr, "Dump ternminated\n");
exit(1);
exit(1);
}
- printf("%-16s vlan id\n", "port");
+ if (!is_json_context())
+ printf("%-16s vlan id\n", "port");
+
if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
}
- if (jw_global) {
- jsonw_end_object(jw_global);
- jsonw_destroy(&jw_global);
- }
-
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
-void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
+void print_vlan_info(FILE *fp, struct rtattr *tb)
{
struct rtattr *i, *list = tb;
int rem = RTA_PAYLOAD(list);
__u16 last_vid_start = 0;
- bool vlan_flags = false;
- bool jsonw_end_parray = false;
- if (!filter_vlan) {
- print_vlan_port(fp, ifindex);
- jsonw_end_parray = true;
- }
+ if (!is_json_context())
+ fprintf(fp, "%s", _SL_);
+
+ open_json_array(PRINT_JSON, "vlan");
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
struct bridge_vlan_info *vinfo;
else if (vcheck_ret == 0)
continue;
- if (filter_vlan) {
- print_vlan_port(fp, ifindex);
- jsonw_end_parray = true;
- }
- if (jw_global) {
- jsonw_start_object(jw_global);
- jsonw_uint_field(jw_global, "vlan",
- last_vid_start);
- if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
- continue;
- } else {
- fprintf(fp, "\t %hu", last_vid_start);
- }
- if (last_vid_start != vinfo->vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vlanEnd",
- vinfo->vid);
- else
- fprintf(fp, "-%hu", vinfo->vid);
- }
- if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
- if (jw_global) {
- start_json_vlan_flags_array(&vlan_flags);
- jsonw_string(jw_global, "PVID");
- } else {
- fprintf(fp, " PVID");
- }
- }
- if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
- if (jw_global) {
- start_json_vlan_flags_array(&vlan_flags);
- jsonw_string(jw_global,
- "Egress Untagged");
- } else {
- fprintf(fp, " Egress Untagged");
- }
- }
- if (jw_global && vlan_flags) {
- jsonw_end_array(jw_global);
- vlan_flags = false;
- }
+ open_json_object(NULL);
+ print_range("vlan", last_vid_start, vinfo->vid);
- if (jw_global)
- jsonw_end_object(jw_global);
- else
- fprintf(fp, "\n");
+ print_vlan_flags(vinfo->flags);
+ close_json_object();
}
- if (jsonw_end_parray) {
- if (jw_global)
- jsonw_end_array(jw_global);
- else
- fprintf(fp, "\n");
-
- }
+ close_json_array(PRINT_ANY, "\n");
}
int do_vlan(int argc, char **argv)
4 meta
7 canid
8 ipset
+9 ipt
void ll_init_map(struct rtnl_handle *rth);
unsigned ll_name_to_index(const char *name);
const char *ll_index_to_name(unsigned idx);
-const char *ll_idx_n2a(unsigned idx, char *buf);
int ll_index_to_type(unsigned idx);
int ll_index_to_flags(unsigned idx);
unsigned namehash(const char *str);
+const char *ll_idx_n2a(unsigned int idx);
+unsigned int ll_idx_a2n(const char *name);
+
#endif /* __LL_MAP_H__ */
/* BPF_FUNC_skb_set_tunnel_key flags. */
#define BPF_F_ZERO_CSUM_TX (1ULL << 1)
#define BPF_F_DONT_FRAGMENT (1ULL << 2)
+#define BPF_F_SEQ_NUMBER (1ULL << 3)
/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
* BPF_FUNC_perf_event_read_value flags.
__u8 tos;
__u8 table;
- __u8 res1; /* reserved */
+ __u8 res1; /* reserved */
__u8 res2; /* reserved */
__u8 action;
__u32 end;
};
+struct fib_rule_port_range {
+ __u16 start;
+ __u16 end;
+};
+
enum {
FRA_UNSPEC,
FRA_DST, /* destination address */
FRA_PAD,
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
FRA_UID_RANGE, /* UID range */
+ FRA_PROTOCOL, /* Originator of the rule */
+ FRA_IP_PROTO, /* ip proto */
+ FRA_SPORT_RANGE, /* sport */
+ FRA_DPORT_RANGE, /* dport */
__FRA_MAX
};
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
+#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */
#define ETH_P_TIPC 0x88CA /* TIPC */
#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */
};
+/* tun section */
+
+enum {
+ IFLA_TUN_UNSPEC,
+ IFLA_TUN_OWNER,
+ IFLA_TUN_GROUP,
+ IFLA_TUN_TYPE,
+ IFLA_TUN_PI,
+ IFLA_TUN_VNET_HDR,
+ IFLA_TUN_PERSIST,
+ IFLA_TUN_MULTI_QUEUE,
+ IFLA_TUN_NUM_QUEUES,
+ IFLA_TUN_NUM_DISABLED_QUEUES,
+ __IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
#endif /* _LINUX_IF_LINK_H */
enum {
TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
+ TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
};
/* Match-all classifier */
#define TCF_EM_VLAN 6
#define TCF_EM_CANID 7
#define TCF_EM_IPSET 8
-#define TCF_EM_MAX 8
+#define TCF_EM_IPT 9
+#define TCF_EM_MAX 9
enum {
TCF_EM_PROG_TC
sctp_assoc_t nxt_assoc_id;
};
+/* 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+ *
+ * This cmsghdr structure specifies SCTP options for sendmsg().
+ *
+ * cmsg_level cmsg_type cmsg_data[]
+ * ------------ ------------ -------------------
+ * IPPROTO_SCTP SCTP_PRINFO struct sctp_prinfo
+ */
+struct sctp_prinfo {
+ __u16 pr_policy;
+ __u32 pr_value;
+};
+
/*
* sinfo_flags: 16 bits (unsigned integer)
*
SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */
SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */
SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */
+ /* 2 bits here have been used by SCTP_PR_SCTP_MASK */
+ SCTP_SENDALL = (1 << 6),
SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */
SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
};
#define SCTP_RCVINFO SCTP_RCVINFO
SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */
#define SCTP_NXTINFO SCTP_NXTINFO
+ SCTP_PRINFO, /* 5.3.7 SCTP PR-SCTP Information Structure */
+#define SCTP_PRINFO SCTP_PRINFO
+ SCTP_AUTHINFO, /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO SCTP_AUTHINFO
+ SCTP_DSTADDRV4, /* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4 SCTP_DSTADDRV4
+ SCTP_DSTADDRV6, /* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6 SCTP_DSTADDRV6
} sctp_cmsg_t;
/*
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_TC_EM_IPT_H
+#define __LINUX_TC_EM_IPT_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+enum {
+ TCA_EM_IPT_UNSPEC,
+ TCA_EM_IPT_HOOK,
+ TCA_EM_IPT_MATCH_NAME,
+ TCA_EM_IPT_MATCH_REVISION,
+ TCA_EM_IPT_NFPROTO,
+ TCA_EM_IPT_MATCH_DATA,
+ __TCA_EM_IPT_MAX
+};
+
+#define TCA_EM_IPT_MAX (__TCA_EM_IPT_MAX - 1)
+
+#endif
TCP_NLA_MIN_RTT, /* minimum RTT */
TCP_NLA_RECUR_RETRANS, /* Recurring retransmits for the current pkt */
TCP_NLA_DELIVERY_RATE_APP_LMT, /* delivery rate application limited ? */
+ TCP_NLA_SNDQ_SIZE, /* Data (bytes) pending in send queue */
+ TCP_NLA_CA_STATE, /* ca_state of socket */
};
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _RDMA_NETLINK_H
-#define _RDMA_NETLINK_H
-
-#include <linux/types.h>
-
-enum {
- RDMA_NL_RDMA_CM = 1,
- RDMA_NL_IWCM,
- RDMA_NL_RSVD,
- RDMA_NL_LS, /* RDMA Local Services */
- RDMA_NL_NLDEV, /* RDMA device interface */
- RDMA_NL_NUM_CLIENTS
-};
-
-enum {
- RDMA_NL_GROUP_CM = 1,
- RDMA_NL_GROUP_IWPM,
- RDMA_NL_GROUP_LS,
- RDMA_NL_NUM_GROUPS
-};
-
-#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
-#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
-#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
-
-enum {
- RDMA_NL_RDMA_CM_ID_STATS = 0,
- RDMA_NL_RDMA_CM_NUM_OPS
-};
-
-enum {
- RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
- RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
- RDMA_NL_RDMA_CM_NUM_ATTR,
-};
-
-/* iwarp port mapper op-codes */
-enum {
- RDMA_NL_IWPM_REG_PID = 0,
- RDMA_NL_IWPM_ADD_MAPPING,
- RDMA_NL_IWPM_QUERY_MAPPING,
- RDMA_NL_IWPM_REMOVE_MAPPING,
- RDMA_NL_IWPM_REMOTE_INFO,
- RDMA_NL_IWPM_HANDLE_ERR,
- RDMA_NL_IWPM_MAPINFO,
- RDMA_NL_IWPM_MAPINFO_NUM,
- RDMA_NL_IWPM_NUM_OPS
-};
-
-struct rdma_cm_id_stats {
- __u32 qp_num;
- __u32 bound_dev_if;
- __u32 port_space;
- __s32 pid;
- __u8 cm_state;
- __u8 node_type;
- __u8 port_num;
- __u8 qp_type;
-};
-
-enum {
- IWPM_NLA_REG_PID_UNSPEC = 0,
- IWPM_NLA_REG_PID_SEQ,
- IWPM_NLA_REG_IF_NAME,
- IWPM_NLA_REG_IBDEV_NAME,
- IWPM_NLA_REG_ULIB_NAME,
- IWPM_NLA_REG_PID_MAX
-};
-
-enum {
- IWPM_NLA_RREG_PID_UNSPEC = 0,
- IWPM_NLA_RREG_PID_SEQ,
- IWPM_NLA_RREG_IBDEV_NAME,
- IWPM_NLA_RREG_ULIB_NAME,
- IWPM_NLA_RREG_ULIB_VER,
- IWPM_NLA_RREG_PID_ERR,
- IWPM_NLA_RREG_PID_MAX
-
-};
-
-enum {
- IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
- IWPM_NLA_MANAGE_MAPPING_SEQ,
- IWPM_NLA_MANAGE_ADDR,
- IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
- IWPM_NLA_RMANAGE_MAPPING_ERR,
- IWPM_NLA_RMANAGE_MAPPING_MAX
-};
-
-#define IWPM_NLA_MANAGE_MAPPING_MAX 3
-#define IWPM_NLA_QUERY_MAPPING_MAX 4
-#define IWPM_NLA_MAPINFO_SEND_MAX 3
-
-enum {
- IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
- IWPM_NLA_QUERY_MAPPING_SEQ,
- IWPM_NLA_QUERY_LOCAL_ADDR,
- IWPM_NLA_QUERY_REMOTE_ADDR,
- IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
- IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
- IWPM_NLA_RQUERY_MAPPING_ERR,
- IWPM_NLA_RQUERY_MAPPING_MAX
-};
-
-enum {
- IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
- IWPM_NLA_MAPINFO_ULIB_NAME,
- IWPM_NLA_MAPINFO_ULIB_VER,
- IWPM_NLA_MAPINFO_REQ_MAX
-};
-
-enum {
- IWPM_NLA_MAPINFO_UNSPEC = 0,
- IWPM_NLA_MAPINFO_LOCAL_ADDR,
- IWPM_NLA_MAPINFO_MAPPED_ADDR,
- IWPM_NLA_MAPINFO_MAX
-};
-
-enum {
- IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
- IWPM_NLA_MAPINFO_SEQ,
- IWPM_NLA_MAPINFO_SEND_NUM,
- IWPM_NLA_MAPINFO_ACK_NUM,
- IWPM_NLA_MAPINFO_NUM_MAX
-};
-
-enum {
- IWPM_NLA_ERR_UNSPEC = 0,
- IWPM_NLA_ERR_SEQ,
- IWPM_NLA_ERR_CODE,
- IWPM_NLA_ERR_MAX
-};
-
-/*
- * Local service operations:
- * RESOLVE - The client requests the local service to resolve a path.
- * SET_TIMEOUT - The local service requests the client to set the timeout.
- * IP_RESOLVE - The client requests the local service to resolve an IP to GID.
- */
-enum {
- RDMA_NL_LS_OP_RESOLVE = 0,
- RDMA_NL_LS_OP_SET_TIMEOUT,
- RDMA_NL_LS_OP_IP_RESOLVE,
- RDMA_NL_LS_NUM_OPS
-};
-
-/* Local service netlink message flags */
-#define RDMA_NL_LS_F_ERR 0x0100 /* Failed response */
-
-/*
- * Local service resolve operation family header.
- * The layout for the resolve operation:
- * nlmsg header
- * family header
- * attributes
- */
-
-/*
- * Local service path use:
- * Specify how the path(s) will be used.
- * ALL - For connected CM operation (6 pathrecords)
- * UNIDIRECTIONAL - For unidirectional UD (1 pathrecord)
- * GMP - For miscellaneous GMP like operation (at least 1 reversible
- * pathrecord)
- */
-enum {
- LS_RESOLVE_PATH_USE_ALL = 0,
- LS_RESOLVE_PATH_USE_UNIDIRECTIONAL,
- LS_RESOLVE_PATH_USE_GMP,
- LS_RESOLVE_PATH_USE_MAX
-};
-
-#define LS_DEVICE_NAME_MAX 64
-
-struct rdma_ls_resolve_header {
- __u8 device_name[LS_DEVICE_NAME_MAX];
- __u8 port_num;
- __u8 path_use;
-};
-
-struct rdma_ls_ip_resolve_header {
- __u32 ifindex;
-};
-
-/* Local service attribute type */
-#define RDMA_NLA_F_MANDATORY (1 << 13)
-#define RDMA_NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \
- RDMA_NLA_F_MANDATORY))
-
-/*
- * Local service attributes:
- * Attr Name Size Byte order
- * -----------------------------------------------------
- * PATH_RECORD struct ib_path_rec_data
- * TIMEOUT u32 cpu
- * SERVICE_ID u64 cpu
- * DGID u8[16] BE
- * SGID u8[16] BE
- * TCLASS u8
- * PKEY u16 cpu
- * QOS_CLASS u16 cpu
- * IPV4 u32 BE
- * IPV6 u8[16] BE
- */
-enum {
- LS_NLA_TYPE_UNSPEC = 0,
- LS_NLA_TYPE_PATH_RECORD,
- LS_NLA_TYPE_TIMEOUT,
- LS_NLA_TYPE_SERVICE_ID,
- LS_NLA_TYPE_DGID,
- LS_NLA_TYPE_SGID,
- LS_NLA_TYPE_TCLASS,
- LS_NLA_TYPE_PKEY,
- LS_NLA_TYPE_QOS_CLASS,
- LS_NLA_TYPE_IPV4,
- LS_NLA_TYPE_IPV6,
- LS_NLA_TYPE_MAX
-};
-
-/* Local service DGID/SGID attribute: big endian */
-struct rdma_nla_ls_gid {
- __u8 gid[16];
-};
-
-enum rdma_nldev_command {
- RDMA_NLDEV_CMD_UNSPEC,
-
- RDMA_NLDEV_CMD_GET, /* can dump */
-
- /* 2 - 4 are free to use */
-
- RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */
-
- /* 6 - 8 are free to use */
-
- RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */
-
- RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */
-
- RDMA_NLDEV_NUM_OPS
-};
-
-enum rdma_nldev_attr {
- /* don't change the order or add anything between, this is ABI! */
- RDMA_NLDEV_ATTR_UNSPEC,
-
- /* Identifier for ib_device */
- RDMA_NLDEV_ATTR_DEV_INDEX, /* u32 */
-
- RDMA_NLDEV_ATTR_DEV_NAME, /* string */
- /*
- * Device index together with port index are identifiers
- * for port/link properties.
- *
- * For RDMA_NLDEV_CMD_GET commamnd, port index will return number
- * of available ports in ib_device, while for port specific operations,
- * it will be real port index as it appears in sysfs. Port index follows
- * sysfs notation and starts from 1 for the first port.
- */
- RDMA_NLDEV_ATTR_PORT_INDEX, /* u32 */
-
- /*
- * Device and port capabilities
- */
- RDMA_NLDEV_ATTR_CAP_FLAGS, /* u64 */
-
- /*
- * FW version
- */
- RDMA_NLDEV_ATTR_FW_VERSION, /* string */
-
- /*
- * Node GUID (in host byte order) associated with the RDMA device.
- */
- RDMA_NLDEV_ATTR_NODE_GUID, /* u64 */
-
- /*
- * System image GUID (in host byte order) associated with
- * this RDMA device and other devices which are part of a
- * single system.
- */
- RDMA_NLDEV_ATTR_SYS_IMAGE_GUID, /* u64 */
-
- /*
- * Subnet prefix (in host byte order)
- */
- RDMA_NLDEV_ATTR_SUBNET_PREFIX, /* u64 */
-
- /*
- * Local Identifier (LID),
- * According to IB specification, It is 16-bit address assigned
- * by the Subnet Manager. Extended to be 32-bit for OmniPath users.
- */
- RDMA_NLDEV_ATTR_LID, /* u32 */
- RDMA_NLDEV_ATTR_SM_LID, /* u32 */
-
- /*
- * LID mask control (LMC)
- */
- RDMA_NLDEV_ATTR_LMC, /* u8 */
-
- RDMA_NLDEV_ATTR_PORT_STATE, /* u8 */
- RDMA_NLDEV_ATTR_PORT_PHYS_STATE, /* u8 */
-
- RDMA_NLDEV_ATTR_DEV_NODE_TYPE, /* u8 */
-
- RDMA_NLDEV_ATTR_RES_SUMMARY, /* nested table */
- RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY, /* nested table */
- RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */
- RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */
-
- RDMA_NLDEV_ATTR_RES_QP, /* nested table */
- RDMA_NLDEV_ATTR_RES_QP_ENTRY, /* nested table */
- /*
- * Local QPN
- */
- RDMA_NLDEV_ATTR_RES_LQPN, /* u32 */
- /*
- * Remote QPN,
- * Applicable for RC and UC only IBTA 11.2.5.3 QUERY QUEUE PAIR
- */
- RDMA_NLDEV_ATTR_RES_RQPN, /* u32 */
- /*
- * Receive Queue PSN,
- * Applicable for RC and UC only 11.2.5.3 QUERY QUEUE PAIR
- */
- RDMA_NLDEV_ATTR_RES_RQ_PSN, /* u32 */
- /*
- * Send Queue PSN
- */
- RDMA_NLDEV_ATTR_RES_SQ_PSN, /* u32 */
- RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE, /* u8 */
- /*
- * QP types as visible to RDMA/core, the reserved QPT
- * are not exported through this interface.
- */
- RDMA_NLDEV_ATTR_RES_TYPE, /* u8 */
- RDMA_NLDEV_ATTR_RES_STATE, /* u8 */
- /*
- * Process ID which created object,
- * in case of kernel origin, PID won't exist.
- */
- RDMA_NLDEV_ATTR_RES_PID, /* u32 */
- /*
- * The name of process created following resource.
- * It will exist only for kernel objects.
- * For user created objects, the user is supposed
- * to read /proc/PID/comm file.
- */
- RDMA_NLDEV_ATTR_RES_KERN_NAME, /* string */
-
- RDMA_NLDEV_ATTR_MAX
-};
-#endif /* _RDMA_NETLINK_H */
#include "libnetlink.h"
#include "ll_map.h"
#include "rtm_map.h"
+#include "json_print.h"
extern int preferred_family;
extern int human_readable;
extern int oneline;
extern int brief;
extern int json;
+extern int pretty;
extern int timestamp;
extern int timestamp_short;
extern const char * _SL_;
ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI
};
+static inline void inet_prefix_reset(inet_prefix *p)
+{
+ p->flags = 0;
+}
+
static inline bool is_addrtype_inet(const inet_prefix *p)
{
return p->flags & ADDRTYPE_INET;
const char *format_host_r(int af, int len, const void *addr,
char *buf, int buflen);
+#define format_host_rta_r(af, rta, buf, buflen) \
+ format_host_r(af, RTA_PAYLOAD(rta), RTA_DATA(rta), \
+ buf, buflen)
+
const char *format_host(int af, int lne, const void *addr);
#define format_host_rta(af, rta) \
format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta))
void invarg(const char *, const char *) __attribute__((noreturn));
void duparg(const char *, const char *) __attribute__((noreturn));
void duparg2(const char *, const char *) __attribute__((noreturn));
+int nodev(const char *dev);
int check_ifname(const char *);
int get_ifname(char *, const char *);
+const char *get_ifname_rta(int ifindex, const struct rtattr *rta);
int matches(const char *arg, const char *pattern);
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
int print_timestamp(FILE *fp);
void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
+unsigned int print_name_and_link(const char *fmt,
+ const char *name, struct rtattr *tb[]);
+
#define BIT(nr) (1UL << (nr))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
ssize_t getcmdline(char **line, size_t *len, FILE *in);
int makeargs(char *line, char *argv[], int maxargs);
-struct iplink_req {
- struct nlmsghdr n;
- struct ifinfomsg i;
- char buf[1024];
-};
-
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
- char **name, char **type, char **link, char **dev,
- int *group, int *index);
-
int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
bool show_label);
char *find_cgroup2_mount(void);
int get_command_name(const char *pid, char *comm, size_t len);
+int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
+ struct rtattr *tb[]);
+
#ifdef NEED_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
" netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
" vrf | sr }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
-" -h[uman-readable] | -iec |\n"
+" -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
" -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
" -4 | -6 | -I | -D | -B | -0 |\n"
" -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
-" -rc[vbuf] [size] | -n[etns] name | -a[ll] |Â -c[olor]}\n");
+" -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
exit(-1);
}
++brief;
} else if (matches(opt, "-json") == 0) {
++json;
+ } else if (matches(opt, "-pretty") == 0) {
+ ++pretty;
} else if (matches(opt, "-rcvbuf") == 0) {
unsigned int size;
exit(-1);
}
-static void print_tunnel(struct ip6_tnl_parm2 *p)
+static void print_tunnel(const void *t)
{
+ const struct ip6_tnl_parm2 *p = t;
char s1[1024];
char s2[1024];
}
if (medium) {
p->link = ll_name_to_index(medium);
- if (p->link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", medium);
- return -1;
- }
+ if (!p->link)
+ return nodev(medium);
}
return 0;
}
}
}
-/*
- * @p1: user specified parameter
- * @p2: database entry
- */
-static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
- const struct ip6_tnl_parm2 *p2)
+static void ip6_tnl_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+ const struct ifinfomsg *ifi = info->ifi;
+ const struct ip6_tnl_parm2 *p1 = info->p1;
+ struct ip6_tnl_parm2 *p2 = info->p2;
+
+ ip6_tnl_parm_init(p2, 0);
+ if (ifi->ifi_type == ARPHRD_IP6GRE)
+ p2->proto = IPPROTO_GRE;
+ p2->link = ifi->ifi_index;
+ strcpy(p2->name, p1->name);
+}
+
+static bool ip6_tnl_parm_match(const struct tnl_print_nlmsg_info *info)
{
+ const struct ip6_tnl_parm2 *p1 = info->p1;
+ const struct ip6_tnl_parm2 *p2 = info->p2;
+
return ((!p1->link || p1->link == p2->link) &&
(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
(IN6_IS_ADDR_UNSPECIFIED(&p1->laddr) ||
(!p1->flags || (p1->flags & p2->flags)));
}
-static int do_tunnels_list(struct ip6_tnl_parm2 *p)
-{
- char buf[512];
- int err = -1;
- FILE *fp = fopen("/proc/net/dev", "r");
-
- if (fp == NULL) {
- perror("fopen");
- return -1;
- }
-
- /* skip two lines at the begenning of the file */
- if (!fgets(buf, sizeof(buf), fp) ||
- !fgets(buf, sizeof(buf), fp)) {
- fprintf(stderr, "/proc/net/dev read error\n");
- goto end;
- }
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- char name[IFNAMSIZ];
- int index, type;
- struct ip6_tnl_parm2 p1 = {};
- char *ptr;
-
- buf[sizeof(buf) - 1] = '\0';
- if ((ptr = strchr(buf, ':')) == NULL ||
- (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
- fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
- goto end;
- }
- if (p->name[0] && strcmp(p->name, name))
- continue;
- index = ll_name_to_index(name);
- if (index == 0)
- continue;
- type = ll_index_to_type(index);
- if (type == -1) {
- fprintf(stderr, "Failed to get type of \"%s\"\n", name);
- continue;
- }
- if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
- continue;
- ip6_tnl_parm_init(&p1, 0);
- if (type == ARPHRD_IP6GRE)
- p1.proto = IPPROTO_GRE;
- strcpy(p1.name, name);
- p1.link = ll_name_to_index(p1.name);
- if (p1.link == 0)
- continue;
- if (tnl_get_ioctl(p1.name, &p1))
- continue;
- if (!ip6_tnl_parm_match(p, &p1))
- continue;
- print_tunnel(&p1);
- if (show_stats)
- tnl_print_stats(ptr);
- printf("\n");
- }
- err = 0;
- end:
- fclose(fp);
- return err;
-}
-
static int do_show(int argc, char **argv)
{
- struct ip6_tnl_parm2 p;
+ struct ip6_tnl_parm2 p, p1;
- ll_init_map(&rth);
ip6_tnl_parm_init(&p, 0);
p.proto = 0; /* default to any */
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
return -1;
- if (!p.name[0] || show_stats)
- do_tunnels_list(&p);
- else {
- if (tnl_get_ioctl(p.name, &p))
- return -1;
- print_tunnel(&p);
- printf("\n");
+ if (!p.name[0] || show_stats) {
+ struct tnl_print_nlmsg_info info = {
+ .p1 = &p,
+ .p2 = &p1,
+ .init = ip6_tnl_parm_initialize,
+ .match = ip6_tnl_parm_match,
+ .print = print_tunnel,
+ };
+
+ return do_tunnels_list(&info);
}
+ if (tnl_get_ioctl(p.name, &p))
+ return -1;
+
+ print_tunnel(&p);
+ fputc('\n', stdout);
return 0;
}
int get_operstate(const char *name);
int print_linkinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
-int print_linkinfo_brief(const struct sockaddr_nl *who,
- struct nlmsghdr *n, void *arg,
- struct link_filter *filter);
int print_addrinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
int print_addrlabel(const struct sockaddr_nl *who,
extern struct rtnl_handle rth;
+struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+};
+
struct link_util {
struct link_util *next;
const char *id;
struct link_util *get_link_kind(const char *kind);
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type);
+
+/* iplink_bridge.c */
void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len);
int bridge_parse_xstats(struct link_util *lu, int argc, char **argv);
int bridge_print_xstats(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
+/* iproute_lwtunnel.c */
+int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp);
+void lwt_print_encap(FILE *fp, struct rtattr *encap_type, struct rtattr *encap);
+
+/* iplink_xdp.c */
+int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
+ bool generic, bool drv, bool offload);
+void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
+
+/* iplink_vrf.c */
__u32 ipvrf_get_table(const char *name);
int name_is_vrf(const char *name);
#include "utils.h"
#include "ll_map.h"
#include "ip_common.h"
-#include "xdp.h"
#include "color.h"
enum {
}
}
-static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
- const struct rtattr *carrier_changes)
+static void __print_link_stats(FILE *fp, struct rtattr *tb[])
{
+ const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
+ struct rtnl_link_stats64 _s, *s = &_s;
+ int ret;
+
+ ret = get_rtnl_link_stats_rta(s, tb);
+ if (ret < 0)
+ return;
+
if (is_json_context()) {
- open_json_object("stats64");
+ open_json_object((ret == sizeof(*s)) ? "stats64" : "stats");
/* RX stats */
open_json_object("rx");
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
if (s->rx_compressed)
print_uint(PRINT_JSON,
- "compressed",
- NULL, s->rx_compressed);
+ "compressed", NULL, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
if (s->tx_compressed)
print_uint(PRINT_JSON,
- "compressed",
- NULL, s->tx_compressed);
+ "compressed", NULL, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON, "carrier_changes", NULL,
rta_getattr_u32(carrier_changes));
}
- close_json_object();
- close_json_object();
-
- } else {
- /* RX stats */
- fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
- s->rx_compressed ? "compressed" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 10, s->rx_bytes);
- print_num(fp, 8, s->rx_packets);
- print_num(fp, 7, s->rx_errors);
- print_num(fp, 7, s->rx_dropped);
- print_num(fp, 7, s->rx_over_errors);
- print_num(fp, 7, s->multicast);
- if (s->rx_compressed)
- print_num(fp, 7, s->rx_compressed);
-
- /* RX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
- s->rx_nohandler ? " nohandler" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 8, s->rx_length_errors);
- print_num(fp, 7, s->rx_crc_errors);
- print_num(fp, 7, s->rx_frame_errors);
- print_num(fp, 7, s->rx_fifo_errors);
- print_num(fp, 7, s->rx_missed_errors);
- if (s->rx_nohandler)
- print_num(fp, 7, s->rx_nohandler);
-
- }
- fprintf(fp, "%s", _SL_);
-
- /* TX stats */
- fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
- s->tx_compressed ? "compressed" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 10, s->tx_bytes);
- print_num(fp, 8, s->tx_packets);
- print_num(fp, 7, s->tx_errors);
- print_num(fp, 7, s->tx_dropped);
- print_num(fp, 7, s->tx_carrier_errors);
- print_num(fp, 7, s->collisions);
- if (s->tx_compressed)
- print_num(fp, 7, s->tx_compressed);
-
- /* TX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " TX errors: aborted fifo window heartbeat");
- if (carrier_changes)
- fprintf(fp, " transns");
- fprintf(fp, "%s", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 8, s->tx_aborted_errors);
- print_num(fp, 7, s->tx_fifo_errors);
- print_num(fp, 7, s->tx_window_errors);
- print_num(fp, 7, s->tx_heartbeat_errors);
- if (carrier_changes)
- print_num(fp, 7,
- rta_getattr_u32(carrier_changes));
- }
- }
-}
-
-static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
- const struct rtattr *carrier_changes)
-{
- if (is_json_context()) {
- open_json_object("stats");
-
- /* RX stats */
- open_json_object("rx");
- print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
- print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
- print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
- print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
- print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
- print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
- if (s->rx_compressed)
- print_int(PRINT_JSON,
- "compressed",
- NULL, s->rx_compressed);
-
- /* RX error stats */
- if (show_stats > 1) {
- print_uint(PRINT_JSON,
- "length_errors",
- NULL, s->rx_length_errors);
- print_uint(PRINT_JSON,
- "crc_errors",
- NULL, s->rx_crc_errors);
- print_uint(PRINT_JSON,
- "frame_errors",
- NULL, s->rx_frame_errors);
- print_uint(PRINT_JSON,
- "fifo_errors",
- NULL, s->rx_fifo_errors);
- print_uint(PRINT_JSON,
- "missed_errors",
- NULL, s->rx_missed_errors);
- if (s->rx_nohandler)
- print_int(PRINT_JSON,
- "nohandler",
- NULL, s->rx_nohandler);
- }
- close_json_object();
-
- /* TX stats */
- open_json_object("tx");
- print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
- print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
- print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
- print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
- print_uint(PRINT_JSON,
- "carrier_errors",
- NULL, s->tx_carrier_errors);
- print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
- if (s->tx_compressed)
- print_int(PRINT_JSON,
- "compressed",
- NULL, s->tx_compressed);
-
- /* TX error stats */
- if (show_stats > 1) {
- print_uint(PRINT_JSON,
- "aborted_errors",
- NULL, s->tx_aborted_errors);
- print_uint(PRINT_JSON,
- "fifo_errors",
- NULL, s->tx_fifo_errors);
- print_uint(PRINT_JSON,
- "window_errors",
- NULL, s->tx_window_errors);
- print_uint(PRINT_JSON,
- "heartbeat_errors",
- NULL, s->tx_heartbeat_errors);
- if (carrier_changes)
- print_uint(PRINT_JSON,
- "carrier_changes",
- NULL,
- rta_getattr_u32(carrier_changes));
- }
close_json_object();
close_json_object();
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_);
-
fprintf(fp, " ");
print_num(fp, 10, s->rx_bytes);
print_num(fp, 8, s->rx_packets);
}
}
-static void __print_link_stats(FILE *fp, struct rtattr **tb)
-{
- const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
-
- if (tb[IFLA_STATS64]) {
- struct rtnl_link_stats64 stats = { 0 };
-
- memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]),
- MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats)));
-
- print_link_stats64(fp, &stats, carrier_changes);
- } else if (tb[IFLA_STATS]) {
- struct rtnl_link_stats stats = { 0 };
-
- memcpy(&stats, RTA_DATA(tb[IFLA_STATS]),
- MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats)));
-
- print_link_stats32(fp, &stats, carrier_changes);
- }
-}
-
static void print_link_stats(FILE *fp, struct nlmsghdr *n)
{
struct ifinfomsg *ifi = NLMSG_DATA(n);
fprintf(fp, "%s", _SL_);
}
-int print_linkinfo_brief(const struct sockaddr_nl *who,
- struct nlmsghdr *n, void *arg,
- struct link_filter *pfilter)
+static int print_linkinfo_brief(FILE *fp, const char *name,
+ const struct ifinfomsg *ifi,
+ struct rtattr *tb[])
{
- FILE *fp = (FILE *)arg;
- struct ifinfomsg *ifi = NLMSG_DATA(n);
- struct rtattr *tb[IFLA_MAX+1];
- int len = n->nlmsg_len;
- const char *name;
- char buf[32] = { 0, };
unsigned int m_flag = 0;
- if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
- return -1;
-
- len -= NLMSG_LENGTH(sizeof(*ifi));
- if (len < 0)
- return -1;
-
- if (!pfilter)
- pfilter = &filter;
-
- if (pfilter->ifindex && ifi->ifi_index != pfilter->ifindex)
- return -1;
- if (pfilter->up && !(ifi->ifi_flags&IFF_UP))
- return -1;
-
- parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
- if (tb[IFLA_IFNAME] == NULL) {
- fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
- name = "<nil>";
- } else {
- name = rta_getattr_str(tb[IFLA_IFNAME]);
- }
-
- if (pfilter->label &&
- (!pfilter->family || pfilter->family == AF_PACKET) &&
- fnmatch(pfilter->label, RTA_DATA(tb[IFLA_IFNAME]), 0))
- return -1;
-
- if (tb[IFLA_GROUP]) {
- int group = rta_getattr_u32(tb[IFLA_GROUP]);
-
- if (pfilter->group != -1 && group != pfilter->group)
- return -1;
- }
-
- if (tb[IFLA_MASTER]) {
- int master = rta_getattr_u32(tb[IFLA_MASTER]);
-
- if (pfilter->master > 0 && master != pfilter->master)
- return -1;
- } else if (pfilter->master > 0)
- return -1;
-
- if (pfilter->kind && match_link_kind(tb, pfilter->kind, 0))
- return -1;
-
- if (pfilter->slave_kind && match_link_kind(tb, pfilter->slave_kind, 1))
- return -1;
-
- if (n->nlmsg_type == RTM_DELLINK)
- print_bool(PRINT_ANY, "deleted", "Deleted ", true);
-
- if (tb[IFLA_LINK]) {
- SPRINT_BUF(b1);
- int iflink = rta_getattr_u32(tb[IFLA_LINK]);
-
- if (iflink == 0) {
- snprintf(buf, sizeof(buf), "%s@NONE", name);
- print_null(PRINT_JSON, "link", NULL, NULL);
- } else {
- const char *link = ll_idx_n2a(iflink, b1);
-
- print_string(PRINT_JSON, "link", NULL, link);
- snprintf(buf, sizeof(buf), "%s@%s", name, link);
- m_flag = ll_index_to_flags(iflink);
- m_flag = !(m_flag & IFF_UP);
- }
- } else
- snprintf(buf, sizeof(buf), "%s", name);
-
- print_string(PRINT_FP, NULL, "%-16s ", buf);
- print_string(PRINT_JSON, "ifname", NULL, name);
+ m_flag = print_name_and_link("%-16s ", name, tb);
if (tb[IFLA_OPERSTATE])
print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
- if (pfilter->family == AF_PACKET) {
+ if (filter.family == AF_PACKET) {
SPRINT_BUF(b1);
if (tb[IFLA_ADDRESS]) {
}
}
- if (pfilter->family == AF_PACKET) {
+ if (filter.family == AF_PACKET) {
print_link_flags(fp, ifi->ifi_flags, m_flag);
print_string(PRINT_FP, NULL, "%s", "\n");
}
+
fflush(fp);
return 0;
}
struct ifinfomsg *ifi = NLMSG_DATA(n);
struct rtattr *tb[IFLA_MAX+1];
int len = n->nlmsg_len;
+ const char *name;
unsigned int m_flag = 0;
+ SPRINT_BUF(b1);
if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
return 0;
return -1;
if (filter.ifindex && ifi->ifi_index != filter.ifindex)
- return 0;
+ return -1;
if (filter.up && !(ifi->ifi_flags&IFF_UP))
- return 0;
+ return -1;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
- if (tb[IFLA_IFNAME] == NULL)
- fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
+
+ name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
+ if (!name)
+ return -1;
if (filter.label &&
(!filter.family || filter.family == AF_PACKET) &&
- fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
- return 0;
+ fnmatch(filter.label, name, 0))
+ return -1;
if (tb[IFLA_GROUP]) {
int group = rta_getattr_u32(tb[IFLA_GROUP]);
if (n->nlmsg_type == RTM_DELLINK)
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
- print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
- if (tb[IFLA_IFNAME]) {
- print_color_string(PRINT_ANY,
- COLOR_IFNAME,
- "ifname", "%s",
- rta_getattr_str(tb[IFLA_IFNAME]));
- } else {
- print_null(PRINT_JSON, "ifname", NULL, NULL);
- print_color_null(PRINT_FP, COLOR_IFNAME,
- "ifname", "%s", "<nil>");
- }
-
- if (tb[IFLA_LINK]) {
- int iflink = rta_getattr_u32(tb[IFLA_LINK]);
+ if (brief)
+ return print_linkinfo_brief(fp, name, ifi, tb);
- if (iflink == 0)
- print_null(PRINT_ANY, "link", "@%s: ", "NONE");
- else {
- if (tb[IFLA_LINK_NETNSID])
- print_int(PRINT_ANY,
- "link_index", "@if%d: ", iflink);
- else {
- SPRINT_BUF(b1);
+ print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
- print_string(PRINT_ANY,
- "link",
- "@%s: ",
- ll_idx_n2a(iflink, b1));
- m_flag = ll_index_to_flags(iflink);
- m_flag = !(m_flag & IFF_UP);
- }
- }
- } else {
- print_string(PRINT_FP, NULL, ": ", NULL);
- }
+ m_flag = print_name_and_link("%s: ", name, tb);
print_link_flags(fp, ifi->ifi_flags, m_flag);
if (tb[IFLA_MTU])
"qdisc %s ",
rta_getattr_str(tb[IFLA_QDISC]));
if (tb[IFLA_MASTER]) {
- SPRINT_BUF(b1);
+ int master = rta_getattr_u32(tb[IFLA_MASTER]);
print_string(PRINT_ANY,
- "master",
- "master %s ",
- ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
+ "master", "master %s ",
+ ll_index_to_name(master));
}
if (tb[IFLA_OPERSTATE])
print_linkmode(fp, tb[IFLA_LINKMODE]);
if (tb[IFLA_GROUP]) {
- SPRINT_BUF(b1);
int group = rta_getattr_u32(tb[IFLA_GROUP]);
print_string(PRINT_ANY,
print_link_event(fp, rta_getattr_u32(tb[IFLA_EVENT]));
if (!filter.family || filter.family == AF_PACKET || show_details) {
- SPRINT_BUF(b1);
-
print_string(PRINT_FP, NULL, "%s", _SL_);
print_string(PRINT_ANY,
"link_type",
rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
if (tb[IFLA_PHYS_PORT_ID]) {
- SPRINT_BUF(b1);
print_string(PRINT_ANY,
"phys_port_id",
"portid %s ",
}
if (tb[IFLA_PHYS_SWITCH_ID]) {
- SPRINT_BUF(b1);
print_string(PRINT_ANY,
"phys_switch_id",
"switchid %s ",
close_json_array(PRINT_JSON, NULL);
}
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_string(PRINT_FP, NULL, "%s", "\n");
fflush(fp);
return 1;
}
return 0;
}
+static int ifa_label_match_rta(int ifindex, const struct rtattr *rta)
+{
+ const char *label;
+
+ if (!filter.label)
+ return 0;
+
+ if (rta)
+ label = RTA_DATA(rta);
+ else
+ label = ll_index_to_name(ifindex);
+
+ return fnmatch(filter.label, label, 0);
+}
+
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
void *arg)
{
return 0;
if ((filter.flags ^ ifa_flags) & filter.flagmask)
return 0;
- if (filter.label) {
- SPRINT_BUF(b1);
- const char *label;
-
- if (rta_tb[IFA_LABEL])
- label = RTA_DATA(rta_tb[IFA_LABEL]);
- else
- label = ll_idx_n2a(ifa->ifa_index, b1);
- if (fnmatch(filter.label, label, 0) != 0)
- return 0;
- }
if (filter.family && filter.family != ifa->ifa_family)
return 0;
+ if (ifa_label_match_rta(ifa->ifa_index, rta_tb[IFA_LABEL]))
+ return 0;
+
if (inet_addr_match_rta(&filter.pfx, rta_tb[IFA_LOCAL]))
return 0;
if ((filter.flags ^ ifa_flags) & filter.flagmask)
continue;
- if (filter.pfx.family || filter.label) {
- struct rtattr *rta =
- tb[IFA_LOCAL] ? : tb[IFA_ADDRESS];
-
- if (inet_addr_match_rta(&filter.pfx, rta))
- continue;
-
- if (filter.label) {
- SPRINT_BUF(b1);
- const char *label;
-
- if (tb[IFA_LABEL])
- label = RTA_DATA(tb[IFA_LABEL]);
- else
- label = ll_idx_n2a(ifa->ifa_index, b1);
- if (fnmatch(filter.label, label, 0) != 0)
- continue;
- }
- }
+
+ if (ifa_label_match_rta(ifa->ifa_index, tb[IFA_LABEL]))
+ continue;
+
+ if (!tb[IFA_LOCAL])
+ tb[IFA_LOCAL] = tb[IFA_ADDRESS];
+ if (inet_addr_match_rta(&filter.pfx, tb[IFA_LOCAL]))
+ continue;
ok = 1;
break;
ipaddr_filter(&linfo, ainfo);
for (l = linfo.head; l; l = l->next) {
+ struct nlmsghdr *n = &l->h;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
int res = 0;
- struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
open_json_object(NULL);
- if (brief) {
- if (print_linkinfo_brief(NULL, &l->h,
- stdout, NULL) == 0)
- if (filter.family != AF_PACKET)
- print_selected_addrinfo(ifi,
- ainfo->head,
- stdout);
- } else if (no_link ||
- (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
- if (filter.family != AF_PACKET)
- print_selected_addrinfo(ifi,
- ainfo->head, stdout);
- if (res > 0 && !do_link && show_stats)
- print_link_stats(stdout, &l->h);
- }
+ if (brief || !no_link)
+ res = print_linkinfo(NULL, n, stdout);
+ if (res >= 0 && filter.family != AF_PACKET)
+ print_selected_addrinfo(ifi, ainfo->head, stdout);
+ if (res > 0 && !do_link && show_stats)
+ print_link_stats(stdout, n);
close_json_object();
}
fflush(stdout);
if (!scoped && cmd != RTM_DELADDR)
req.ifa.ifa_scope = default_scope(&lcl);
- if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ req.ifa.ifa_index = ll_name_to_index(d);
+ if (!req.ifa.ifa_index)
+ return nodev(d);
if (valid_lftp || preferred_lftp) {
struct ifa_cacheinfo cinfo = {};
#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))
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];
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;
}
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;
}
#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);
}
} 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;
}
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;
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;
}
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;
}
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;
}
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);
}
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
-#include "xdp.h"
#include "namespace.h"
#define IPLINK_IOCTL_COMPAT 1
return 0;
}
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
- char **name, char **type, char **link, char **dev,
- int *group, int *index)
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
{
+ char *name = NULL;
+ char *dev = NULL;
+ char *link = NULL;
int ret, len;
char abuf[32];
int qlen = -1;
int numrxqueues = -1;
int dev_index = 0;
int link_netnsid = -1;
+ int index = 0;
+ int group = -1;
int addr_len = 0;
- *group = -1;
ret = argc;
while (argc > 0) {
req->i.ifi_flags &= ~IFF_UP;
} else if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
+ if (name)
+ duparg("name", *argv);
if (check_ifname(*argv))
invarg("\"name\" not a valid ifname", *argv);
- *name = *argv;
+ name = *argv;
+ if (!dev) {
+ dev = name;
+ dev_index = ll_name_to_index(dev);
+ }
} else if (strcmp(*argv, "index") == 0) {
NEXT_ARG();
- if (*index)
+ if (index)
duparg("index", *argv);
- *index = atoi(*argv);
- if (*index <= 0)
+ index = atoi(*argv);
+ if (index <= 0)
invarg("Invalid \"index\" value", *argv);
} else if (matches(*argv, "link") == 0) {
NEXT_ARG();
- *link = *argv;
+ link = *argv;
} else if (matches(*argv, "address") == 0) {
NEXT_ARG();
addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
if (xdp_parse(&argc, &argv, req, dev_index,
generic, drv, offload))
exit(-1);
+
+ if (offload && name == dev)
+ dev = NULL;
} else if (strcmp(*argv, "netns") == 0) {
NEXT_ARG();
if (netns != -1)
if (len < 0)
return -1;
addattr_nest_end(&req->n, vflist);
+
+ if (name == dev)
+ dev = NULL;
} else if (matches(*argv, "master") == 0) {
int ifindex;
*argv, len);
} else if (strcmp(*argv, "group") == 0) {
NEXT_ARG();
- if (*group != -1)
+ if (group != -1)
duparg("group", *argv);
- if (rtnl_group_a2n(group, *argv))
+ if (rtnl_group_a2n(&group, *argv))
invarg("Invalid \"group\" value\n", *argv);
+ addattr32(&req->n, sizeof(*req), IFLA_GROUP, group);
} else if (strcmp(*argv, "mode") == 0) {
int mode;
if (strcmp(*argv, "dev") == 0)
NEXT_ARG();
- if (*dev)
+ if (dev != name)
duparg2("dev", *argv);
if (check_ifname(*argv))
invarg("\"dev\" not a valid ifname", *argv);
- *dev = *argv;
- dev_index = ll_name_to_index(*dev);
+ dev = *argv;
+ dev_index = ll_name_to_index(dev);
}
argc--; argv++;
}
+ ret -= argc;
+
+ /* Allow "ip link add dev" and "ip link add name" */
+ if (!name)
+ name = dev;
+ else if (!dev)
+ dev = name;
+ else if (!strcmp(name, dev))
+ name = dev;
+
if (dev_index && addr_len) {
int halen = nl_get_ll_addr_len(dev_index);
}
}
- return ret - argc;
-}
-
-static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
-{
- char *dev = NULL;
- char *name = NULL;
- char *link = NULL;
- char *type = NULL;
- int index = 0;
- int group;
- struct link_util *lu = NULL;
- struct iplink_req req = {
- .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- .n.nlmsg_flags = NLM_F_REQUEST | flags,
- .n.nlmsg_type = cmd,
- .i.ifi_family = preferred_family,
- };
- int ret;
-
- ret = iplink_parse(argc, argv,
- &req, &name, &type, &link, &dev, &group, &index);
- if (ret < 0)
- return ret;
-
- argc -= ret;
- argv += ret;
+ if (!(req->n.nlmsg_flags & NLM_F_CREATE) && index) {
+ fprintf(stderr,
+ "index can be used only when creating devices.\n");
+ exit(-1);
+ }
if (group != -1) {
- if (dev)
- addattr_l(&req.n, sizeof(req), IFLA_GROUP,
- &group, sizeof(group));
- else {
+ if (!dev) {
if (argc) {
fprintf(stderr,
"Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
*argv);
- return -1;
+ exit(-1);
}
- if (flags & NLM_F_CREATE) {
+ if (req->n.nlmsg_flags & NLM_F_CREATE) {
fprintf(stderr,
"group cannot be used when creating devices.\n");
- return -1;
+ exit(-1);
}
- addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
- if (rtnl_talk(&rth, &req.n, NULL) < 0)
- return -2;
- return 0;
+ *type = NULL;
+ return ret;
}
}
- if (!(flags & NLM_F_CREATE)) {
+ if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
if (!dev) {
fprintf(stderr,
"Not enough information: \"dev\" argument is required.\n");
exit(-1);
}
- if (cmd == RTM_NEWLINK && index) {
+
+ req->i.ifi_index = ll_name_to_index(dev);
+ if (!req->i.ifi_index)
+ return nodev(dev);
+
+ /* Not renaming to the same name */
+ if (name == dev)
+ name = NULL;
+ } else {
+ if (name != dev) {
fprintf(stderr,
- "index can be used only when creating devices.\n");
+ "both \"name\" and \"dev\" cannot be used when creating devices.\n");
exit(-1);
}
- req.i.ifi_index = ll_name_to_index(dev);
- if (req.i.ifi_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", dev);
- return -1;
- }
- } else {
- /* Allow "ip link add dev" and "ip link add name" */
- if (!name)
- name = dev;
-
if (link) {
int ifindex;
ifindex = ll_name_to_index(link);
- if (ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- link);
- return -1;
- }
- addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+ if (!ifindex)
+ return nodev(link);
+ addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
}
- req.i.ifi_index = index;
+ req->i.ifi_index = index;
}
if (name) {
- addattr_l(&req.n, sizeof(req),
+ addattr_l(&req->n, sizeof(*req),
IFLA_IFNAME, name, strlen(name) + 1);
}
+ return ret;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+ char *type = NULL;
+ struct iplink_req req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .n.nlmsg_flags = NLM_F_REQUEST | flags,
+ .n.nlmsg_type = cmd,
+ .i.ifi_family = preferred_family,
+ };
+ int ret;
+
+ ret = iplink_parse(argc, argv, &req, &type);
+ if (ret < 0)
+ return ret;
+
if (type) {
+ struct link_util *lu;
struct rtattr *linkinfo;
char *ulinep = strchr(type, '_');
int iflatype;
iflatype = IFLA_INFO_SLAVE_DATA;
else
iflatype = IFLA_INFO_DATA;
+
+ argc -= ret;
+ argv += ret;
+
if (lu && argc) {
- struct rtattr *data
- = addattr_nest(&req.n,
- sizeof(req), iflatype);
+ struct rtattr *data;
+
+ data = addattr_nest(&req.n, sizeof(req), iflatype);
if (lu->parse_opt &&
lu->parse_opt(lu, argc, argv, &req.n))
return -2;
open_json_object(NULL);
- if (brief)
- print_linkinfo_brief(NULL, answer, stdout, NULL);
- else
- print_linkinfo(NULL, answer, stdout);
+ print_linkinfo(NULL, answer, stdout);
close_json_object();
free(answer);
NEXT_ARG();
ifindex = ll_name_to_index(*argv);
if (!ifindex)
- return -1;
+ return nodev(*argv);
addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
} else if (matches(*argv, "clear_active_slave") == 0) {
addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
NEXT_ARG();
ifindex = ll_name_to_index(*argv);
if (!ifindex)
- return -1;
+ return nodev(*argv);
addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
} else if (matches(*argv, "primary_reselect") == 0) {
NEXT_ARG();
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
filter_index = ll_name_to_index(*argv);
- if (filter_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- return -1;
- }
+ if (!filter_index)
+ return nodev(*argv);
} else if (strcmp(*argv, "help") == 0) {
bridge_print_xstats_help(lu, stdout);
exit(0);
fprintf(f, "%s %s ", flag, val ? "on" : "off");
}
-static void _print_hex(FILE *f,
- const char *json_attr,
- const char *attr,
- __u16 val)
-{
- if (is_json_context()) {
- SPRINT_BUF(b1);
-
- snprintf(b1, sizeof(b1), "0x%x", val);
- print_string(PRINT_JSON, json_attr, NULL, b1);
- } else {
- fprintf(f, "%s 0x%x ", attr, val);
- }
-}
-
static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
{
struct timeval tv;
rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
if (tb[IFLA_BRPORT_ID])
- _print_hex(f, "id", "port_id",
- rta_getattr_u16(tb[IFLA_BRPORT_ID]));
+ print_0xhex(PRINT_ANY, "id", "port_id 0x%x ",
+ rta_getattr_u16(tb[IFLA_BRPORT_ID]));
if (tb[IFLA_BRPORT_NO])
- _print_hex(f, "no", "port_no",
+ print_0xhex(PRINT_ANY, "no", "port_no 0x%x ",
rta_getattr_u16(tb[IFLA_BRPORT_NO]));
if (tb[IFLA_BRPORT_DESIGNATED_PORT])
__u16 fwd_mask;
fwd_mask = rta_getattr_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
- _print_hex(f, "group_fwd_mask", "group_fwd_mask", fwd_mask);
+ print_0xhex(PRINT_ANY, "group_fwd_mask",
+ "group_fwd_mask 0x%x ", fwd_mask);
_bitmask2str(fwd_mask, convbuf, sizeof(convbuf), fwd_mask_tbl);
print_string(PRINT_ANY, "group_fwd_mask_str",
"group_fwd_mask_str %s ", convbuf);
bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
!(n->nlmsg_flags & NLM_F_CREATE));
- daddr.flags = 0;
+ inet_prefix_reset(&daddr);
while (argc > 0) {
if (!matches(*argv, "id") ||
struct ifla_vlan_qos_mapping m;
struct rtattr *tail;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, attrtype, NULL, 0);
+ tail = addattr_nest(n, 1024, attrtype);
while (argc > 0) {
char *colon = strchr(*argv, ':');
addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
*argcp = argc;
*argvp = argv;
}
static int vxcan_parse_opt(struct link_util *lu, int argc, char **argv,
- struct nlmsghdr *hdr)
+ struct nlmsghdr *n)
{
- char *dev = NULL;
- char *name = NULL;
- char *link = NULL;
char *type = NULL;
- int index = 0;
int err;
struct rtattr *data;
- int group;
struct ifinfomsg *ifm, *peer_ifm;
- unsigned int ifi_flags, ifi_change;
+ unsigned int ifi_flags, ifi_change, ifi_index;
if (strcmp(argv[0], "peer") != 0) {
usage();
return -1;
}
- ifm = NLMSG_DATA(hdr);
+ ifm = NLMSG_DATA(n);
ifi_flags = ifm->ifi_flags;
ifi_change = ifm->ifi_change;
+ ifi_index = ifm->ifi_index;
ifm->ifi_flags = 0;
ifm->ifi_change = 0;
+ ifm->ifi_index = 0;
- data = NLMSG_TAIL(hdr);
- addattr_l(hdr, 1024, VXCAN_INFO_PEER, NULL, 0);
+ data = addattr_nest(n, 1024, VXCAN_INFO_PEER);
- hdr->nlmsg_len += sizeof(struct ifinfomsg);
+ n->nlmsg_len += sizeof(struct ifinfomsg);
- err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
- &name, &type, &link, &dev, &group, &index);
+ err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type);
if (err < 0)
return err;
if (type)
duparg("type", argv[err]);
- if (name) {
- addattr_l(hdr, 1024,
- IFLA_IFNAME, name, strlen(name) + 1);
- }
-
peer_ifm = RTA_DATA(data);
- peer_ifm->ifi_index = index;
+ peer_ifm->ifi_index = ifm->ifi_index;
peer_ifm->ifi_flags = ifm->ifi_flags;
peer_ifm->ifi_change = ifm->ifi_change;
ifm->ifi_flags = ifi_flags;
ifm->ifi_change = ifi_change;
+ ifm->ifi_index = ifi_index;
- if (group != -1)
- addattr32(hdr, 1024, IFLA_GROUP, group);
-
- data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+ addattr_nest_end(n, data);
return argc - 1 - err;
}
static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- inet_prefix saddr;
- inet_prefix daddr;
+ inet_prefix saddr, daddr;
__u32 vni = 0;
__u8 learning = 1;
__u16 dstport = 0;
!(n->nlmsg_flags & NLM_F_CREATE));
saddr.family = daddr.family = AF_UNSPEC;
- saddr.flags = daddr.flags = 0;
+
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
while (argc > 0) {
if (!matches(*argv, "id") ||
NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_LINK, "dev", *argv);
link = ll_name_to_index(*argv);
- if (link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- exit(-1);
- }
+ if (!link)
+ exit(nodev(*argv));
addattr32(n, 1024, IFLA_VXLAN_LINK, link);
} else if (!matches(*argv, "ttl") ||
!matches(*argv, "hoplimit")) {
#include <linux/bpf.h>
-#include "json_print.h"
-#include "xdp.h"
#include "bpf_util.h"
+#include "utils.h"
+#include "ip_common.h"
extern int force;
#include "ll_map.h"
#include "libgenl.h"
-static const char *values_on_off[] = { "off", "on" };
+static const char * const values_on_off[] = { "off", "on" };
-static const char *VALIDATE_STR[] = {
+static const char * const validate_str[] = {
[MACSEC_VALIDATE_DISABLED] = "disabled",
[MACSEC_VALIDATE_CHECK] = "check",
[MACSEC_VALIDATE_STRICT] = "strict",
static void ipmacsec_usage(void)
{
- fprintf(stderr, "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n");
- fprintf(stderr, " ip macsec set DEV tx sa { 0..3 } [ OPTS ]\n");
- fprintf(stderr, " ip macsec del DEV tx sa { 0..3 }\n");
- fprintf(stderr, " ip macsec add DEV rx SCI [ on | off ]\n");
- fprintf(stderr, " ip macsec set DEV rx SCI [ on | off ]\n");
- fprintf(stderr, " ip macsec del DEV rx SCI\n");
- fprintf(stderr, " ip macsec add DEV rx SCI sa { 0..3 } [ OPTS ] key ID KEY\n");
- fprintf(stderr, " ip macsec set DEV rx SCI sa { 0..3 } [ OPTS ]\n");
- fprintf(stderr, " ip macsec del DEV rx SCI sa { 0..3 }\n");
- fprintf(stderr, " ip macsec show\n");
- fprintf(stderr, " ip macsec show DEV\n");
- fprintf(stderr, "where OPTS := [ pn <u32> ] [ on | off ]\n");
- fprintf(stderr, " ID := 128-bit hex string\n");
- fprintf(stderr, " KEY := 128-bit hex string\n");
- fprintf(stderr, " SCI := { sci <u64> | port { 1..2^16-1 } address <lladdr> }\n");
+ fprintf(stderr,
+ "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n"
+ " ip macsec set DEV tx sa { 0..3 } [ OPTS ]\n"
+ " ip macsec del DEV tx sa { 0..3 }\n"
+ " ip macsec add DEV rx SCI [ on | off ]\n"
+ " ip macsec set DEV rx SCI [ on | off ]\n"
+ " ip macsec del DEV rx SCI\n"
+ " ip macsec add DEV rx SCI sa { 0..3 } [ OPTS ] key ID KEY\n"
+ " ip macsec set DEV rx SCI sa { 0..3 } [ OPTS ]\n"
+ " ip macsec del DEV rx SCI sa { 0..3 }\n"
+ " ip macsec show\n"
+ " ip macsec show DEV\n"
+ "where OPTS := [ pn <u32> ] [ on | off ]\n"
+ " ID := 128-bit hex string\n"
+ " KEY := 128-bit hex string\n"
+ " SCI := { sci <u64> | port { 1..2^16-1 } address <lladdr> }\n");
exit(-1);
}
-static int one_of(const char *msg, const char *realval, const char **list,
+static int one_of(const char *msg, const char *realval, const char * const *list,
size_t len, int *index)
{
int i;
attrs[MACSEC_SECY_ATTR_SCB];
}
-static void print_flag(FILE *f, struct rtattr *attrs[], const char *desc,
+static void print_flag(struct rtattr *attrs[], const char *desc,
int field)
{
- if (attrs[field]) {
- const char *v = values_on_off[!!rta_getattr_u8(attrs[field])];
+ __u8 flag;
- if (is_json_context())
- print_string(PRINT_JSON, desc, NULL, v);
- else
- fprintf(f, "%s %s ", desc, v);
+ if (!attrs[field])
+ return;
+
+ flag = rta_getattr_u8(attrs[field]);
+ if (is_json_context())
+ print_bool(PRINT_JSON, desc, NULL, flag);
+ else {
+ print_string(PRINT_FP, NULL, "%s ", desc);
+ print_string(PRINT_FP, NULL, "%s ",
+ flag ? "on" : "off");
}
}
+static void print_key(struct rtattr *key)
+{
+ SPRINT_BUF(keyid);
+
+ print_string(PRINT_ANY, "key", " key %s\n",
+ hexstring_n2a(RTA_DATA(key), RTA_PAYLOAD(key),
+ keyid, sizeof(keyid)));
+}
+
#define DEFAULT_CIPHER_NAME "GCM-AES-128"
static const char *cs_id_to_name(__u64 cid)
}
}
-static void print_cipher_suite(const char *prefix, __u64 cid, __u8 icv_len)
-{
- printf("%scipher suite: %s, using ICV length %d\n", prefix,
- cs_id_to_name(cid), icv_len);
-}
-
-static void print_attrs(const char *prefix, struct rtattr *attrs[])
+static void print_attrs(struct rtattr *attrs[])
{
- print_flag(stdout, attrs, "protect", MACSEC_SECY_ATTR_PROTECT);
+ print_flag(attrs, "protect", MACSEC_SECY_ATTR_PROTECT);
if (attrs[MACSEC_SECY_ATTR_VALIDATE]) {
__u8 val = rta_getattr_u8(attrs[MACSEC_SECY_ATTR_VALIDATE]);
- printf("validate %s ", VALIDATE_STR[val]);
+ print_string(PRINT_ANY, "validate",
+ "validate %s ", validate_str[val]);
}
- print_flag(stdout, attrs, "sc", MACSEC_RXSC_ATTR_ACTIVE);
- print_flag(stdout, attrs, "sa", MACSEC_SA_ATTR_ACTIVE);
- print_flag(stdout, attrs, "encrypt", MACSEC_SECY_ATTR_ENCRYPT);
- print_flag(stdout, attrs, "send_sci", MACSEC_SECY_ATTR_INC_SCI);
- print_flag(stdout, attrs, "end_station", MACSEC_SECY_ATTR_ES);
- print_flag(stdout, attrs, "scb", MACSEC_SECY_ATTR_SCB);
+ print_flag(attrs, "sc", MACSEC_RXSC_ATTR_ACTIVE);
+ print_flag(attrs, "sa", MACSEC_SA_ATTR_ACTIVE);
+ print_flag(attrs, "encrypt", MACSEC_SECY_ATTR_ENCRYPT);
+ print_flag(attrs, "send_sci", MACSEC_SECY_ATTR_INC_SCI);
+ print_flag(attrs, "end_station", MACSEC_SECY_ATTR_ES);
+ print_flag(attrs, "scb", MACSEC_SECY_ATTR_SCB);
+ print_flag(attrs, "replay", MACSEC_SECY_ATTR_REPLAY);
- print_flag(stdout, attrs, "replay", MACSEC_SECY_ATTR_REPLAY);
if (attrs[MACSEC_SECY_ATTR_WINDOW]) {
- printf("window %d ",
- rta_getattr_u32(attrs[MACSEC_SECY_ATTR_WINDOW]));
+ __u32 win = rta_getattr_u32(attrs[MACSEC_SECY_ATTR_WINDOW]);
+
+ print_uint(PRINT_ANY, "window", "window %u ", win);
}
- if (attrs[MACSEC_SECY_ATTR_CIPHER_SUITE] &&
- attrs[MACSEC_SECY_ATTR_ICV_LEN]) {
- printf("\n");
- print_cipher_suite(prefix,
- rta_getattr_u64(attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]),
- rta_getattr_u8(attrs[MACSEC_SECY_ATTR_ICV_LEN]));
+ if (attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]) {
+ __u64 cid = rta_getattr_u64(attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]);
+
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_ANY, "cipher_suite",
+ " cipher suite: %s,", cs_id_to_name(cid));
}
+ if (attrs[MACSEC_SECY_ATTR_ICV_LEN]) {
+ __u8 icv_len = rta_getattr_u8(attrs[MACSEC_SECY_ATTR_ICV_LEN]);
+
+ print_uint(PRINT_ANY, "icv_length",
+ " using ICV length %u\n", icv_len);
+ }
}
-static void print_one_stat(const char **names, struct rtattr **attr, int idx,
- bool long_stat)
+static __u64 getattr_uint(struct rtattr *stat)
{
- int pad = strlen(names[idx]) + 1;
+ switch (RTA_PAYLOAD(stat)) {
+ case sizeof(__u64):
+ return rta_getattr_u64(stat);
+ case sizeof(__u32):
+ return rta_getattr_u32(stat);
+ case sizeof(__u16):
+ return rta_getattr_u16(stat);
+ case sizeof(__u8):
+ return rta_getattr_u8(stat);
+ default:
+ fprintf(stderr, "invalid attribute length %lu\n",
+ RTA_PAYLOAD(stat));
+ exit(-1);
+ }
+}
+
+static void print_fp_stats(const char *prefix,
+ const char *names[], unsigned int num,
+ struct rtattr *stats[])
+{
+ unsigned int i;
+ int pad;
+
+ printf("%sstats:", prefix);
+
+ for (i = 1; i < num; i++) {
+ if (!names[i])
+ continue;
+ printf(" %s", names[i]);
+ }
- if (attr[idx]) {
- if (long_stat)
- printf("%*llu", pad, rta_getattr_u64(attr[idx]));
+ printf("\n%s ", prefix);
+
+ for (i = 1; i < num; i++) {
+ if (!names[i])
+ continue;
+
+ pad = strlen(names[i]) + 1;
+ if (stats[i])
+ printf("%*llu", pad, getattr_uint(stats[i]));
else
- printf("%*u", pad, rta_getattr_u32(attr[idx]));
- } else {
- printf("%*c", pad, '-');
+ printf("%*c", pad, '-');
}
+ printf("\n");
+}
+
+static void print_json_stats(const char *names[], unsigned int num,
+ struct rtattr *stats[])
+{
+ unsigned int i;
+
+ for (i = 1; i < num; i++) {
+ if (!names[i] || !stats[i])
+ continue;
+
+ print_uint(PRINT_JSON, names[i],
+ NULL, getattr_uint(stats[i]));
+ }
+}
+
+static void print_stats(const char *prefix,
+ const char *names[], unsigned int num,
+ struct rtattr *stats[])
+{
+
+ if (is_json_context())
+ print_json_stats(names, num, stats);
+ else
+ print_fp_stats(prefix, names, num, stats);
}
static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = {
static void print_txsc_stats(const char *prefix, struct rtattr *attr)
{
struct rtattr *stats[MACSEC_TXSC_STATS_ATTR_MAX + 1];
- int i;
if (!attr || show_stats == 0)
return;
parse_rtattr_nested(stats, MACSEC_TXSC_STATS_ATTR_MAX + 1, attr);
- printf("%sstats:", prefix);
-
- for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) {
- if (!txsc_stats_names[i])
- continue;
- printf(" %s", txsc_stats_names[i]);
- }
- printf("\n%s ", prefix);
-
- for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) {
- if (!txsc_stats_names[i])
- continue;
- print_one_stat(txsc_stats_names, stats, i, true);
- }
-
- printf("\n");
+ print_stats(prefix, txsc_stats_names, NUM_MACSEC_TXSC_STATS_ATTR,
+ stats);
}
static const char *secy_stats_names[NUM_MACSEC_SECY_STATS_ATTR] = {
static void print_secy_stats(const char *prefix, struct rtattr *attr)
{
struct rtattr *stats[MACSEC_SECY_STATS_ATTR_MAX + 1];
- int i;
if (!attr || show_stats == 0)
return;
parse_rtattr_nested(stats, MACSEC_SECY_STATS_ATTR_MAX + 1, attr);
- printf("%sstats:", prefix);
- for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) {
- if (!secy_stats_names[i])
- continue;
- printf(" %s", secy_stats_names[i]);
- }
-
- printf("\n%s ", prefix);
-
- for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) {
- if (!secy_stats_names[i])
- continue;
- print_one_stat(secy_stats_names, stats, i, true);
- }
-
- printf("\n");
+ print_stats(prefix, secy_stats_names,
+ NUM_MACSEC_SECY_STATS_ATTR, stats);
}
static const char *rxsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = {
static void print_rxsa_stats(const char *prefix, struct rtattr *attr)
{
struct rtattr *stats[MACSEC_SA_STATS_ATTR_MAX + 1];
- int i;
if (!attr || show_stats == 0)
return;
parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr);
- printf("%s%s ", prefix, prefix);
-
- for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) {
- if (!rxsa_stats_names[i])
- continue;
- printf(" %s", rxsa_stats_names[i]);
- }
- printf("\n%s%s ", prefix, prefix);
-
- for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) {
- if (!rxsa_stats_names[i])
- continue;
- print_one_stat(rxsa_stats_names, stats, i, false);
- }
-
- printf("\n");
+ print_stats(prefix, rxsa_stats_names, NUM_MACSEC_SA_STATS_ATTR, stats);
}
static const char *txsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = {
return;
parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr);
- printf("%s%s %s %s\n", prefix, prefix,
- txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED],
- txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED]);
- printf("%s%s ", prefix, prefix);
-
- print_one_stat(txsa_stats_names, stats,
- MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, false);
- print_one_stat(txsa_stats_names, stats,
- MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, false);
- printf("\n");
+
+ print_stats(prefix, txsa_stats_names, NUM_MACSEC_SA_STATS_ATTR, stats);
}
static void print_tx_sc(const char *prefix, __u64 sci, __u8 encoding_sa,
struct rtattr *a;
int rem;
- printf("%sTXSC: %016llx on SA %d\n", prefix, ntohll(sci), encoding_sa);
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_0xhex(PRINT_ANY, "sci",
+ "TXSC: %016llx", ntohll(sci));
+ print_uint(PRINT_ANY, "encoding_sa",
+ " on SA %d\n", encoding_sa);
+
print_secy_stats(prefix, secy_stats);
print_txsc_stats(prefix, txsc_stats);
+ open_json_array(PRINT_JSON, "sa_list");
rem = RTA_PAYLOAD(sa);
for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
- SPRINT_BUF(keyid);
bool state;
+ open_json_object(NULL);
parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a);
state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]);
- printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix,
- rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]),
- rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]),
- values_on_off[state],
- hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]),
- RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]),
- keyid, sizeof(keyid)));
+
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_uint(PRINT_ANY, "an", "%d:",
+ rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]));
+ print_uint(PRINT_ANY, "pn", " PN %u,",
+ rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]));
+
+ print_bool(PRINT_JSON, "active", NULL, state);
+ print_string(PRINT_FP, NULL,
+ " state %s,", state ? "on" : "off");
+ print_key(sa_attr[MACSEC_SA_ATTR_KEYID]);
+
print_txsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]);
+ close_json_object();
}
+ close_json_array(PRINT_JSON, NULL);
}
static const char *rxsc_stats_names[NUM_MACSEC_RXSC_STATS_ATTR] = {
static void print_rxsc_stats(const char *prefix, struct rtattr *attr)
{
struct rtattr *stats[MACSEC_RXSC_STATS_ATTR_MAX + 1];
- int i;
if (!attr || show_stats == 0)
return;
parse_rtattr_nested(stats, MACSEC_RXSC_STATS_ATTR_MAX + 1, attr);
- printf("%sstats:", prefix);
- for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) {
- if (!rxsc_stats_names[i])
- continue;
- printf(" %s", rxsc_stats_names[i]);
- }
-
- printf("\n%s ", prefix);
- for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) {
- if (!rxsc_stats_names[i])
- continue;
- print_one_stat(rxsc_stats_names, stats, i, true);
- }
-
- printf("\n");
+ print_stats(prefix, rxsc_stats_names,
+ NUM_MACSEC_RXSC_STATS_ATTR, stats);
}
-static void print_rx_sc(const char *prefix, __u64 sci, __u8 active,
+static void print_rx_sc(const char *prefix, __be64 sci, __u8 active,
struct rtattr *rxsc_stats, struct rtattr *sa)
{
struct rtattr *sa_attr[MACSEC_SA_ATTR_MAX + 1];
struct rtattr *a;
int rem;
- printf("%sRXSC: %016llx, state %s\n", prefix, ntohll(sci),
- values_on_off[!!active]);
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_0xhex(PRINT_ANY, "sci",
+ "RXSC: %016llx,", ntohll(sci));
+ print_bool(PRINT_JSON, "active", NULL, active);
+ print_string(PRINT_FP, NULL,
+ " state %s\n", active ? "on" : "off");
print_rxsc_stats(prefix, rxsc_stats);
+ open_json_array(PRINT_JSON, "sa_list");
rem = RTA_PAYLOAD(sa);
for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
- SPRINT_BUF(keyid);
bool state;
+ open_json_object(NULL);
parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a);
state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]);
- printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix,
- rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]),
- rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]),
- values_on_off[state],
- hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]),
- RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]),
- keyid, sizeof(keyid)));
+
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_string(PRINT_FP, NULL, "%s", prefix);
+ print_uint(PRINT_ANY, "an", "%u:",
+ rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]));
+ print_uint(PRINT_ANY, "pn", " PN %u,",
+ rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]));
+
+ print_bool(PRINT_JSON, "active", NULL, state);
+ print_string(PRINT_FP, NULL, " state %s,",
+ state ? "on" : "off");
+
+ print_key(sa_attr[MACSEC_SA_ATTR_KEYID]);
+
print_rxsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]);
+ close_json_object();
+ }
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rxsc_list(struct rtattr *sc)
+{
+ int rem = RTA_PAYLOAD(sc);
+ struct rtattr *c;
+
+ open_json_array(PRINT_JSON, "rx_sc");
+ for (c = RTA_DATA(sc); RTA_OK(c, rem); c = RTA_NEXT(c, rem)) {
+ struct rtattr *sc_attr[MACSEC_RXSC_ATTR_MAX + 1];
+
+ open_json_object(NULL);
+
+ parse_rtattr_nested(sc_attr, MACSEC_RXSC_ATTR_MAX + 1, c);
+ print_rx_sc(" ",
+ rta_getattr_u64(sc_attr[MACSEC_RXSC_ATTR_SCI]),
+ rta_getattr_u32(sc_attr[MACSEC_RXSC_ATTR_ACTIVE]),
+ sc_attr[MACSEC_RXSC_ATTR_STATS],
+ sc_attr[MACSEC_RXSC_ATTR_SA_LIST]);
+ close_json_object();
}
+ close_json_array(PRINT_JSON, NULL);
}
static int process(const struct sockaddr_nl *who, struct nlmsghdr *n,
void *arg)
{
struct genlmsghdr *ghdr;
- struct rtattr *attrs[MACSEC_ATTR_MAX + 1], *sc, *c;
+ struct rtattr *attrs[MACSEC_ATTR_MAX + 1];
struct rtattr *attrs_secy[MACSEC_SECY_ATTR_MAX + 1];
int len = n->nlmsg_len;
int ifindex;
__u64 sci;
__u8 encoding_sa;
- int rem;
if (n->nlmsg_type != genl_family)
return -1;
parse_rtattr(attrs, MACSEC_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
if (!validate_dump(attrs)) {
- printf("incomplete dump message\n");
+ fprintf(stderr, "incomplete dump message\n");
return -1;
}
attrs[MACSEC_ATTR_SECY]);
if (!validate_secy_dump(attrs_secy)) {
- printf("incomplete dump message\n");
+ fprintf(stderr, "incomplete dump message\n");
return -1;
}
if (filter.sci && sci != filter.sci)
return 0;
- printf("%d: %s: ", ifindex, ll_index_to_name(ifindex));
- print_attrs(" ", attrs_secy);
+ open_json_object(NULL);
+ print_uint(PRINT_ANY, "ifindex", "%u: ", ifindex);
+ print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
+ "%s: ", ll_index_to_name(ifindex));
+
+ print_attrs(attrs_secy);
print_tx_sc(" ", sci, encoding_sa,
attrs[MACSEC_ATTR_TXSC_STATS],
attrs[MACSEC_ATTR_SECY_STATS],
attrs[MACSEC_ATTR_TXSA_LIST]);
- if (!attrs[MACSEC_ATTR_RXSC_LIST])
- return 0;
+ if (attrs[MACSEC_ATTR_RXSC_LIST])
+ print_rxsc_list(attrs[MACSEC_ATTR_RXSC_LIST]);
- sc = attrs[MACSEC_ATTR_RXSC_LIST];
- rem = RTA_PAYLOAD(sc);
- for (c = RTA_DATA(sc); RTA_OK(c, rem); c = RTA_NEXT(c, rem)) {
- struct rtattr *sc_attr[MACSEC_RXSC_ATTR_MAX + 1];
-
- parse_rtattr_nested(sc_attr, MACSEC_RXSC_ATTR_MAX + 1, c);
- print_rx_sc(" ",
- rta_getattr_u64(sc_attr[MACSEC_RXSC_ATTR_SCI]),
- rta_getattr_u32(sc_attr[MACSEC_RXSC_ATTR_ACTIVE]),
- sc_attr[MACSEC_RXSC_ATTR_STATS],
- sc_attr[MACSEC_RXSC_ATTR_SA_LIST]);
- }
+ close_json_object();
return 0;
}
exit(1);
}
+ new_json_obj(json);
if (rtnl_dump_filter(&genl_rth, process, stdout) < 0) {
+ delete_json_obj();
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+ delete_json_obj();
return 0;
}
}
}
- print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT);
+ print_flag(tb, "protect", IFLA_MACSEC_PROTECT);
if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
- __u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
+ __u64 csid
+ = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
print_string(PRINT_ANY,
"cipher_suite",
print_string(PRINT_ANY,
"validation",
"validate %s ",
- VALIDATE_STR[val]);
+ validate_str[val]);
}
const char *inc_sci, *es, *replay;
replay = "replay";
}
- print_flag(f, tb, "encrypt", IFLA_MACSEC_ENCRYPT);
- print_flag(f, tb, inc_sci, IFLA_MACSEC_INC_SCI);
- print_flag(f, tb, es, IFLA_MACSEC_ES);
- print_flag(f, tb, "scb", IFLA_MACSEC_SCB);
- print_flag(f, tb, replay, IFLA_MACSEC_REPLAY_PROTECT);
+ print_flag(tb, "encrypt", IFLA_MACSEC_ENCRYPT);
+ print_flag(tb, inc_sci, IFLA_MACSEC_INC_SCI);
+ print_flag(tb, es, IFLA_MACSEC_ES);
+ print_flag(tb, "scb", IFLA_MACSEC_SCB);
+ print_flag(tb, replay, IFLA_MACSEC_REPLAY_PROTECT);
if (tb[IFLA_MACSEC_WINDOW])
print_int(PRINT_ANY,
}
static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
- struct nlmsghdr *hdr)
+ struct nlmsghdr *n)
{
int ret;
__u8 encoding_sa = 0xff;
if (ret > 0) {
if (sci.sci)
- addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
+ addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
&sci.sci, sizeof(sci.sci));
else
- addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
+ addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
&sci.port, sizeof(sci.port));
}
ARRAY_SIZE(values_on_off), &i);
if (ret != 0)
return ret;
- addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
+ addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
} else if (strcmp(*argv, "send_sci") == 0) {
NEXT_ARG();
int i;
if (ret != 0)
return ret;
send_sci = i;
- addattr8(hdr, MACSEC_BUFLEN,
+ addattr8(n, MACSEC_BUFLEN,
IFLA_MACSEC_INC_SCI, send_sci);
} else if (strcmp(*argv, "end_station") == 0) {
NEXT_ARG();
if (ret != 0)
return ret;
es = i;
- addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
+ addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
} else if (strcmp(*argv, "scb") == 0) {
NEXT_ARG();
int i;
if (ret != 0)
return ret;
scb = i;
- addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
+ addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
} else if (strcmp(*argv, "protect") == 0) {
NEXT_ARG();
int i;
ARRAY_SIZE(values_on_off), &i);
if (ret != 0)
return ret;
- addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
+ addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
} else if (strcmp(*argv, "replay") == 0) {
NEXT_ARG();
int i;
} else if (strcmp(*argv, "validate") == 0) {
NEXT_ARG();
ret = one_of("validate", *argv,
- VALIDATE_STR, ARRAY_SIZE(VALIDATE_STR),
+ validate_str, ARRAY_SIZE(validate_str),
(int *)&validate);
if (ret != 0)
return ret;
- addattr8(hdr, MACSEC_BUFLEN,
+ addattr8(n, MACSEC_BUFLEN,
IFLA_MACSEC_VALIDATION, validate);
} else if (strcmp(*argv, "encodingsa") == 0) {
if (encoding_sa != 0xff)
}
if (!check_txsc_flags(es, scb, send_sci)) {
- fprintf(stderr, "invalid combination of send_sci/end_station/scb\n");
+ fprintf(stderr,
+ "invalid combination of send_sci/end_station/scb\n");
return -1;
}
}
if (cipher.id)
- addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
+ addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
&cipher.id, sizeof(cipher.id));
if (cipher.icv_len)
- addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
+ addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
&cipher.icv_len, sizeof(cipher.icv_len));
if (replay_protect != -1) {
- addattr32(hdr, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
- addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
+ addattr32(n, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
+ addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
replay_protect);
}
if (encoding_sa != 0xff) {
- addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
+ addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
&encoding_sa, sizeof(encoding_sa));
}
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
+#include "json_print.h"
static struct {
char *dev;
static void print_maddr(FILE *fp, struct ma_info *list)
{
- fprintf(fp, "\t");
+ print_string(PRINT_FP, NULL, "\t", NULL);
+ open_json_object(NULL);
if (list->addr.family == AF_PACKET) {
SPRINT_BUF(b1);
- fprintf(fp, "link %s", ll_addr_n2a((unsigned char *)list->addr.data,
- list->addr.bytelen, 0,
- b1, sizeof(b1)));
+
+ print_string(PRINT_FP, NULL, "link ", NULL);
+ print_color_string(PRINT_ANY, COLOR_MAC, "link", "%s",
+ ll_addr_n2a((void *)list->addr.data, list->addr.bytelen,
+ 0, b1, sizeof(b1)));
} else {
- switch (list->addr.family) {
- case AF_INET:
- fprintf(fp, "inet ");
- break;
- case AF_INET6:
- fprintf(fp, "inet6 ");
- break;
- default:
- fprintf(fp, "family %d ", list->addr.family);
- break;
- }
- fprintf(fp, "%s",
- format_host(list->addr.family,
- -1, list->addr.data));
+ print_string(PRINT_ANY, "family", "%-5s ",
+ family_name(list->addr.family));
+ print_color_string(PRINT_ANY, ifa_family_color(list->addr.family),
+ "address", "%s",
+ format_host(list->addr.family,
+ -1, list->addr.data));
}
+
if (list->users != 1)
- fprintf(fp, " users %d", list->users);
+ print_uint(PRINT_ANY, "users", " users %u", list->users);
+
if (list->features)
- fprintf(fp, " %s", list->features);
- fprintf(fp, "\n");
+ print_string(PRINT_ANY, "features", " %s", list->features);
+
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
}
static void print_mlist(FILE *fp, struct ma_info *list)
{
int cur_index = 0;
+ new_json_obj(json);
for (; list; list = list->next) {
- if (oneline) {
- cur_index = list->index;
- fprintf(fp, "%d:\t%s%s", cur_index, list->name, _SL_);
- } else if (cur_index != list->index) {
+
+ if (list->index != cur_index || oneline) {
+ if (cur_index) {
+ close_json_array(PRINT_JSON, NULL);
+ close_json_object();
+ }
+ open_json_object(NULL);
+
+ print_uint(PRINT_ANY, "ifindex", "%d:", list->index);
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "ifname", "\t%s", list->name);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
cur_index = list->index;
- fprintf(fp, "%d:\t%s\n", cur_index, list->name);
+
+ open_json_array(PRINT_JSON, "maddr");
}
+
print_maddr(fp, list);
}
+ if (cur_index) {
+ close_json_array(PRINT_JSON, NULL);
+ close_json_object();
+ }
+
+ delete_json_obj();
}
static int multiaddr_list(int argc, char **argv)
#include <rt_names.h>
#include "utils.h"
#include "ip_common.h"
+#include "json_print.h"
static void usage(void) __attribute__((noreturn));
int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
- FILE *fp = (FILE *)arg;
struct rtmsg *r = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[RTA_MAX+1];
- char obuf[256];
-
+ const char *src, *dst;
SPRINT_BUF(b1);
+ SPRINT_BUF(b2);
__u32 table;
int iif = 0;
int family;
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
return -1;
}
+
if (r->rtm_type != RTN_MULTICAST) {
- fprintf(stderr, "Not a multicast route (type: %s)\n",
- rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
- return 0;
+ fprintf(stderr,
+ "Non multicast route received, kernel does support IP multicast?\n");
+ return -1;
}
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
family = get_real_family(r->rtm_type, r->rtm_family);
+ open_json_object(NULL);
if (n->nlmsg_type == RTM_DELROUTE)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (tb[RTA_SRC])
- len = snprintf(obuf, sizeof(obuf),
- "(%s, ", rt_addr_n2a_rta(family, tb[RTA_SRC]));
+ src = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_SRC]),
+ RTA_DATA(tb[RTA_SRC]), b1, sizeof(b1));
else
- len = sprintf(obuf, "(unknown, ");
+ src = "unknown";
+
if (tb[RTA_DST])
- snprintf(obuf + len, sizeof(obuf) - len,
- "%s)", rt_addr_n2a_rta(family, tb[RTA_DST]));
+ dst = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_DST]),
+ RTA_DATA(tb[RTA_DST]), b2, sizeof(b2));
else
- snprintf(obuf + len, sizeof(obuf) - len, "unknown) ");
+ dst = "unknown";
+
+ if (is_json_context()) {
+ print_string(PRINT_JSON, "src", NULL, src);
+ print_string(PRINT_JSON, "dst", NULL, dst);
+ } else {
+ char obuf[256];
+
+ snprintf(obuf, sizeof(obuf), "(%s,%s)", src, dst);
+ print_string(PRINT_FP, NULL,
+ "%-32s Iif: ", obuf);
+ }
- fprintf(fp, "%-32s Iif: ", obuf);
if (iif)
- fprintf(fp, "%-10s ", ll_index_to_name(iif));
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "iif", "%-10s ", ll_index_to_name(iif));
else
- fprintf(fp, "unresolved ");
+ print_string(PRINT_ANY,"iif", "%s ", "unresolved");
if (tb[RTA_MULTIPATH]) {
struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
int first = 1;
+ open_json_array(PRINT_JSON, "multipath");
len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
for (;;) {
if (nh->rtnh_len > len)
break;
+ open_json_object(NULL);
if (first) {
- fprintf(fp, "Oifs: ");
+ print_string(PRINT_FP, NULL, "Oifs: ", NULL);
first = 0;
}
- fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
+
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "oif", "%s", ll_index_to_name(nh->rtnh_ifindex));
+
if (nh->rtnh_hops > 1)
- fprintf(fp, "(ttl %d) ", nh->rtnh_hops);
+ print_uint(PRINT_ANY,
+ "ttl", "(ttl %u) ", nh->rtnh_hops);
else
- fprintf(fp, " ");
+ print_string(PRINT_FP, NULL, " ", NULL);
+
+ close_json_object();
len -= NLMSG_ALIGN(nh->rtnh_len);
nh = RTNH_NEXT(nh);
}
+ close_json_array(PRINT_JSON, NULL);
}
- fprintf(fp, " State: %s",
- r->rtm_flags & RTNH_F_UNRESOLVED ? "unresolved" : "resolved");
+
+ print_string(PRINT_ANY, "state", " State: %s",
+ (r->rtm_flags & RTNH_F_UNRESOLVED) ? "unresolved" : "resolved");
+
if (r->rtm_flags & RTNH_F_OFFLOAD)
- fprintf(fp, " offload");
+ print_null(PRINT_ANY, "offload", " offload", NULL);
+
if (show_stats && tb[RTA_MFC_STATS]) {
struct rta_mfc_stats *mfcs = RTA_DATA(tb[RTA_MFC_STATS]);
- fprintf(fp, "%s %"PRIu64" packets, %"PRIu64" bytes", _SL_,
- (uint64_t)mfcs->mfcs_packets,
- (uint64_t)mfcs->mfcs_bytes);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_uint(PRINT_ANY, "packets", " %"PRIu64" packets,",
+ mfcs->mfcs_packets);
+ print_uint(PRINT_ANY, "bytes", " %"PRIu64" bytes", mfcs->mfcs_bytes);
+
if (mfcs->mfcs_wrong_if)
- fprintf(fp, ", %"PRIu64" arrived on wrong iif.",
- (uint64_t)mfcs->mfcs_wrong_if);
+ print_uint(PRINT_ANY, "wrong_if",
+ ", %"PRIu64" arrived on wrong iif.",
+ mfcs->mfcs_wrong_if);
}
+
if (show_stats && tb[RTA_EXPIRES]) {
struct timeval tv;
+ double age;
__jiffies_to_tv(&tv, rta_getattr_u64(tb[RTA_EXPIRES]));
- fprintf(fp, ", Age %4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
+ age = tv.tv_sec;
+ age += tv.tv_usec / 1000000.;
+ print_float(PRINT_ANY, "expires",
+ ", Age %.2f", age);
}
if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
- fprintf(fp, " Table: %s",
- rtnl_rttable_n2a(table, b1, sizeof(b1)));
+ print_string(PRINT_ANY, "table", " Table: %s",
+ rtnl_rttable_n2a(table, b1, sizeof(b1)));
- fprintf(fp, "\n");
- fflush(fp);
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
return 0;
}
if (id) {
int idx;
- if ((idx = ll_name_to_index(id)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", id);
- return -1;
- }
+ idx = ll_name_to_index(id);
+ if (!idx)
+ return nodev(id);
filter.iif = idx;
}
return 1;
}
+ new_json_obj(json);
if (rtnl_dump_filter(&rth, print_mroute, stdout) < 0) {
+ delete_json_obj();
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+ delete_json_obj();
- exit(0);
+ return 0;
}
int do_multiroute(int argc, char **argv)
#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
ll_init_map(&rth);
- if (dev && (req.ndm.ndm_ifindex = ll_name_to_index(dev)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", dev);
- return -1;
+ if (dev) {
+ req.ndm.ndm_ifindex = ll_name_to_index(dev);
+ if (!req.ndm.ndm_ifindex)
+ return nodev(dev);
}
if (rtnl_talk(&rth, &req.n, NULL) < 0)
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)
{
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)) {
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 (tb[NDA_PROBES] && show_stats) {
- __u32 p = rta_getattr_u32(tb[NDA_PROBES]);
+ if (!is_json_context())
+ fprintf(fp, "lladdr ");
- fprintf(fp, " probes %u", p);
+ print_color_string(PRINT_ANY, COLOR_MAC,
+ "lladdr", "%s", lladdr);
}
- if (r->ndm_state) {
- int nud = r->ndm_state;
-
- fprintf(fp, " ");
-
-#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
+ if (r->ndm_flags & NTF_ROUTER)
+ print_null(PRINT_ANY, "router", " %s", "router");
+
+ 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]));
}
- fprintf(fp, "\n");
- fflush(fp);
+ if (r->ndm_state)
+ print_neigh_state(r->ndm_state);
+
+ print_string(PRINT_FP, NULL, "\n", "");
+ close_json_object();
+ fflush(stdout);
+
return 0;
}
ll_init_map(&rth);
if (filter_dev) {
- if ((filter.index = ll_name_to_index(filter_dev)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
- return -1;
- }
+ filter.index = ll_name_to_index(filter_dev);
+ if (!filter.index)
+ return nodev(filter_dev);
addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
}
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;
}
int ifindex;
} filter;
+static const char * const rp_filter_names[] = {
+ "off", "strict", "loose"
+};
+
static void usage(void) __attribute__((noreturn));
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)
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]));
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;
}
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;
}
} 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
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;
} 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);
}
#include "list.h"
#include "ip_common.h"
#include "namespace.h"
+#include "json_print.h"
static int usage(void)
{
return -1;
}
+ open_json_object(NULL);
if (n->nlmsg_type == RTM_DELNSID)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
nsid = rta_getattr_u32(tb[NETNSA_NSID]);
- fprintf(fp, "nsid %u ", nsid);
+ print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
c = netns_map_get_by_nsid(nsid);
if (c != NULL) {
- fprintf(fp, "(iproute2 netns name: %s)", c->name);
+ print_string(PRINT_ANY, "name",
+ "(iproute2 netns name: %s)", c->name);
netns_map_del(c);
}
/* During 'ip monitor nsid', no chance to have new nsid in cache. */
if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
if (netns_get_name(nsid, name) == 0) {
- fprintf(fp, "(iproute2 netns name: %s)", name);
+ print_string(PRINT_ANY, "name",
+ "(iproute2 netns name: %s)", name);
netns_map_add(nsid, name);
}
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
fflush(fp);
return 0;
}
perror("Cannot send dump request");
exit(1);
}
+
+ new_json_obj(json);
if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
+ delete_json_obj();
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+ delete_json_obj();
return 0;
}
if (!dir)
return 0;
+ new_json_obj(json);
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
- printf("%s", entry->d_name);
+
+ open_json_object(NULL);
+ print_string(PRINT_ANY, "name",
+ "%s", entry->d_name);
if (ipnetns_have_nsid()) {
id = get_netnsid_from_name(entry->d_name);
if (id >= 0)
- printf(" (id: %d)", id);
+ print_uint(PRINT_ANY, "id",
+ " (id: %d)", id);
}
- printf("\n");
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
}
closedir(dir);
+ delete_json_obj();
return 0;
}
#include "utils.h"
#include "ip_common.h"
+#include "json_print.h"
static struct
{
NEXT_ARG();
ifindex = ll_name_to_index(*argv);
- if (ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
- return -1;
- }
+ if (!ifindex)
+ return nodev(*argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_IFINDEX, ifindex);
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)
{
- FILE *fp = (FILE *)arg;
- struct ndtmsg *ndtm = NLMSG_DATA(n);
- int len = n->nlmsg_len;
- struct rtattr *tb[NDTA_MAX+1];
- struct rtattr *tpb[NDTPA_MAX+1];
- int ret;
- if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
- fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
- n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
- return 0;
- }
- len -= NLMSG_LENGTH(sizeof(*ndtm));
- if (len < 0) {
- fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
- return -1;
- }
+ 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);
- if (preferred_family && preferred_family != ndtm->ndtm_family)
- return 0;
+ print_string(PRINT_FP, NULL, "%s", _SL_);
- parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
- n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
+ 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));
- if (tb[NDTA_NAME]) {
- const char *name = rta_getattr_str(tb[NDTA_NAME]);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
- 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]));
+ 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);
- if (tpb[NDTPA_IFINDEX]) {
- __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+ 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);
- if (filter.index && filter.index != ifindex)
- return 0;
- } else {
- if (filter.index && filter.index != NONE_DEV)
- return 0;
- }
+ 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_);
}
- 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);
+ print_string(PRINT_FP, NULL, " ", NULL);
+ if (tpb[NDTPA_REFCNT]) {
+ __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
- if (tb[NDTA_NAME]) {
- const char *name = rta_getattr_str(tb[NDTA_NAME]);
+ print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt);
+ }
- fprintf(fp, "%s ", name);
+ if (tpb[NDTPA_REACHABLE_TIME]) {
+ __u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+
+ print_uint(PRINT_ANY, "reachable",
+ "reachable %llu ", reachable);
}
- fprintf(fp, "%s", _SL_);
+ if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
+ __u64 breachable
+ = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
- ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
- tb[NDTA_GC_INTERVAL]);
- if (ret)
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "base_reachable",
+ "base_reachable %llu ", breachable);
+ }
- if (tb[NDTA_THRESH1]) {
- __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
+ if (tpb[NDTPA_RETRANS_TIME]) {
+ __u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
- fprintf(fp, "thresh1 %u ", thresh1);
+ print_uint(PRINT_ANY, "retrans", "retrans %llu ", retrans);
}
- if (tb[NDTA_THRESH2]) {
- __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
- fprintf(fp, "thresh2 %u ", thresh2);
+ 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 (tb[NDTA_THRESH3]) {
- __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
- fprintf(fp, "thresh3 %u ", thresh3);
+ 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 (tb[NDTA_GC_INTERVAL]) {
- unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
- fprintf(fp, "gc_int %llu ", gc_int);
+ if (tpb[NDTPA_QUEUE_LEN]) {
+ __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+
+ print_uint(PRINT_ANY, "queue", "queue %u ", queue);
}
- 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 (tpb[NDTPA_APP_PROBES]) {
+ __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
- fprintf(fp, " ");
- fprintf(fp, "config ");
+ print_uint(PRINT_ANY, "app_probes", "app_probes %u ", aprobe);
+ }
- 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);
+ if (tpb[NDTPA_UCAST_PROBES]) {
+ __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "ucast_probes",
+ "ucast_probes %u ", uprobe);
+ }
- fprintf(fp, "last_flush %s ",
- ntable_strtime_delta(ndtc->ndtc_last_flush));
- fprintf(fp, "last_rand %s ",
- ntable_strtime_delta(ndtc->ndtc_last_rand));
+ if (tpb[NDTPA_MCAST_PROBES]) {
+ __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "mcast_probes",
+ "mcast_probes %u ", mprobe);
+ }
- fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
- fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
- fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
- fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
+ if (tpb[NDTPA_ANYCAST_DELAY]) {
+ __u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
- fprintf(fp, "%s", _SL_);
+ print_uint(PRINT_ANY, "anycast_delay",
+ "anycast_delay %llu ", anycast_delay);
}
- if (tb[NDTA_PARMS]) {
- if (tpb[NDTPA_IFINDEX]) {
- __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+ if (tpb[NDTPA_PROXY_DELAY]) {
+ __u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
- fprintf(fp, " ");
- fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
- fprintf(fp, "%s", _SL_);
- }
+ print_uint(PRINT_ANY, "proxy_delay",
+ "proxy_delay %llu ", proxy_delay);
+ }
- fprintf(fp, " ");
+ if (tpb[NDTPA_PROXY_QLEN]) {
+ __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
- if (tpb[NDTPA_REFCNT]) {
- __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
+ print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue);
+ }
- fprintf(fp, "refcnt %u ", refcnt);
- }
- if (tpb[NDTPA_REACHABLE_TIME]) {
- unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+ if (tpb[NDTPA_LOCKTIME]) {
+ __u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
- fprintf(fp, "reachable %llu ", reachable);
- }
- if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
- unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
+ print_uint(PRINT_ANY, "locktime", "locktime %llu ", locktime);
+ }
- fprintf(fp, "base_reachable %llu ", breachable);
- }
- if (tpb[NDTPA_RETRANS_TIME]) {
- unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+}
- fprintf(fp, "retrans %llu ", retrans);
- }
+static void print_ndtstats(const struct ndt_stats *ndts)
+{
- fprintf(fp, "%s", _SL_);
+ print_string(PRINT_FP, NULL, " stats ", NULL);
- fprintf(fp, " ");
+ 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);
- if (tpb[NDTPA_GC_STALETIME]) {
- unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
- 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]);
+ 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);
- fprintf(fp, "delay_probe %llu ", delay_probe);
- }
- if (tpb[NDTPA_QUEUE_LEN]) {
- __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
- fprintf(fp, "queue %u ", queue);
- }
+ 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);
- fprintf(fp, "%s", _SL_);
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
- fprintf(fp, " ");
+ 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);
- if (tpb[NDTPA_APP_PROBES]) {
- __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+}
- fprintf(fp, "app_probes %u ", aprobe);
- }
- if (tpb[NDTPA_UCAST_PROBES]) {
- __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
+static int print_ntable(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE *)arg;
+ struct ndtmsg *ndtm = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[NDTA_MAX+1];
+ struct rtattr *tpb[NDTPA_MAX+1];
+ int ret;
- fprintf(fp, "ucast_probes %u ", uprobe);
- }
- if (tpb[NDTPA_MCAST_PROBES]) {
- __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
+ if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
+ fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+ len -= NLMSG_LENGTH(sizeof(*ndtm));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
- fprintf(fp, "mcast_probes %u ", mprobe);
- }
+ if (preferred_family && preferred_family != ndtm->ndtm_family)
+ return 0;
- fprintf(fp, "%s", _SL_);
+ parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
+ n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
- fprintf(fp, " ");
+ if (tb[NDTA_NAME]) {
+ const char *name = rta_getattr_str(tb[NDTA_NAME]);
+
+ if (filter.name && strcmp(filter.name, name))
+ return 0;
+ }
- if (tpb[NDTPA_ANYCAST_DELAY]) {
- unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
+ if (tb[NDTA_PARMS]) {
+ parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
+ RTA_PAYLOAD(tb[NDTA_PARMS]));
- fprintf(fp, "anycast_delay %llu ", anycast_delay);
- }
- if (tpb[NDTPA_PROXY_DELAY]) {
- unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
+ if (tpb[NDTPA_IFINDEX]) {
+ __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
- fprintf(fp, "proxy_delay %llu ", proxy_delay);
+ if (filter.index && filter.index != ifindex)
+ return 0;
+ } else {
+ if (filter.index && filter.index != NONE_DEV)
+ return 0;
}
- 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]);
+ open_json_object(NULL);
+ print_string(PRINT_ANY, "family",
+ "%s ", family_name(ndtm->ndtm_family));
- fprintf(fp, "locktime %llu ", locktime);
- }
+ if (tb[NDTA_NAME]) {
+ const char *name = rta_getattr_str(tb[NDTA_NAME]);
- fprintf(fp, "%s", _SL_);
+ print_string(PRINT_ANY, "name", "%s ", name);
}
- if (tb[NDTA_STATS] && show_stats) {
- struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
- fprintf(fp, " ");
- fprintf(fp, "stats ");
+ ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
+ tb[NDTA_GC_INTERVAL]);
+ if (ret)
+ print_string(PRINT_FP, NULL, " ", NULL);
- 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);
+ if (tb[NDTA_THRESH1]) {
+ __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "thresh1", "thresh1 %u ", thresh1);
+ }
- 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);
+ if (tb[NDTA_THRESH2]) {
+ __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "thresh2", "thresh2 %u ", thresh2);
+ }
- 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);
+ if (tb[NDTA_THRESH3]) {
+ __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
+ print_uint(PRINT_ANY, "thresh3", "thresh3 %u ", thresh3);
+ }
- 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);
+ if (tb[NDTA_GC_INTERVAL]) {
+ __u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
- fprintf(fp, "%s", _SL_);
+ print_uint(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int);
}
- fprintf(fp, "\n");
+ if (ret)
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ if (tb[NDTA_CONFIG] && show_stats)
+ print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG]));
+
+ if (tb[NDTA_PARMS])
+ print_ndtparams(tpb);
+
+ 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;
}
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;
}
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
-#include "iproute_lwtunnel.h"
#ifndef RTAX_RTTVAR
#define RTAX_RTTVAR RTAX_HOPS
if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
ip6_multiple_tables = 1;
- if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
+ if (filter.cloned == !(r->rtm_flags & RTM_F_CLONED))
return 0;
if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
unsigned int of = features;
if (features & RTAX_FEATURE_ECN) {
- fprintf(fp, "ecn ");
+ print_null(PRINT_ANY, "ecn", "ecn ", NULL);
features &= ~RTAX_FEATURE_ECN;
}
if (features)
- fprintf(fp, "0x%x ", of);
+ print_0xhex(PRINT_ANY,
+ "features", "0x%x ", of);
+}
+
+static void print_rt_flags(FILE *fp, unsigned int flags)
+{
+ open_json_array(PRINT_JSON,
+ is_json_context() ? "flags" : "");
+
+ if (flags & RTNH_F_DEAD)
+ print_string(PRINT_ANY, NULL, "%s ", "dead");
+ if (flags & RTNH_F_ONLINK)
+ print_string(PRINT_ANY, NULL, "%s ", "onlink");
+ if (flags & RTNH_F_PERVASIVE)
+ print_string(PRINT_ANY, NULL, "%s ", "pervasive");
+ if (flags & RTNH_F_OFFLOAD)
+ print_string(PRINT_ANY, NULL, "%s ", "offload");
+ if (flags & RTM_F_NOTIFY)
+ print_string(PRINT_ANY, NULL, "%s ", "notify");
+ if (flags & RTNH_F_LINKDOWN)
+ print_string(PRINT_ANY, NULL, "%s ", "linkdown");
+ if (flags & RTNH_F_UNRESOLVED)
+ print_string(PRINT_ANY, NULL, "%s ", "unresolved");
+
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rt_pref(FILE *fp, unsigned int pref)
+{
+
+ switch (pref) {
+ case ICMPV6_ROUTER_PREF_LOW:
+ print_string(PRINT_ANY,
+ "pref", "pref %s", "low");
+ break;
+ case ICMPV6_ROUTER_PREF_MEDIUM:
+ print_string(PRINT_ANY,
+ "pref", "pref %s", "medium");
+ break;
+ case ICMPV6_ROUTER_PREF_HIGH:
+ print_string(PRINT_ANY,
+ "pref", "pref %s", "high");
+ break;
+ default:
+ print_uint(PRINT_ANY,
+ "pref", "%u", pref);
+ }
+}
+
+static void print_rta_if(FILE *fp, const struct rtattr *rta,
+ const char *prefix)
+{
+ const char *ifname = ll_index_to_name(rta_getattr_u32(rta));
+
+ if (is_json_context())
+ print_string(PRINT_JSON, prefix, NULL, ifname);
+ else {
+ fprintf(fp, "%s ", prefix);
+ color_fprintf(fp, COLOR_IFNAME, "%s ", ifname);
+ }
+}
+
+static void print_cache_flags(FILE *fp, __u32 flags)
+{
+ json_writer_t *jw = get_json_writer();
+ flags &= ~0xFFFF;
+
+ if (jw) {
+ jsonw_name(jw, "cache");
+ jsonw_start_array(jw);
+ } else {
+ fprintf(fp, "%s cache ", _SL_);
+ if (flags == 0)
+ return;
+ putc('<', fp);
+ }
+
+#define PRTFL(fl, flname) \
+ if (flags & RTCF_##fl) { \
+ flags &= ~RTCF_##fl; \
+ if (jw) \
+ jsonw_string(jw, flname); \
+ else \
+ fprintf(fp, "%s%s", flname, flags ? "," : "> "); \
+ }
+
+ PRTFL(LOCAL, "local");
+ PRTFL(REJECT, "reject");
+ PRTFL(MULTICAST, "mc");
+ PRTFL(BROADCAST, "brd");
+ PRTFL(DNAT, "dst-nat");
+ PRTFL(SNAT, "src-nat");
+ PRTFL(MASQ, "masq");
+ PRTFL(DIRECTDST, "dst-direct");
+ PRTFL(DIRECTSRC, "src-direct");
+ PRTFL(REDIRECTED, "redirected");
+ PRTFL(DOREDIRECT, "redirect");
+ PRTFL(FAST, "fastroute");
+ PRTFL(NOTIFY, "notify");
+ PRTFL(TPROXY, "proxy");
+#undef PRTFL
+
+ if (flags)
+ print_hex(PRINT_ANY, "flags", "%x>", flags);
+
+ if (jw) {
+ jsonw_end_array(jw);
+ jsonw_destroy(&jw);
+ }
+}
+
+static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
+{
+ static int hz;
+
+ if (!hz)
+ hz = get_user_hz();
+
+ if (ci->rta_expires != 0)
+ print_uint(PRINT_ANY, "expires",
+ "expires %usec ", ci->rta_expires/hz);
+ if (ci->rta_error != 0)
+ print_uint(PRINT_ANY, "error",
+ "error %u ", ci->rta_error);
+
+ if (show_stats) {
+ if (ci->rta_clntref)
+ print_uint(PRINT_ANY, "users",
+ "users %u ", ci->rta_clntref);
+ if (ci->rta_used != 0)
+ print_uint(PRINT_ANY, "used",
+ "used %u ", ci->rta_used);
+ if (ci->rta_lastuse != 0)
+ print_uint(PRINT_ANY, "age",
+ "age %usec ", ci->rta_lastuse/hz);
+ }
+ if (ci->rta_id)
+ print_0xhex(PRINT_ANY, "ipid",
+ "ipid 0x%04x ", ci->rta_id);
+ if (ci->rta_ts || ci->rta_tsage) {
+ print_0xhex(PRINT_ANY, "ts",
+ "ts 0x%x", ci->rta_ts);
+ print_uint(PRINT_ANY, "tsage",
+ "tsage %usec ", ci->rta_tsage);
+ }
+}
+
+static void print_rta_flow(FILE *fp, const struct rtattr *rta)
+{
+ __u32 to = rta_getattr_u32(rta);
+ __u32 from = to >> 16;
+ SPRINT_BUF(b1);
+
+ to &= 0xFFFF;
+ if (is_json_context()) {
+ open_json_object("flow");
+
+ if (from)
+ print_string(PRINT_JSON, "from", NULL,
+ rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+ print_string(PRINT_JSON, "to", NULL,
+ rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+ close_json_object();
+ } else {
+ fprintf(fp, "realm%s ", from ? "s" : "");
+
+ if (from)
+ print_string(PRINT_FP, NULL, "%s/",
+ rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+ print_string(PRINT_FP, NULL, "%s ",
+ rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+ }
+}
+
+static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
+ const struct rtattr *rta)
+{
+ const char *newdst = format_host_rta(r->rtm_family, rta);
+
+ if (is_json_context())
+ print_string(PRINT_JSON, "to", NULL, newdst);
+ else {
+ fprintf(fp, "as to ");
+ print_color_string(PRINT_FP,
+ ifa_family_color(r->rtm_family),
+ NULL, "%s ", newdst);
+ }
+}
+
+static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
+ const struct rtattr *rta)
+{
+ const char *gateway = format_host_rta(r->rtm_family, rta);
+
+ if (is_json_context())
+ print_string(PRINT_JSON, "gateway", NULL, gateway);
+ else {
+ fprintf(fp, "via ");
+ print_color_string(PRINT_FP,
+ ifa_family_color(r->rtm_family),
+ NULL, "%s ", gateway);
+ }
+}
+
+static void print_rta_via(FILE *fp, const struct rtattr *rta)
+{
+ size_t len = RTA_PAYLOAD(rta) - 2;
+ const struct rtvia *via = RTA_DATA(rta);
+
+ if (is_json_context()) {
+ open_json_object("via");
+ print_string(PRINT_JSON, "family", NULL,
+ family_name(via->rtvia_family));
+ print_string(PRINT_JSON, "host", NULL,
+ format_host(via->rtvia_family, len,
+ via->rtvia_addr));
+ close_json_object();
+ } else {
+ print_string(PRINT_FP, NULL, "via %s ",
+ family_name(via->rtvia_family));
+ print_color_string(PRINT_FP,
+ ifa_family_color(via->rtvia_family),
+ NULL, "%s ",
+ format_host(via->rtvia_family,
+ len, via->rtvia_addr));
+ }
+}
+
+static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
+{
+ struct rtattr *mxrta[RTAX_MAX+1];
+ unsigned int mxlock = 0;
+ int i;
+
+ open_json_array(PRINT_JSON, "metrics");
+
+ parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
+
+ if (mxrta[RTAX_LOCK])
+ mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
+
+ for (i = 2; i <= RTAX_MAX; i++) {
+ __u32 val = 0U;
+
+ if (mxrta[i] == NULL && !(mxlock & (1 << i)))
+ continue;
+
+ if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
+ val = rta_getattr_u32(mxrta[i]);
+
+ if (i == RTAX_HOPLIMIT && (int)val == -1)
+ continue;
+
+ if (!is_json_context()) {
+ if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
+ fprintf(fp, "%s ", mx_names[i]);
+ else
+ fprintf(fp, "metric %d ", i);
+
+ if (mxlock & (1<<i))
+ fprintf(fp, "lock ");
+ }
+
+ switch (i) {
+ case RTAX_FEATURES:
+ print_rtax_features(fp, val);
+ break;
+ default:
+ fprintf(fp, "%u ", val);
+ break;
+
+ case RTAX_RTT:
+ case RTAX_RTTVAR:
+ case RTAX_RTO_MIN:
+ if (i == RTAX_RTT)
+ val /= 8;
+ else if (i == RTAX_RTTVAR)
+ val /= 4;
+
+ if (is_json_context())
+ print_uint(PRINT_JSON, mx_names[i],
+ NULL, val);
+ else {
+ if (val >= 1000)
+ fprintf(fp, "%gs ", val/1e3);
+ else
+ fprintf(fp, "%ums ", val);
+ }
+ break;
+ case RTAX_CC_ALGO:
+ print_string(PRINT_ANY, "congestion",
+ "%s ", rta_getattr_str(mxrta[i]));
+ break;
+ }
+ }
+
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
+ struct rtattr *rta)
+{
+ const struct rtnexthop *nh = RTA_DATA(rta);
+ int len = RTA_PAYLOAD(rta);
+ int first = 1;
+
+ while (len > sizeof(*nh)) {
+ struct rtattr *tb[RTA_MAX + 1];
+
+ if (nh->rtnh_len > len)
+ break;
+
+ if (!is_json_context()) {
+ if ((r->rtm_flags & RTM_F_CLONED) &&
+ r->rtm_type == RTN_MULTICAST) {
+ if (first) {
+ fprintf(fp, "Oifs: ");
+ first = 0;
+ } else {
+ fprintf(fp, " ");
+ }
+ } else
+ fprintf(fp, "%s\tnexthop ", _SL_);
+ }
+
+ if (nh->rtnh_len > sizeof(*nh)) {
+ parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
+ nh->rtnh_len - sizeof(*nh));
+
+ if (tb[RTA_ENCAP])
+ lwt_print_encap(fp,
+ tb[RTA_ENCAP_TYPE],
+ tb[RTA_ENCAP]);
+ if (tb[RTA_NEWDST])
+ print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+ if (tb[RTA_GATEWAY])
+ print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+ if (tb[RTA_VIA])
+ print_rta_via(fp, tb[RTA_VIA]);
+ if (tb[RTA_FLOW])
+ print_rta_flow(fp, tb[RTA_FLOW]);
+ }
+
+ if ((r->rtm_flags & RTM_F_CLONED) &&
+ r->rtm_type == RTN_MULTICAST) {
+ fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
+ if (nh->rtnh_hops != 1)
+ fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
+ fprintf(fp, " ");
+ } else {
+ fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
+ if (r->rtm_family != AF_MPLS)
+ fprintf(fp, "weight %d ",
+ nh->rtnh_hops+1);
+ }
+
+ print_rt_flags(fp, nh->rtnh_flags);
+
+ len -= NLMSG_ALIGN(nh->rtnh_len);
+ nh = RTNH_NEXT(nh);
+ }
}
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
struct rtmsg *r = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[RTA_MAX+1];
- int host_len, family;
+ int family, color, host_len;
__u32 table;
int ret;
SPRINT_BUF(b1);
- static int hz;
if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
fprintf(stderr, "Not a route: %08x %08x %08x\n",
struct nlmsghdr *fn;
if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
- if ((ret = flush_update()) < 0)
+ ret = flush_update();
+ if (ret < 0)
return ret;
}
fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
return 0;
}
+ open_json_object(NULL);
if (n->nlmsg_type == RTM_DELROUTE)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
(!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
- fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+ print_string(PRINT_ANY, NULL, "%s ",
+ rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+ color = COLOR_NONE;
if (tb[RTA_DST]) {
family = get_real_family(r->rtm_type, r->rtm_family);
+ color = ifa_family_color(family);
+
if (r->rtm_dst_len != host_len) {
- fprintf(fp, "%s/%u ",
- rt_addr_n2a_rta(family, tb[RTA_DST]),
- r->rtm_dst_len);
+ snprintf(b1, sizeof(b1),
+ "%s/%u", rt_addr_n2a_rta(family, tb[RTA_DST]),
+ r->rtm_dst_len);
} else {
- fprintf(fp, "%s ",
- format_host_rta(family, tb[RTA_DST]));
+ format_host_rta_r(family, tb[RTA_DST],
+ b1, sizeof(b1));
+
}
} else if (r->rtm_dst_len) {
- fprintf(fp, "0/%d ", r->rtm_dst_len);
+ snprintf(b1, sizeof(b1), "0/%d ", r->rtm_dst_len);
} else {
- fprintf(fp, "default ");
+ strncpy(b1, "default", sizeof(b1));
}
+ print_color_string(PRINT_ANY, color,
+ "dst", "%s ", b1);
+
if (tb[RTA_SRC]) {
family = get_real_family(r->rtm_type, r->rtm_family);
+ color = ifa_family_color(family);
+
if (r->rtm_src_len != host_len) {
- fprintf(fp, "from %s/%u ",
- rt_addr_n2a_rta(family, tb[RTA_SRC]),
- r->rtm_src_len);
+ snprintf(b1, sizeof(b1),
+ "%s/%u",
+ rt_addr_n2a_rta(family, tb[RTA_SRC]),
+ r->rtm_src_len);
} else {
- fprintf(fp, "from %s ",
- format_host_rta(family, tb[RTA_SRC]));
+ format_host_rta_r(family, tb[RTA_SRC],
+ b1, sizeof(b1));
}
+ print_color_string(PRINT_ANY, color,
+ "from", "from %s ", b1);
} else if (r->rtm_src_len) {
- fprintf(fp, "from 0/%u ", r->rtm_src_len);
- }
- if (tb[RTA_NEWDST]) {
- fprintf(fp, "as to %s ",
- format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
+ snprintf(b1, sizeof(b1), "0/%u", r->rtm_src_len);
+
+ print_string(PRINT_ANY, "src", "from %s ", b1);
}
+ if (tb[RTA_NEWDST])
+ print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+
if (tb[RTA_ENCAP])
lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
if (r->rtm_tos && filter.tosmask != -1) {
- SPRINT_BUF(b1);
- fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+ print_string(PRINT_ANY, "tos", "tos %s ",
+ rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
}
- if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
- fprintf(fp, "via %s ",
- format_host_rta(r->rtm_family, tb[RTA_GATEWAY]));
- }
- if (tb[RTA_VIA]) {
- size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
- struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+ if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
+ print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+
+ if (tb[RTA_VIA])
+ print_rta_via(fp, tb[RTA_VIA]);
- fprintf(fp, "via %s %s ",
- family_name(via->rtvia_family),
- format_host(via->rtvia_family, len, via->rtvia_addr));
- }
if (tb[RTA_OIF] && filter.oifmask != -1)
- fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
+ print_rta_if(fp, tb[RTA_OIF], "dev");
if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
- fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
- if (!(r->rtm_flags&RTM_F_CLONED)) {
- if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
- fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
- if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
- fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
+ print_string(PRINT_ANY,
+ "table", "table %s ",
+ rtnl_rttable_n2a(table, b1, sizeof(b1)));
+
+ if (!(r->rtm_flags & RTM_F_CLONED)) {
+ if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) &&
+ filter.protocolmask != -1)
+ print_string(PRINT_ANY,
+ "protocol", "proto %s ",
+ rtnl_rtprot_n2a(r->rtm_protocol,
+ b1, sizeof(b1)));
+
+ if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) &&
+ filter.scopemask != -1)
+ print_string(PRINT_ANY,
+ "scope", "scope %s ",
+ rtnl_rtscope_n2a(r->rtm_scope,
+ b1, sizeof(b1)));
}
+
if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
+ const char *psrc
+ = rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]);
+
/* Do not use format_host(). It is our local addr
and symbolic name will not be useful.
- */
- fprintf(fp, "src %s ",
- rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]));
+ */
+ if (is_json_context())
+ print_string(PRINT_JSON, "prefsrc", NULL, psrc);
+ else {
+ fprintf(fp, "src ");
+ print_color_string(PRINT_FP,
+ ifa_family_color(r->rtm_family),
+ NULL, "%s ", psrc);
+ }
+
}
+
if (tb[RTA_PRIORITY] && filter.metricmask != -1)
- fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
- if (r->rtm_flags & RTNH_F_DEAD)
- fprintf(fp, "dead ");
- if (r->rtm_flags & RTNH_F_ONLINK)
- fprintf(fp, "onlink ");
- if (r->rtm_flags & RTNH_F_PERVASIVE)
- fprintf(fp, "pervasive ");
- if (r->rtm_flags & RTNH_F_OFFLOAD)
- fprintf(fp, "offload ");
- if (r->rtm_flags & RTM_F_NOTIFY)
- fprintf(fp, "notify ");
- if (r->rtm_flags & RTNH_F_LINKDOWN)
- fprintf(fp, "linkdown ");
- if (r->rtm_flags & RTNH_F_UNRESOLVED)
- fprintf(fp, "unresolved ");
+ print_uint(PRINT_ANY, "metric", "metric %u ",
+ rta_getattr_u32(tb[RTA_PRIORITY]));
+
+ print_rt_flags(fp, r->rtm_flags);
+
if (tb[RTA_MARK]) {
unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
if (mark) {
- if (mark >= 16)
- fprintf(fp, "mark 0x%x ", mark);
+ if (is_json_context())
+ print_uint(PRINT_JSON, "mark", NULL, mark);
+ else if (mark >= 16)
+ print_0xhex(PRINT_FP, NULL,
+ "mark 0x%x ", mark);
else
- fprintf(fp, "mark %u ", mark);
+ print_uint(PRINT_FP, NULL,
+ "mark %u ", mark);
}
}
- if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
- __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
- __u32 from = to>>16;
-
- to &= 0xFFFF;
- fprintf(fp, "realm%s ", from ? "s" : "");
- if (from) {
- fprintf(fp, "%s/",
- rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
- }
- fprintf(fp, "%s ",
- rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
- }
+ if (tb[RTA_FLOW] && filter.realmmask != ~0U)
+ print_rta_flow(fp, tb[RTA_FLOW]);
if (tb[RTA_UID])
- fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
+ print_uint(PRINT_ANY, "uid", "uid %u ",
+ rta_getattr_u32(tb[RTA_UID]));
- if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
- __u32 flags = r->rtm_flags&~0xFFFF;
- int first = 1;
+ if (r->rtm_family == AF_INET) {
+ if (r->rtm_flags & RTM_F_CLONED) {
+ print_cache_flags(fp, r->rtm_flags);
- fprintf(fp, "%s cache ", _SL_);
-
-#define PRTFL(fl, flname) if (flags&RTCF_##fl) { \
- flags &= ~RTCF_##fl; \
- fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
- first = 0; }
- PRTFL(LOCAL, "local");
- PRTFL(REJECT, "reject");
- PRTFL(MULTICAST, "mc");
- PRTFL(BROADCAST, "brd");
- PRTFL(DNAT, "dst-nat");
- PRTFL(SNAT, "src-nat");
- PRTFL(MASQ, "masq");
- PRTFL(DIRECTDST, "dst-direct");
- PRTFL(DIRECTSRC, "src-direct");
- PRTFL(REDIRECTED, "redirected");
- PRTFL(DOREDIRECT, "redirect");
- PRTFL(FAST, "fastroute");
- PRTFL(NOTIFY, "notify");
- PRTFL(TPROXY, "proxy");
-
- if (flags)
- fprintf(fp, "%s%x> ", first ? "<" : "", flags);
- if (tb[RTA_CACHEINFO]) {
- struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
-
- if (!hz)
- hz = get_user_hz();
- if (ci->rta_expires != 0)
- fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
- if (ci->rta_error != 0)
- fprintf(fp, "error %d ", ci->rta_error);
- if (show_stats) {
- if (ci->rta_clntref)
- fprintf(fp, "users %d ", ci->rta_clntref);
- if (ci->rta_used != 0)
- fprintf(fp, "used %d ", ci->rta_used);
- if (ci->rta_lastuse != 0)
- fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
- }
- if (ci->rta_id)
- fprintf(fp, "ipid 0x%04x ", ci->rta_id);
- if (ci->rta_ts || ci->rta_tsage)
- fprintf(fp, "ts 0x%x tsage %dsec ",
- ci->rta_ts, ci->rta_tsage);
+ if (tb[RTA_CACHEINFO])
+ print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
}
} else if (r->rtm_family == AF_INET6) {
- struct rta_cacheinfo *ci = NULL;
-
- if (tb[RTA_CACHEINFO])
- ci = RTA_DATA(tb[RTA_CACHEINFO]);
- if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
- if (!hz)
- hz = get_user_hz();
- if (r->rtm_flags & RTM_F_CLONED)
- fprintf(fp, "%s cache ", _SL_);
- if (ci->rta_expires)
- fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
- if (ci->rta_error != 0)
- fprintf(fp, "error %d ", ci->rta_error);
- if (show_stats) {
- if (ci->rta_clntref)
- fprintf(fp, "users %d ", ci->rta_clntref);
- if (ci->rta_used != 0)
- fprintf(fp, "used %d ", ci->rta_used);
- if (ci->rta_lastuse != 0)
- fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
- }
- } else if (ci) {
- if (ci->rta_error != 0)
- fprintf(fp, "error %d ", ci->rta_error);
+ if (r->rtm_flags & RTM_F_CLONED) {
+ if (tb[RTA_CACHEINFO])
+ print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
}
}
- if (tb[RTA_METRICS]) {
- int i;
- unsigned int mxlock = 0;
- struct rtattr *mxrta[RTAX_MAX+1];
-
- parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
- RTA_PAYLOAD(tb[RTA_METRICS]));
- if (mxrta[RTAX_LOCK])
- mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
- for (i = 2; i <= RTAX_MAX; i++) {
- __u32 val = 0U;
+ if (tb[RTA_METRICS])
+ print_rta_metrics(fp, tb[RTA_METRICS]);
- if (mxrta[i] == NULL && !(mxlock & (1 << i)))
- continue;
+ if (tb[RTA_IIF] && filter.iifmask != -1)
+ print_rta_if(fp, tb[RTA_IIF], "iif");
- if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
- val = rta_getattr_u32(mxrta[i]);
+ if (tb[RTA_MULTIPATH])
+ print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
- if (i == RTAX_HOPLIMIT && (int)val == -1)
- continue;
+ if (tb[RTA_PREF])
+ print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
- if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
- fprintf(fp, "%s ", mx_names[i]);
- else
- fprintf(fp, "metric %d ", i);
-
- if (mxlock & (1<<i))
- fprintf(fp, "lock ");
-
- switch (i) {
- case RTAX_FEATURES:
- print_rtax_features(fp, val);
- break;
- default:
- fprintf(fp, "%u ", val);
- break;
-
- case RTAX_RTT:
- case RTAX_RTTVAR:
- case RTAX_RTO_MIN:
- if (i == RTAX_RTT)
- val /= 8;
- else if (i == RTAX_RTTVAR)
- val /= 4;
-
- if (val >= 1000)
- fprintf(fp, "%gs ", val/1e3);
- else
- fprintf(fp, "%ums ", val);
- break;
- case RTAX_CC_ALGO:
- fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
- break;
- }
- }
- }
- if (tb[RTA_IIF] && filter.iifmask != -1) {
- fprintf(fp, "iif %s ",
- ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
- }
- if (tb[RTA_MULTIPATH]) {
- struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
- int first = 1;
-
- len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
-
- for (;;) {
- if (len < sizeof(*nh))
- break;
- if (nh->rtnh_len > len)
- break;
- if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
- if (first) {
- fprintf(fp, "Oifs: ");
- first = 0;
- } else {
- fprintf(fp, " ");
- }
- } else
- fprintf(fp, "%s\tnexthop ", _SL_);
- if (nh->rtnh_len > sizeof(*nh)) {
- parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
-
- if (tb[RTA_ENCAP])
- lwt_print_encap(fp,
- tb[RTA_ENCAP_TYPE],
- tb[RTA_ENCAP]);
- if (tb[RTA_NEWDST]) {
- fprintf(fp, "as to %s ",
- format_host_rta(r->rtm_family,
- tb[RTA_NEWDST]));
- }
- if (tb[RTA_GATEWAY]) {
- fprintf(fp, "via %s ",
- format_host_rta(r->rtm_family,
- tb[RTA_GATEWAY]));
- }
- if (tb[RTA_VIA]) {
- size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
- struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
-
- fprintf(fp, "via %s %s ",
- family_name(via->rtvia_family),
- format_host(via->rtvia_family, len, via->rtvia_addr));
- }
- if (tb[RTA_FLOW]) {
- __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
- __u32 from = to>>16;
-
- to &= 0xFFFF;
- fprintf(fp, "realm%s ", from ? "s" : "");
- if (from) {
- fprintf(fp, "%s/",
- rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
- }
- fprintf(fp, "%s ",
- rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
- }
- }
- if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
- fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
- if (nh->rtnh_hops != 1)
- fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
- fprintf(fp, " ");
- } else {
- fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
- if (r->rtm_family != AF_MPLS)
- fprintf(fp, "weight %d ",
- nh->rtnh_hops+1);
- }
- if (nh->rtnh_flags & RTNH_F_DEAD)
- fprintf(fp, "dead ");
- if (nh->rtnh_flags & RTNH_F_ONLINK)
- fprintf(fp, "onlink ");
- if (nh->rtnh_flags & RTNH_F_PERVASIVE)
- fprintf(fp, "pervasive ");
- if (nh->rtnh_flags & RTNH_F_OFFLOAD)
- fprintf(fp, "offload ");
- if (nh->rtnh_flags & RTNH_F_LINKDOWN)
- fprintf(fp, "linkdown ");
- len -= NLMSG_ALIGN(nh->rtnh_len);
- nh = RTNH_NEXT(nh);
- }
- }
- if (tb[RTA_PREF]) {
- unsigned int pref = rta_getattr_u8(tb[RTA_PREF]);
-
- fprintf(fp, "pref ");
-
- switch (pref) {
- case ICMPV6_ROUTER_PREF_LOW:
- fprintf(fp, "low");
- break;
- case ICMPV6_ROUTER_PREF_MEDIUM:
- fprintf(fp, "medium");
- break;
- case ICMPV6_ROUTER_PREF_HIGH:
- fprintf(fp, "high");
- break;
- default:
- fprintf(fp, "%u", pref);
- }
- }
if (tb[RTA_TTL_PROPAGATE]) {
- fprintf(fp, "ttl-propagate ");
- if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
- fprintf(fp, "enabled");
+ bool propogate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
+
+ if (is_json_context())
+ print_bool(PRINT_JSON, "ttl-propogate", NULL,
+ propogate);
else
- fprintf(fp, "disabled");
+ print_string(PRINT_FP, NULL,
+ "ttl-propogate %s",
+ propogate ? "enabled" : "disabled");
}
- fprintf(fp, "\n");
+
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
fflush(fp);
return 0;
}
}
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
- if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
- return -1;
- }
+ rtnh->rtnh_ifindex = ll_name_to_index(*argv);
+ if (!rtnh->rtnh_ifindex)
+ return nodev(*argv);
} else if (strcmp(*argv, "weight") == 0) {
unsigned int w;
usage();
if (d) {
- int idx;
+ int idx = ll_name_to_index(d);
- if ((idx = ll_name_to_index(d)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ if (!idx)
+ return nodev(d);
addattr32(&req.n, sizeof(req), RTA_OIF, idx);
}
return 0;
}
+static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
+{
+ time_t start = time(0);
+ char flushb[4096-512];
+ int round = 0;
+ int ret;
+
+ if (filter.cloned) {
+ if (do_ipv6 != AF_INET6) {
+ iproute_flush_cache();
+ if (show_stats)
+ printf("*** IPv4 routing cache is flushed.\n");
+ }
+ if (do_ipv6 == AF_INET)
+ return 0;
+ }
+
+ filter.flushb = flushb;
+ filter.flushp = 0;
+ filter.flushe = sizeof(flushb);
+
+ for (;;) {
+ if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+ perror("Cannot send dump request");
+ return -2;
+ }
+ filter.flushed = 0;
+ if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ return -2;
+ }
+ if (filter.flushed == 0) {
+ if (show_stats) {
+ if (round == 0 &&
+ (!filter.cloned || do_ipv6 == AF_INET6))
+ printf("Nothing to flush.\n");
+ else
+ printf("*** Flush is complete after %d round%s ***\n",
+ round, round > 1 ? "s" : "");
+ }
+ fflush(stdout);
+ return 0;
+ }
+ round++;
+ ret = flush_update();
+ if (ret < 0)
+ return ret;
+
+ if (time(0) - start > 30) {
+ printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
+ (long)(time(0) - start), filter.flushed);
+ return -1;
+ }
+
+ if (show_stats) {
+ printf("\n*** Round %d, deleting %d entries ***\n",
+ round, filter.flushed);
+ fflush(stdout);
+ }
+ }
+}
+
static int iproute_list_flush_or_save(int argc, char **argv, int action)
{
int do_ipv6 = preferred_family;
char *od = NULL;
unsigned int mark = 0;
rtnl_filter_t filter_fn;
- int ret;
if (action == IPROUTE_SAVE) {
if (save_route_prep())
invarg("invalid mark value", *argv);
filter.markmask = -1;
} else if (matches(*argv, "metric") == 0 ||
- matches(*argv, "priority") == 0 ||
- strcmp(*argv, "preference") == 0) {
+ matches(*argv, "priority") == 0 ||
+ strcmp(*argv, "preference") == 0) {
__u32 metric;
NEXT_ARG();
int idx;
if (id) {
- if ((idx = ll_name_to_index(id)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", id);
- return -1;
- }
+ idx = ll_name_to_index(id);
+ if (!idx)
+ return nodev(id);
filter.iif = idx;
filter.iifmask = -1;
}
if (od) {
- if ((idx = ll_name_to_index(od)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", od);
- return -1;
- }
+ idx = ll_name_to_index(od);
+ if (!idx)
+ return nodev(od);
filter.oif = idx;
filter.oifmask = -1;
}
}
filter.mark = mark;
- if (action == IPROUTE_FLUSH) {
- int round = 0;
- char flushb[4096-512];
- time_t start = time(0);
-
- if (filter.cloned) {
- if (do_ipv6 != AF_INET6) {
- iproute_flush_cache();
- if (show_stats)
- printf("*** IPv4 routing cache is flushed.\n");
- }
- if (do_ipv6 == AF_INET)
- return 0;
- }
-
- filter.flushb = flushb;
- filter.flushp = 0;
- filter.flushe = sizeof(flushb);
-
- for (;;) {
- if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
- perror("Cannot send dump request");
- return -2;
- }
- filter.flushed = 0;
- if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
- fprintf(stderr, "Flush terminated\n");
- return -2;
- }
- if (filter.flushed == 0) {
- if (show_stats) {
- if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
- printf("Nothing to flush.\n");
- else
- printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
- }
- fflush(stdout);
- return 0;
- }
- round++;
- if ((ret = flush_update()) < 0)
- return ret;
-
- if (time(0) - start > 30) {
- printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
- (long)(time(0) - start), filter.flushed);
- return -1;
- }
-
- if (show_stats) {
- printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
- fflush(stdout);
- }
- }
- }
+ if (action == IPROUTE_FLUSH)
+ return iproute_flush(do_ipv6, filter_fn);
if (!filter.cloned) {
if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
}
}
+ new_json_obj(json);
+
if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -2;
}
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
int idx;
if (idev) {
- if ((idx = ll_name_to_index(idev)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", idev);
- return -1;
- }
+ idx = ll_name_to_index(idev);
+ if (!idx)
+ return nodev(idev);
addattr32(&req.n, sizeof(req), RTA_IIF, idx);
}
if (odev) {
- if ((idx = ll_name_to_index(odev)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", odev);
- return -1;
- }
+ idx = ll_name_to_index(odev);
+ if (!idx)
+ return nodev(odev);
addattr32(&req.n, sizeof(req), RTA_OIF, idx);
}
}
return iproute_showdump();
if (matches(*argv, "help") == 0)
usage();
- fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
+
+ fprintf(stderr,
+ "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
exit(-1);
}
#include <errno.h>
#include "rt_names.h"
-#include "utils.h"
-#include "iproute_lwtunnel.h"
#include "bpf_util.h"
+#include "utils.h"
+#include "ip_common.h"
#include "ila_common.h"
#include <linux/seg6.h>
{
int i;
- fprintf(fp, "segs %d [ ", srh->first_segment + 1);
+ if (is_json_context())
+ open_json_array(PRINT_JSON, "segs");
+ else
+ fprintf(fp, "segs %d [ ", srh->first_segment + 1);
for (i = srh->first_segment; i >= 0; i--)
- fprintf(fp, "%s ",
- rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
+ print_color_string(PRINT_ANY, COLOR_INET6,
+ NULL, "%s ",
+ rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
- fprintf(fp, "] ");
+ if (is_json_context())
+ close_json_array(PRINT_JSON, NULL);
+ else
+ fprintf(fp, "] ");
if (sr_has_hmac(srh)) {
unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
struct sr6_tlv_hmac *tlv;
tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
- fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid));
+ print_0xhex(PRINT_ANY, "hmac",
+ "hmac 0x%X ", ntohl(tlv->hmackeyid));
}
}
return;
tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
- fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode));
+ print_string(PRINT_ANY, "mode",
+ "mode %s ", format_seg6mode_type(tuninfo->mode));
print_srh(fp, tuninfo->srh);
}
action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
- fprintf(fp, "action %s ", format_action_type(action));
+ print_string(PRINT_ANY, "action",
+ "action %s ", format_action_type(action));
if (tb[SEG6_LOCAL_SRH]) {
- fprintf(fp, "srh ");
+ open_json_object("srh");
print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
+ close_json_object();
}
if (tb[SEG6_LOCAL_TABLE])
- fprintf(fp, "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
+ print_uint(PRINT_ANY, "table",
+ "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
if (tb[SEG6_LOCAL_NH4]) {
- fprintf(fp, "nh4 %s ",
- rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
+ print_string(PRINT_ANY, "nh4",
+ "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
}
if (tb[SEG6_LOCAL_NH6]) {
- fprintf(fp, "nh6 %s ",
- rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
+ print_string(PRINT_ANY, "nh6",
+ "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
}
if (tb[SEG6_LOCAL_IIF]) {
int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
- fprintf(fp, "iif %s ", ll_index_to_name(iif));
+ print_string(PRINT_ANY, "iif",
+ "iif %s ", ll_index_to_name(iif));
}
if (tb[SEG6_LOCAL_OIF]) {
int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
- fprintf(fp, "oif %s ", ll_index_to_name(oif));
+ print_string(PRINT_ANY, "oif",
+ "oif %s ", ll_index_to_name(oif));
}
}
parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
if (tb[MPLS_IPTUNNEL_DST])
- fprintf(fp, " %s ",
+ print_string(PRINT_ANY, "dst", " %s ",
format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
if (tb[MPLS_IPTUNNEL_TTL])
- fprintf(fp, "ttl %u ",
+ print_uint(PRINT_ANY, "ttl", "ttl %u ",
rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
}
parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
if (tb[LWTUNNEL_IP_ID])
- fprintf(fp, "id %llu ",
- ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
+ print_uint(PRINT_ANY, "id", "id %llu ",
+ ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
if (tb[LWTUNNEL_IP_SRC])
- fprintf(fp, "src %s ",
- rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
+ print_color_string(PRINT_ANY, COLOR_INET,
+ "src", "src %s ",
+ rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
if (tb[LWTUNNEL_IP_DST])
- fprintf(fp, "dst %s ",
- rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
+ print_color_string(PRINT_ANY, COLOR_INET,
+ "dst", "dst %s ",
+ rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
if (tb[LWTUNNEL_IP_TTL])
- fprintf(fp, "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
+ print_uint(PRINT_ANY, "ttl",
+ "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
if (tb[LWTUNNEL_IP_TOS])
- fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
+ print_uint(PRINT_ANY, "tos",
+ "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
}
static void print_encap_ila(FILE *fp, struct rtattr *encap)
addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
abuf, sizeof(abuf));
- fprintf(fp, " %s ", abuf);
+ print_string(PRINT_ANY, "locator",
+ " %s ", abuf);
}
if (tb[ILA_ATTR_CSUM_MODE])
- fprintf(fp, " csum-mode %s ",
- ila_csum_mode2name(rta_getattr_u8(
- tb[ILA_ATTR_CSUM_MODE])));
+ print_string(PRINT_ANY, "csum_mode",
+ " csum-mode %s ",
+ ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
if (tb[ILA_ATTR_IDENT_TYPE])
- fprintf(fp, " ident-type %s ",
- ila_ident_type2name(rta_getattr_u8(
- tb[ILA_ATTR_IDENT_TYPE])));
+ print_string(PRINT_ANY, "ident_type",
+ " ident-type %s ",
+ ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
if (tb[ILA_ATTR_HOOK_TYPE])
- fprintf(fp, " hook-type %s ",
- ila_hook_type2name(rta_getattr_u8(
- tb[ILA_ATTR_HOOK_TYPE])));
+ print_string(PRINT_ANY, "hook_type",
+ " hook-type %s ",
+ ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
}
static void print_encap_ip6(FILE *fp, struct rtattr *encap)
parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
if (tb[LWTUNNEL_IP6_ID])
- fprintf(fp, "id %llu ",
- ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
+ print_uint(PRINT_ANY, "id", "id %llu ",
+ ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
if (tb[LWTUNNEL_IP6_SRC])
- fprintf(fp, "src %s ",
- rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
+ print_color_string(PRINT_ANY, COLOR_INET6,
+ "src", "src %s ",
+ rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
if (tb[LWTUNNEL_IP6_DST])
- fprintf(fp, "dst %s ",
- rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
+ print_color_string(PRINT_ANY, COLOR_INET6,
+ "dst", "dst %s ",
+ rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
if (tb[LWTUNNEL_IP6_HOPLIMIT])
- fprintf(fp, "hoplimit %u ",
- rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
+ print_uint(PRINT_ANY, "hoplimit",
+ "hoplimit %u ",
+ rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
if (tb[LWTUNNEL_IP6_TC])
- fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
+ print_uint(PRINT_ANY, "tc",
+ "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
}
static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
const char *str)
{
struct rtattr *tb[LWT_BPF_PROG_MAX+1];
+ const char *progname = NULL;
parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
- fprintf(fp, "%s ", str);
if (tb[LWT_BPF_PROG_NAME])
- fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
+ progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
+
+ if (is_json_context())
+ print_string(PRINT_JSON, str, NULL,
+ progname ? : "<unknown>");
+ else {
+ fprintf(fp, "%s ", str);
+ if (progname)
+ fprintf(fp, "%s ", progname);
+ }
}
static void print_encap_bpf(FILE *fp, struct rtattr *encap)
if (tb[LWT_BPF_XMIT])
print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
if (tb[LWT_BPF_XMIT_HEADROOM])
- fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
+ print_uint(PRINT_ANY, "headroom",
+ " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
}
void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
et = rta_getattr_u16(encap_type);
- fprintf(fp, " encap %s ", format_encap_type(et));
+ print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
switch (et) {
case LWTUNNEL_ENCAP_MPLS:
duparg2("iif", *argv);
iif = ll_name_to_index(*argv);
if (!iif)
- invarg("\"iif\" interface not found\n", *argv);
+ exit(nodev(*argv));
rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
} else if (strcmp(*argv, "oif") == 0) {
NEXT_ARG();
duparg2("oif", *argv);
oif = ll_name_to_index(*argv);
if (!oif)
- invarg("\"oif\" interface not found\n", *argv);
+ exit(nodev(*argv));
rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
} else if (strcmp(*argv, "srh") == 0) {
NEXT_ARG();
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LWTUNNEL_H__
-#define __LETUNNEL_H__ 1
-
-int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp);
-void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
- struct rtattr *encap);
-
-#endif
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
+#include "json_print.h"
enum list_action {
IPRULE_LIST,
"SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"
" [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
" [ uidrange NUMBER-NUMBER ]\n"
+ " [ ipproto PROTOCOL ]\n"
+ " [ sport [ NUMBER | NUMBER-NUMBER ]\n"
+ " [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
"ACTION := [ table TABLE_ID ]\n"
+ " [ protocol PROTO ]\n"
" [ nat ADDRESS ]\n"
" [ realms [SRCREALM/]DSTREALM ]\n"
" [ goto NUMBER ]\n"
struct fib_rule_uid_range range;
inet_prefix src;
inet_prefix dst;
+ int protocol;
+ int protocolmask;
} filter;
+static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
+{
+ __u32 table = frh->table;
+ if (tb[RTA_TABLE])
+ table = rta_getattr_u32(tb[RTA_TABLE]);
+ return table;
+}
+
static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
{
- struct rtmsg *r = NLMSG_DATA(n);
+ struct fib_rule_hdr *frh = NLMSG_DATA(n);
__u32 table;
- if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
+ if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
return false;
if (filter.prefmask &&
filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
return false;
- if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT))
+ if (filter.not && !(frh->flags & FIB_RULE_INVERT))
return false;
if (filter.src.family) {
inet_prefix *f_src = &filter.src;
- if (f_src->family != r->rtm_family ||
- f_src->bitlen > r->rtm_src_len)
+ if (f_src->family != frh->family ||
+ f_src->bitlen > frh->src_len)
return false;
if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
if (filter.dst.family) {
inet_prefix *f_dst = &filter.dst;
- if (f_dst->family != r->rtm_family ||
- f_dst->bitlen > r->rtm_dst_len)
+ if (f_dst->family != frh->family ||
+ f_dst->bitlen > frh->dst_len)
return false;
if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
return false;
}
- if (filter.tosmask && filter.tos ^ r->rtm_tos)
+ if (filter.tosmask && filter.tos ^ frh->tos)
return false;
if (filter.fwmark) {
return false;
}
- table = rtm_get_table(r, tb);
+ table = frh_get_table(frh, tb);
if (filter.tb > 0 && filter.tb ^ table)
return false;
int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
- FILE *fp = (FILE *)arg;
- struct rtmsg *r = NLMSG_DATA(n);
+ 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)
return 0;
- len -= NLMSG_LENGTH(sizeof(*r));
+ len -= NLMSG_LENGTH(sizeof(*frh));
if (len < 0)
return -1;
- parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+ parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
- host_len = af_bit_len(r->rtm_family);
+ host_len = af_bit_len(frh->family);
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 (r->rtm_flags & FIB_RULE_INVERT)
- fprintf(fp, "not ");
+ if (frh->flags & FIB_RULE_INVERT)
+ print_null(PRINT_ANY, "not", "not ", NULL);
if (tb[FRA_SRC]) {
- if (r->rtm_src_len != host_len) {
- fprintf(fp, "from %s/%u ",
- rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
- r->rtm_src_len);
- } else {
- fprintf(fp, "from %s ",
- format_host_rta(r->rtm_family, tb[FRA_SRC]));
- }
- } else if (r->rtm_src_len) {
- fprintf(fp, "from 0/%d ", r->rtm_src_len);
+ 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) {
+ 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 (r->rtm_dst_len != host_len) {
- fprintf(fp, "to %s/%u ",
- rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
- r->rtm_dst_len);
- } else {
- fprintf(fp, "to %s ",
- format_host_rta(r->rtm_family, tb[FRA_DST]));
- }
- } else if (r->rtm_dst_len) {
- fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+ 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) {
+ print_string(PRINT_ANY, "dst", "to %s", "0");
+ print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
}
- if (r->rtm_tos) {
- SPRINT_BUF(b1);
- fprintf(fp, "tos %s ",
- rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+ if (frh->tos) {
+ print_string(PRINT_ANY, "tos",
+ "tos %s ",
+ rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
}
if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
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 (r->rtm_flags & FIB_RULE_IIF_DETACHED)
- fprintf(fp, "[detached] ");
+ 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)
+ print_null(PRINT_ANY, "iif_detached", "[detached] ",
+ NULL);
}
if (tb[FRA_OIFNAME]) {
- fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
- if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
- fprintf(fp, "[detached] ");
+ 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)
+ 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);
+ }
+
+ if (tb[FRA_IP_PROTO]) {
+ SPRINT_BUF(pbuf);
+ print_string(PRINT_ANY, "ipproto", "ipproto %s ",
+ inet_proto_n2a(rta_getattr_u8(tb[FRA_IP_PROTO]),
+ pbuf, sizeof(pbuf)));
+ }
+
+ if (tb[FRA_SPORT_RANGE]) {
+ struct fib_rule_port_range *r = RTA_DATA(tb[FRA_SPORT_RANGE]);
+
+ if (r->start == r->end) {
+ print_uint(PRINT_ANY, "sport", "sport %u ", r->start);
+ } else {
+ print_uint(PRINT_ANY, "sport_start", "sport %u",
+ r->start);
+ print_uint(PRINT_ANY, "sport_end", "-%u ", r->end);
+ }
+ }
+
+ if (tb[FRA_DPORT_RANGE]) {
+ struct fib_rule_port_range *r = RTA_DATA(tb[FRA_DPORT_RANGE]);
+
+ if (r->start == r->end) {
+ print_uint(PRINT_ANY, "dport", "dport %u ", r->start);
+ } else {
+ print_uint(PRINT_ANY, "dport_start", "dport %u",
+ r->start);
+ print_uint(PRINT_ANY, "dport_end", "-%u ", r->end);
+ }
}
- table = rtm_get_table(r, tb);
+ 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);
}
}
}
__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 (r->rtm_type == RTN_NAT) {
+ if (frh->action == RTN_NAT) {
if (tb[RTA_GATEWAY]) {
- fprintf(fp, "map-to %s ",
- format_host_rta(r->rtm_family,
- tb[RTA_GATEWAY]));
- } else
- fprintf(fp, "masquerade");
- } else if (r->rtm_type == FR_ACT_GOTO) {
- fprintf(fp, "goto ");
+ 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) {
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");
- if (r->rtm_flags & FIB_RULE_UNRESOLVED)
- fprintf(fp, " [unresolved]");
- } else if (r->rtm_type == FR_ACT_NOP)
- fprintf(fp, "nop");
- else if (r->rtm_type != RTN_UNICAST)
- fprintf(fp, "%s",
- rtnl_rtntype_n2a(r->rtm_type,
- b1, sizeof(b1)));
-
- fprintf(fp, "\n");
+ print_string(PRINT_ANY, "goto", "goto %s", "none");
+
+ if (frh->flags & FIB_RULE_UNRESOLVED)
+ 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) {
+ print_string(PRINT_ANY, "protocol", " proto %s ",
+ rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+ }
+ }
+ print_string(PRINT_FP, NULL, "\n", "");
+ close_json_object();
fflush(fp);
return 0;
}
void *arg)
{
struct rtnl_handle rth2;
- struct rtmsg *r = NLMSG_DATA(n);
+ struct fib_rule_hdr *frh = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[FRA_MAX+1];
- len -= NLMSG_LENGTH(sizeof(*r));
+ len -= NLMSG_LENGTH(sizeof(*frh));
if (len < 0)
return -1;
- parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+ parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
+
+ if (tb[FRA_PROTOCOL]) {
+ __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+ if ((filter.protocol ^ protocol) & filter.protocolmask)
+ return 0;
+ }
if (tb[FRA_PRIORITY]) {
n->nlmsg_type = RTM_DELRULE;
if (af == AF_UNSPEC)
af = AF_INET;
- if (action != IPRULE_LIST && argc > 0) {
- fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
- action == IPRULE_SAVE ? "save" : "flush");
+ if (action == IPRULE_SAVE && argc > 0) {
+ fprintf(stderr, "\"ip rule save\" does not take any arguments.\n");
return -1;
}
NEXT_ARG();
if (get_prefix(&filter.src, *argv, af))
invarg("from value is invalid\n", *argv);
- } else {
+ } else if (matches(*argv, "protocol") == 0) {
+ __u32 prot;
+ NEXT_ARG();
+ filter.protocolmask = -1;
+ if (rtnl_rtprot_a2n(&prot, *argv)) {
+ if (strcmp(*argv, "all") != 0)
+ invarg("invalid \"protocol\"\n", *argv);
+ prot = 0;
+ filter.protocolmask = 0;
+ }
+ filter.protocol = prot;
+ } else{
if (matches(*argv, "dst") == 0 ||
matches(*argv, "to") == 0) {
NEXT_ARG();
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;
}
__u32 tid = 0;
struct {
struct nlmsghdr n;
- struct rtmsg r;
+ struct fib_rule_hdr frh;
char buf[1024];
} req = {
.n.nlmsg_type = cmd,
- .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
.n.nlmsg_flags = NLM_F_REQUEST,
- .r.rtm_family = preferred_family,
- .r.rtm_protocol = RTPROT_BOOT,
- .r.rtm_scope = RT_SCOPE_UNIVERSE,
- .r.rtm_type = RTN_UNSPEC,
+ .frh.family = preferred_family,
+ .frh.action = FR_ACT_UNSPEC,
};
if (cmd == RTM_NEWRULE) {
req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
- req.r.rtm_type = RTN_UNICAST;
+ req.frh.action = FR_ACT_TO_TBL;
}
if (cmd == RTM_DELRULE && argc == 0) {
while (argc > 0) {
if (strcmp(*argv, "not") == 0) {
- req.r.rtm_flags |= FIB_RULE_INVERT;
+ req.frh.flags |= FIB_RULE_INVERT;
} else if (strcmp(*argv, "from") == 0) {
inet_prefix dst;
NEXT_ARG();
- get_prefix(&dst, *argv, req.r.rtm_family);
- req.r.rtm_src_len = dst.bitlen;
+ get_prefix(&dst, *argv, req.frh.family);
+ req.frh.src_len = dst.bitlen;
addattr_l(&req.n, sizeof(req), FRA_SRC,
&dst.data, dst.bytelen);
} else if (strcmp(*argv, "to") == 0) {
inet_prefix dst;
NEXT_ARG();
- get_prefix(&dst, *argv, req.r.rtm_family);
- req.r.rtm_dst_len = dst.bitlen;
+ get_prefix(&dst, *argv, req.frh.family);
+ req.frh.dst_len = dst.bitlen;
addattr_l(&req.n, sizeof(req), FRA_DST,
&dst.data, dst.bytelen);
} else if (matches(*argv, "preference") == 0 ||
NEXT_ARG();
if (rtnl_dsfield_a2n(&tos, *argv))
invarg("TOS value is invalid\n", *argv);
- req.r.rtm_tos = tos;
+ req.frh.tos = tos;
} else if (strcmp(*argv, "fwmark") == 0) {
char *slash;
__u32 fwmark, fwmask;
if (get_rt_realms_or_raw(&realm, *argv))
invarg("invalid realms\n", *argv);
addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+ } else if (matches(*argv, "protocol") == 0) {
+ __u32 proto;
+
+ NEXT_ARG();
+ if (rtnl_rtprot_a2n(&proto, *argv))
+ invarg("\"protocol\" value is invalid\n", *argv);
+ addattr8(&req.n, sizeof(req), FRA_PROTOCOL, proto);
} else if (matches(*argv, "table") == 0 ||
strcmp(*argv, "lookup") == 0) {
NEXT_ARG();
if (rtnl_rttable_a2n(&tid, *argv))
invarg("invalid table ID\n", *argv);
if (tid < 256)
- req.r.rtm_table = tid;
+ req.frh.table = tid;
else {
- req.r.rtm_table = RT_TABLE_UNSPEC;
+ req.frh.table = RT_TABLE_UNSPEC;
addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
}
table_ok = 1;
fprintf(stderr, "Warning: route NAT is deprecated\n");
addattr32(&req.n, sizeof(req), RTA_GATEWAY,
get_addr32(*argv));
- req.r.rtm_type = RTN_NAT;
+ req.frh.action = RTN_NAT;
+ } else if (strcmp(*argv, "ipproto") == 0) {
+ int ipproto;
+
+ NEXT_ARG();
+ ipproto = inet_proto_a2n(*argv);
+ if (ipproto < 0)
+ invarg("Invalid \"ipproto\" value\n",
+ *argv);
+ addattr8(&req.n, sizeof(req), FRA_IP_PROTO, ipproto);
+ } else if (strcmp(*argv, "sport") == 0) {
+ struct fib_rule_port_range r;
+ int ret = 0;
+
+ NEXT_ARG();
+ ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+ if (ret == 1)
+ r.end = r.start;
+ else if (ret != 2)
+ invarg("invalid port range\n", *argv);
+ addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &r,
+ sizeof(r));
+ } else if (strcmp(*argv, "dport") == 0) {
+ struct fib_rule_port_range r;
+ int ret = 0;
+
+ NEXT_ARG();
+ ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+ if (ret == 1)
+ r.end = r.start;
+ else if (ret != 2)
+ invarg("invalid dport range\n", *argv);
+ addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &r,
+ sizeof(r));
} else {
int type;
type = FR_ACT_NOP;
else if (rtnl_rtntype_a2n(&type, *argv))
invarg("Failed to parse rule type", *argv);
- req.r.rtm_type = type;
+ req.frh.action = type;
table_ok = 1;
}
argc--;
return -EINVAL;
}
- if (req.r.rtm_family == AF_UNSPEC)
- req.r.rtm_family = AF_INET;
+ if (req.frh.family == AF_UNSPEC)
+ req.frh.family = AF_INET;
if (!table_ok && cmd == RTM_NEWRULE)
- req.r.rtm_table = RT_TABLE_MAIN;
+ req.frh.table = RT_TABLE_MAIN;
if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -2;
#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): "
__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)
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;
}
} 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;
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;
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
+#include "json_print.h"
extern struct rtnl_handle rth;
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;
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;
}
if (medium) {
p->link = ll_name_to_index(medium);
- if (p->link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", medium);
- return -1;
- }
+ if (!p->link)
+ return nodev(medium);
}
if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
return tnl_del_ioctl(tnl_defname(&p) ? : p.name, p.name, &p);
}
-static void print_tunnel(struct ip_tunnel_parm *p)
+static void print_tunnel(const void *t)
{
+ const struct ip_tunnel_parm *p = t;
struct ip_tunnel_6rd ip6rd = {};
char s1[1024];
char s2[1024];
printf("%s Checksum output packets.", _SL_);
}
-static int do_tunnels_list(struct ip_tunnel_parm *p)
-{
- char buf[512];
- int err = -1;
- FILE *fp = fopen("/proc/net/dev", "r");
- if (fp == NULL) {
- perror("fopen");
- return -1;
- }
+static void ip_tunnel_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+ struct ip_tunnel_parm *p2 = info->p2;
- /* skip header lines */
- if (!fgets(buf, sizeof(buf), fp) ||
- !fgets(buf, sizeof(buf), fp)) {
- fprintf(stderr, "/proc/net/dev read error\n");
- goto end;
- }
+ memset(p2, 0, sizeof(*p2));
+}
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- char name[IFNAMSIZ];
- int index, type;
- struct ip_tunnel_parm p1 = {};
- char *ptr;
-
- buf[sizeof(buf) - 1] = 0;
- ptr = strchr(buf, ':');
- if (ptr == NULL ||
- (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
- fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
- goto end;
- }
- if (p->name[0] && strcmp(p->name, name))
- continue;
- index = ll_name_to_index(name);
- if (index == 0)
- continue;
- type = ll_index_to_type(index);
- if (type == -1) {
- fprintf(stderr, "Failed to get type of \"%s\"\n", name);
- continue;
- }
- if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
- continue;
- if (tnl_get_ioctl(name, &p1))
- continue;
- if ((p->link && p1.link != p->link) ||
- (p->name[0] && strcmp(p1.name, p->name)) ||
- (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
- (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
- (p->i_key && p1.i_key != p->i_key))
- continue;
- print_tunnel(&p1);
- if (show_stats)
- tnl_print_stats(ptr);
- printf("\n");
- }
- err = 0;
- end:
- fclose(fp);
- return err;
+static bool ip_tunnel_parm_match(const struct tnl_print_nlmsg_info *info)
+{
+ const struct ip_tunnel_parm *p1 = info->p1;
+ const struct ip_tunnel_parm *p2 = info->p2;
+
+ return ((!p1->link || p1->link == p2->link) &&
+ (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+ (!p1->iph.daddr || p1->iph.daddr == p2->iph.daddr) &&
+ (!p1->iph.saddr || p1->iph.saddr == p2->iph.saddr) &&
+ (!p1->i_key || p1->i_key == p2->i_key));
}
static int do_show(int argc, char **argv)
{
- struct ip_tunnel_parm p;
+ struct ip_tunnel_parm p, p1;
const char *basedev;
- ll_init_map(&rth);
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
return -1;
basedev = tnl_defname(&p);
- if (!basedev)
- return do_tunnels_list(&p);
+ if (!basedev) {
+ struct tnl_print_nlmsg_info info = {
+ .p1 = &p,
+ .p2 = &p1,
+ .init = ip_tunnel_parm_initialize,
+ .match = ip_tunnel_parm_match,
+ .print = print_tunnel,
+ };
+
+ return do_tunnels_list(&info);
+ }
if (tnl_get_ioctl(p.name[0] ? p.name : basedev, &p))
return -1;
print_tunnel(&p);
- printf("\n");
+ fputc('\n', stdout);
return 0;
}
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
+#include <linux/if_arp.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include "utils.h"
#include "ip_common.h"
+static const char drv_name[] = "tun";
+
#define TUNDEV "/dev/net/tun"
static void usage(void) __attribute__((noreturn));
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");
+
+ if (flags & IFF_PERSIST)
+ print_string(PRINT_ANY, NULL, " %s", "persist");
- flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR);
+ 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)
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";
!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);
}
next:
++fd_path;
}
+ close_json_array(PRINT_JSON, NULL);
globfree(&globbuf);
}
+static int tuntap_filter_req(struct nlmsghdr *nlh, int reqlen)
+{
+ struct rtattr *linkinfo;
+ int err;
-static int do_show(int argc, char **argv)
+ linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
+
+ err = addattr_l(nlh, reqlen, IFLA_INFO_KIND,
+ drv_name, sizeof(drv_name) - 1);
+ if (err)
+ return err;
+
+ addattr_nest_end(nlh, linkinfo);
+
+ return 0;
+}
+
+static int print_tuntap(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
{
- DIR *dir;
- struct dirent *d;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX+1];
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ const char *name, *kind;
long flags, owner = -1, group = -1;
- dir = opendir("/sys/class/net");
- if (!dir) {
- perror("opendir");
+ if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+ return 0;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
return -1;
+
+ switch (ifi->ifi_type) {
+ case ARPHRD_NONE:
+ case ARPHRD_ETHER:
+ break;
+ default:
+ return 0;
}
- while ((d = readdir(dir))) {
- if (d->d_name[0] == '.' &&
- (d->d_name[1] == 0 || d->d_name[1] == '.'))
- continue;
-
- if (read_prop(d->d_name, "tun_flags", &flags))
- continue;
-
- read_prop(d->d_name, "owner", &owner);
- read_prop(d->d_name, "group", &group);
-
- printf("%s:", d->d_name);
- print_flags(flags);
- if (owner != -1)
- printf(" user %ld", owner);
- if (group != -1)
- printf(" group %ld", group);
- printf("\n");
- if (show_details) {
- printf("\tAttached to processes:");
- show_processes(d->d_name);
- printf("\n");
- }
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+ if (!tb[IFLA_IFNAME])
+ return 0;
+
+ if (!tb[IFLA_LINKINFO])
+ return 0;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!linkinfo[IFLA_INFO_KIND])
+ return 0;
+
+ kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
+ if (strcmp(kind, drv_name))
+ return 0;
+
+ name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+ if (read_prop(name, "tun_flags", &flags))
+ return 0;
+ if (read_prop(name, "owner", &owner))
+ return 0;
+ if (read_prop(name, "group", &group))
+ return 0;
+
+ open_json_object(NULL);
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "ifname", "%s:", name);
+ print_flags(flags);
+ if (owner != -1)
+ print_uint(PRINT_ANY, "user",
+ " user %ld", owner);
+ if (group != -1)
+ print_uint(PRINT_ANY, "group",
+ " group %ld", group);
+
+ if (show_details) {
+ print_string(PRINT_FP, NULL,
+ "%s\tAttached to processes:", _SL_);
+ show_processes(name);
}
- closedir(dir);
+ close_json_object();
+ print_string(PRINT_FP, NULL, "%s", "\n");
+
+ return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+ if (rtnl_wilddump_req_filter_fn(&rth, AF_UNSPEC, RTM_GETLINK,
+ tuntap_filter_req) < 0) {
+ perror("Cannot send dump request\n");
+ 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;
}
*argv);
exit(-1);
}
+
+static void print_owner(FILE *f, uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+
+ if (pw)
+ print_string(PRINT_ANY, "user", "user %s ", pw->pw_name);
+ else
+ print_uint(PRINT_ANY, "user", "user %u ", uid);
+}
+
+static void print_group(FILE *f, gid_t gid)
+{
+ struct group *group = getgrgid(gid);
+
+ if (group)
+ print_string(PRINT_ANY, "group", "group %s ", group->gr_name);
+ else
+ print_uint(PRINT_ANY, "group", "group %u ", gid);
+}
+
+static void print_mq(FILE *f, struct rtattr *tb[])
+{
+ if (!tb[IFLA_TUN_MULTI_QUEUE] ||
+ !rta_getattr_u8(tb[IFLA_TUN_MULTI_QUEUE])) {
+ if (is_json_context())
+ print_bool(PRINT_JSON, "multi_queue", NULL, false);
+ return;
+ }
+
+ print_bool(PRINT_ANY, "multi_queue", "multi_queue ", true);
+
+ if (tb[IFLA_TUN_NUM_QUEUES]) {
+ print_uint(PRINT_ANY, "numqueues", "numqueues %u ",
+ rta_getattr_u32(tb[IFLA_TUN_NUM_QUEUES]));
+ }
+
+ if (tb[IFLA_TUN_NUM_DISABLED_QUEUES]) {
+ print_uint(PRINT_ANY, "numdisabled", "numdisabled %u ",
+ rta_getattr_u32(tb[IFLA_TUN_NUM_DISABLED_QUEUES]));
+ }
+}
+
+static void print_onoff(FILE *f, const char *flag, __u8 val)
+{
+ if (is_json_context())
+ print_bool(PRINT_JSON, flag, NULL, !!val);
+ else
+ fprintf(f, "%s %s ", flag, val ? "on" : "off");
+}
+
+static void print_type(FILE *f, __u8 type)
+{
+ SPRINT_BUF(buf);
+ const char *str = buf;
+
+ if (type == IFF_TUN)
+ str = "tun";
+ else if (type == IFF_TAP)
+ str = "tap";
+ else
+ snprintf(buf, sizeof(buf), "UNKNOWN:%hhu", type);
+
+ print_string(PRINT_ANY, "type", "type %s ", str);
+}
+
+static void tun_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ if (!tb)
+ return;
+
+ if (tb[IFLA_TUN_TYPE])
+ print_type(f, rta_getattr_u8(tb[IFLA_TUN_TYPE]));
+
+ if (tb[IFLA_TUN_PI])
+ print_onoff(f, "pi", rta_getattr_u8(tb[IFLA_TUN_PI]));
+
+ if (tb[IFLA_TUN_VNET_HDR]) {
+ print_onoff(f, "vnet_hdr",
+ rta_getattr_u8(tb[IFLA_TUN_VNET_HDR]));
+ }
+
+ print_mq(f, tb);
+
+ if (tb[IFLA_TUN_PERSIST])
+ print_onoff(f, "persist", rta_getattr_u8(tb[IFLA_TUN_PERSIST]));
+
+ if (tb[IFLA_TUN_OWNER])
+ print_owner(f, rta_getattr_u32(tb[IFLA_TUN_OWNER]));
+
+ if (tb[IFLA_TUN_GROUP])
+ print_group(f, rta_getattr_u32(tb[IFLA_TUN_GROUP]));
+}
+
+struct link_util tun_link_util = {
+ .id = "tun",
+ .maxattr = IFLA_TUN_MAX,
+ .print_opt = tun_print_opt,
+};
#include "ip_common.h"
#include "tunnel.h"
-static void print_usage(FILE *f)
+static void gre_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
{
fprintf(f,
- "Usage: ... { gre | gretap | erspan } [ remote ADDR ]\n"
- " [ local ADDR ]\n"
- " [ [i|o]seq ]\n"
- " [ [i|o]key KEY ]\n"
- " [ [i|o]csum ]\n"
- " [ ttl TTL ]\n"
- " [ tos TOS ]\n"
- " [ [no]pmtudisc ]\n"
- " [ [no]ignore-df ]\n"
- " [ dev PHYS_DEV ]\n"
- " [ noencap ]\n"
- " [ encap { fou | gue | none } ]\n"
- " [ encap-sport PORT ]\n"
- " [ encap-dport PORT ]\n"
- " [ [no]encap-csum ]\n"
- " [ [no]encap-csum6 ]\n"
- " [ [no]encap-remcsum ]\n"
- " [ external ]\n"
- " [ fwmark MARK ]\n"
- " [ erspan_ver version ]\n"
- " [ erspan IDX ]\n"
- " [ erspan_dir { ingress | egress } ]\n"
- " [ erspan_hwid hwid ]\n"
- " [ external ]\n"
+ "Usage: ... %-9s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
+ " [ local ADDR ]\n"
+ " [ [i|o]seq ]\n"
+ " [ [i|o]key KEY ]\n"
+ " [ [i|o]csum ]\n"
+ " [ ttl TTL ]\n"
+ " [ tos TOS ]\n"
+ " [ [no]pmtudisc ]\n"
+ " [ [no]ignore-df ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
+ " [ external ]\n"
+ " [ noencap ]\n"
+ " [ encap { fou | gue | none } ]\n"
+ " [ encap-sport PORT ]\n"
+ " [ encap-dport PORT ]\n"
+ " [ [no]encap-csum ]\n"
+ " [ [no]encap-csum6 ]\n"
+ " [ [no]encap-remcsum ]\n"
+ " [ erspan_ver version ]\n"
+ " [ erspan IDX ]\n"
+ " [ erspan_dir { ingress | egress } ]\n"
+ " [ erspan_hwid hwid ]\n"
"\n"
+ );
+ fprintf(f,
"Where: ADDR := { IP_ADDRESS | any }\n"
" TOS := { NUMBER | inherit }\n"
" TTL := { 1..255 | inherit }\n"
);
}
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
- print_usage(stderr);
- exit(-1);
-}
-
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *tb[IFLA_MAX + 1];
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ int len;
__u16 iflags = 0;
__u16 oflags = 0;
__be32 ikey = 0;
__be32 okey = 0;
- unsigned int saddr = 0;
- unsigned int daddr = 0;
- unsigned int link = 0;
+ inet_prefix saddr, daddr;
__u8 pmtudisc = 1;
- __u8 ttl = 0;
+ __u8 ignore_df = 0;
__u8 tos = 0;
- int len;
+ __u8 ttl = 0;
+ __u32 link = 0;
__u16 encaptype = 0;
__u16 encapflags = 0;
__u16 encapsport = 0;
__u16 encapdport = 0;
__u8 metadata = 0;
- __u8 ignore_df = 0;
__u32 fwmark = 0;
__u32 erspan_idx = 0;
__u8 erspan_ver = 0;
__u8 erspan_dir = 0;
__u16 erspan_hwid = 0;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
linkinfo[IFLA_INFO_DATA]);
+ rta = greinfo[IFLA_GRE_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET))
+ goto get_failed;
+
+ rta = greinfo[IFLA_GRE_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET))
+ goto get_failed;
+
if (greinfo[IFLA_GRE_IKEY])
ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
if (greinfo[IFLA_GRE_OFLAGS])
oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
- if (greinfo[IFLA_GRE_LOCAL])
- saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
-
- if (greinfo[IFLA_GRE_REMOTE])
- daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
-
if (greinfo[IFLA_GRE_PMTUDISC])
pmtudisc = rta_getattr_u8(
greinfo[IFLA_GRE_PMTUDISC]);
- if (greinfo[IFLA_GRE_TTL])
- ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+ if (greinfo[IFLA_GRE_IGNORE_DF])
+ ignore_df =
+ !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
if (greinfo[IFLA_GRE_TOS])
tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
+ if (greinfo[IFLA_GRE_TTL])
+ ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+
if (greinfo[IFLA_GRE_LINK])
link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
if (greinfo[IFLA_GRE_ENCAP_TYPE])
encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
+
if (greinfo[IFLA_GRE_ENCAP_FLAGS])
encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
+
if (greinfo[IFLA_GRE_ENCAP_SPORT])
encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
+
if (greinfo[IFLA_GRE_ENCAP_DPORT])
encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
if (greinfo[IFLA_GRE_COLLECT_METADATA])
metadata = 1;
- if (greinfo[IFLA_GRE_IGNORE_DF])
- ignore_df =
- !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
-
if (greinfo[IFLA_GRE_FWMARK])
fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
pmtudisc = 1;
} else if (!matches(*argv, "remote")) {
NEXT_ARG();
- daddr = get_addr32(*argv);
+ get_addr(&daddr, *argv, AF_INET);
} else if (!matches(*argv, "local")) {
NEXT_ARG();
- saddr = get_addr32(*argv);
+ get_addr(&saddr, *argv, AF_INET);
} else if (!matches(*argv, "dev")) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- exit(-1);
- }
+ if (!link)
+ exit(nodev(*argv));
} else if (!matches(*argv, "ttl") ||
!matches(*argv, "hoplimit") ||
!matches(*argv, "hlim")) {
NEXT_ARG();
if (get_u16(&erspan_hwid, *argv, 0))
invarg("invalid erspan hwid\n", *argv);
- } else
- usage();
+ } else {
+ gre_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--; argv++;
}
- if (!ikey && IN_MULTICAST(ntohl(daddr))) {
- ikey = daddr;
- iflags |= GRE_KEY;
- }
- if (!okey && IN_MULTICAST(ntohl(daddr))) {
- okey = daddr;
- oflags |= GRE_KEY;
+ if (is_addrtype_inet_multi(&daddr)) {
+ if (!ikey) {
+ ikey = daddr.data[0];
+ iflags |= GRE_KEY;
+ }
+ if (!okey) {
+ okey = daddr.data[0];
+ oflags |= GRE_KEY;
+ }
+ if (!is_addrtype_inet_not_unspec(&saddr)) {
+ fprintf(stderr,
+ "A broadcast tunnel requires a source address.\n");
+ return -1;
+ }
}
- if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
- fprintf(stderr, "A broadcast tunnel requires a source address.\n");
- return -1;
+
+ if (metadata) {
+ addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
+ return 0;
}
- if (!metadata) {
- addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
- addattr32(n, 1024, IFLA_GRE_OKEY, okey);
- addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
- addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
- addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
- addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
- addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
- if (ignore_df)
- addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
- if (link)
- addattr32(n, 1024, IFLA_GRE_LINK, link);
- addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
- addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
- addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
- if (erspan_ver) {
- addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
- if (erspan_ver == 1 && erspan_idx != 0) {
- addattr32(n, 1024,
- IFLA_GRE_ERSPAN_INDEX, erspan_idx);
- } else if (erspan_ver == 2) {
- addattr8(n, 1024,
- IFLA_GRE_ERSPAN_DIR, erspan_dir);
- addattr16(n, 1024,
- IFLA_GRE_ERSPAN_HWID, erspan_hwid);
- }
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ if (is_addrtype_inet(&saddr))
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen);
+ if (is_addrtype_inet(&daddr))
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen);
+ addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
+ if (ignore_df)
+ addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
+ addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
+ addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
+ if (erspan_ver) {
+ addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+ if (erspan_ver == 1 && erspan_idx != 0) {
+ addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+ } else if (erspan_ver == 2) {
+ addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+ addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
}
- addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
- addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
- addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
- addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
- } else {
- addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
}
+ addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+ addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
return 0;
}
static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
char s2[64];
- unsigned int iflags = 0;
- unsigned int oflags = 0;
+ __u16 iflags = 0;
+ __u16 oflags = 0;
__u8 ttl = 0;
__u8 tos = 0;
tnl_print_endpoint("local", tb[IFLA_GRE_LOCAL], AF_INET);
if (tb[IFLA_GRE_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
if (tb[IFLA_GRE_ERSPAN_VER]) {
__u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
- print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+ print_uint(PRINT_ANY,
+ "erspan_ver", "erspan_ver %u ", erspan_ver);
}
if (tb[IFLA_GRE_ERSPAN_DIR]) {
if (tb[IFLA_GRE_ERSPAN_HWID]) {
__u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
- print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
+ print_0xhex(PRINT_ANY,
+ "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
}
tnl_print_encap(tb,
IFLA_GRE_ENCAP_DPORT);
}
-static void gre_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f);
-}
-
struct link_util gre_link_util = {
.id = "gre",
.maxattr = IFLA_GRE_MAX,
#define DEFAULT_TNL_HOP_LIMIT (64)
-static void print_usage(FILE *f)
+static void gre_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
{
fprintf(f,
- "Usage: ... { ip6gre | ip6gretap | ip6erspan} [ remote ADDR ]\n"
- " [ local ADDR ]\n"
- " [ [i|o]seq ]\n"
- " [ [i|o]key KEY ]\n"
- " [ [i|o]csum ]\n"
- " [ hoplimit TTL ]\n"
- " [ encaplimit ELIM ]\n"
- " [ tclass TCLASS ]\n"
- " [ flowlabel FLOWLABEL ]\n"
- " [ dscp inherit ]\n"
- " [ fwmark MARK ]\n"
- " [ dev PHYS_DEV ]\n"
- " [ noencap ]\n"
- " [ encap { fou | gue | none } ]\n"
- " [ encap-sport PORT ]\n"
- " [ encap-dport PORT ]\n"
- " [ [no]encap-csum ]\n"
- " [ [no]encap-csum6 ]\n"
- " [ [no]encap-remcsum ]\n"
- " [ erspan_ver version ]\n"
- " [ erspan IDX ]\n"
- " [ erspan_dir { ingress | egress } ]\n"
- " [ erspan_hwid hwid ]\n"
- " [ external ]\n"
+ "Usage: ... %-9s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
+ " [ local ADDR ]\n"
+ " [ [i|o]seq ]\n"
+ " [ [i|o]key KEY ]\n"
+ " [ [i|o]csum ]\n"
+ " [ hoplimit TTL ]\n"
+ " [ encaplimit ELIM ]\n"
+ " [ tclass TCLASS ]\n"
+ " [ flowlabel FLOWLABEL ]\n"
+ " [ dscp inherit ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
+ " [ [no]allow-localremote ]\n"
+ " [ external ]\n"
+ " [ noencap ]\n"
+ " [ encap { fou | gue | none } ]\n"
+ " [ encap-sport PORT ]\n"
+ " [ encap-dport PORT ]\n"
+ " [ [no]encap-csum ]\n"
+ " [ [no]encap-csum6 ]\n"
+ " [ [no]encap-remcsum ]\n"
+ " [ erspan_ver version ]\n"
+ " [ erspan IDX ]\n"
+ " [ erspan_dir { ingress | egress } ]\n"
+ " [ erspan_hwid hwid ]\n"
"\n"
+ );
+ fprintf(f,
"Where: ADDR := IPV6_ADDRESS\n"
" TTL := { 0..255 } (default=%d)\n"
" KEY := { DOTTED_QUAD | NUMBER }\n"
);
}
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
- print_usage(stderr);
- exit(-1);
-}
-
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *tb[IFLA_MAX + 1];
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ int len;
__u16 iflags = 0;
__u16 oflags = 0;
__be32 ikey = 0;
__be32 okey = 0;
- struct in6_addr raddr = IN6ADDR_ANY_INIT;
- struct in6_addr laddr = IN6ADDR_ANY_INIT;
- unsigned int link = 0;
- unsigned int flowinfo = 0;
- unsigned int flags = 0;
+ inet_prefix saddr, daddr;
__u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
__u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+ __u32 flowinfo = 0;
+ __u32 flags = 0;
+ __u32 link = 0;
__u16 encaptype = 0;
__u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
__u16 encapsport = 0;
__u16 encapdport = 0;
__u8 metadata = 0;
- int len;
__u32 fwmark = 0;
__u32 erspan_idx = 0;
__u8 erspan_ver = 0;
__u8 erspan_dir = 0;
__u16 erspan_hwid = 0;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
linkinfo[IFLA_INFO_DATA]);
+ rta = greinfo[IFLA_GRE_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+ goto get_failed;
+
+ rta = greinfo[IFLA_GRE_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+ goto get_failed;
+
if (greinfo[IFLA_GRE_IKEY])
ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
if (greinfo[IFLA_GRE_OFLAGS])
oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
- if (greinfo[IFLA_GRE_LOCAL])
- memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));
-
- if (greinfo[IFLA_GRE_REMOTE])
- memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));
-
if (greinfo[IFLA_GRE_TTL])
hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
if (greinfo[IFLA_GRE_ENCAP_SPORT])
encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
- if (greinfo[IFLA_GRE_COLLECT_METADATA])
- metadata = 1;
-
if (greinfo[IFLA_GRE_ENCAP_DPORT])
encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
+ if (greinfo[IFLA_GRE_COLLECT_METADATA])
+ metadata = 1;
+
if (greinfo[IFLA_GRE_FWMARK])
fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
} else if (!matches(*argv, "ocsum")) {
oflags |= GRE_CSUM;
} else if (!matches(*argv, "remote")) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&raddr, &addr.data, sizeof(raddr));
+ get_addr(&daddr, *argv, AF_INET6);
} else if (!matches(*argv, "local")) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&laddr, &addr.data, sizeof(laddr));
+ get_addr(&saddr, *argv, AF_INET6);
} else if (!matches(*argv, "dev")) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- exit(-1);
- }
+ if (!link)
+ exit(nodev(*argv));
} else if (!matches(*argv, "ttl") ||
!matches(*argv, "hoplimit") ||
!matches(*argv, "hlim")) {
invarg("invalid fwmark\n", *argv);
flags &= ~IP6_TNL_F_USE_ORIG_FWMARK;
}
+ } else if (strcmp(*argv, "allow-localremote") == 0) {
+ flags |= IP6_TNL_F_ALLOW_LOCAL_REMOTE;
+ } else if (strcmp(*argv, "noallow-localremote") == 0) {
+ flags &= ~IP6_TNL_F_ALLOW_LOCAL_REMOTE;
} else if (strcmp(*argv, "encaplimit") == 0) {
NEXT_ARG();
if (strcmp(*argv, "none") == 0) {
NEXT_ARG();
if (get_u16(&erspan_hwid, *argv, 0))
invarg("invalid erspan hwid\n", *argv);
- } else
- usage();
+ } else {
+ gre_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--; argv++;
}
- if (!metadata) {
- addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
- addattr32(n, 1024, IFLA_GRE_OKEY, okey);
- addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
- addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
- addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
- addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
- if (link)
- addattr32(n, 1024, IFLA_GRE_LINK, link);
- addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
- addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
- addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
- addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
- addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
- if (erspan_ver) {
- addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
- if (erspan_ver == 1 && erspan_idx != 0) {
- addattr32(n, 1024,
- IFLA_GRE_ERSPAN_INDEX, erspan_idx);
- } else if (erspan_ver == 2) {
- addattr8(n, 1024,
- IFLA_GRE_ERSPAN_DIR, erspan_dir);
- addattr16(n, 1024,
- IFLA_GRE_ERSPAN_HWID, erspan_hwid);
- }
- }
- addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
- addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
- addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
- addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
- } else {
+ if (metadata) {
addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
+ return 0;
+ }
+
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ if (is_addrtype_inet(&saddr))
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen);
+ if (is_addrtype_inet(&daddr))
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen);
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
+ addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
+ addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
+ if (erspan_ver) {
+ addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+ if (erspan_ver == 1 && erspan_idx != 0) {
+ addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+ } else if (erspan_ver == 2) {
+ addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+ addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
+ }
}
+ addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+ addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
return 0;
}
static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
char s2[64];
- unsigned int iflags = 0;
- unsigned int oflags = 0;
- unsigned int flags = 0;
+ __u16 iflags = 0;
+ __u16 oflags = 0;
+ __u32 flags = 0;
__u32 flowinfo = 0;
__u8 ttl = 0;
tnl_print_endpoint("local", tb[IFLA_GRE_LOCAL], AF_INET6);
if (tb[IFLA_GRE_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
if (oflags & GRE_CSUM)
print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
+ if (flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE)
+ print_bool(PRINT_ANY,
+ "ip6_tnl_f_allow_local_remote",
+ "allow-localremote ",
+ true);
+
if (flags & IP6_TNL_F_USE_ORIG_FWMARK) {
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_fwmark",
if (tb[IFLA_GRE_ERSPAN_INDEX]) {
__u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
+
print_uint(PRINT_ANY,
"erspan_index", "erspan_index %u ", erspan_idx);
}
if (tb[IFLA_GRE_ERSPAN_VER]) {
__u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
- print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+ print_uint(PRINT_ANY,
+ "erspan_ver", "erspan_ver %u ", erspan_ver);
}
if (tb[IFLA_GRE_ERSPAN_DIR]) {
if (tb[IFLA_GRE_ERSPAN_HWID]) {
__u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
- print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
+ print_0xhex(PRINT_ANY,
+ "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
}
tnl_print_encap(tb,
IFLA_GRE_ENCAP_DPORT);
}
-static void gre_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f);
-}
-
struct link_util ip6gre_link_util = {
.id = "ip6gre",
.maxattr = IFLA_GRE_MAX,
#define DEFAULT_TNL_HOP_LIMIT (64)
-static void print_usage(FILE *f)
+static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
{
+ const char *mode;
+
+ fprintf(f,
+ "Usage: ... %-6s [ remote ADDR ]\n",
+ lu->id
+ );
fprintf(f,
- "Usage: ... ip6tnl [ mode { ip6ip6 | ipip6 | any } ]\n"
- " [ remote ADDR ]\n"
" [ local ADDR ]\n"
- " [ dev PHYS_DEV ]\n"
" [ encaplimit ELIM ]\n"
" [ hoplimit HLIM ]\n"
" [ tclass TCLASS ]\n"
" [ flowlabel FLOWLABEL ]\n"
" [ dscp inherit ]\n"
- " [ fwmark MARK ]\n"
" [ [no]allow-localremote ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
+ " [ external ]\n"
" [ noencap ]\n"
" [ encap { fou | gue | none } ]\n"
" [ encap-sport PORT ]\n"
" [ [no]encap-csum ]\n"
" [ [no]encap-csum6 ]\n"
" [ [no]encap-remcsum ]\n"
- " [ external ]\n"
- "\n"
+ );
+ mode = "{ ip6ip6 | ipip6 | any }";
+ fprintf(f,
+ " [ mode %s ]\n"
+ "\n",
+ mode
+ );
+ fprintf(f,
"Where: ADDR := IPV6_ADDRESS\n"
" ELIM := { none | 0..255 }(default=%d)\n"
" HLIM := 0..255 (default=%d)\n"
);
}
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
- print_usage(stderr);
- exit(-1);
-}
-
static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
int len;
- struct in6_addr laddr = IN6ADDR_ANY_INIT;
- struct in6_addr raddr = IN6ADDR_ANY_INIT;
+ inet_prefix saddr, daddr;
__u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
__u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
__u32 flowinfo = 0;
__u32 flags = 0;
- __u32 link = 0;
__u8 proto = 0;
+ __u32 link = 0;
__u16 encaptype = 0;
__u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
__u16 encapsport = 0;
__u8 metadata = 0;
__u32 fwmark = 0;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
linkinfo[IFLA_INFO_DATA]);
- if (iptuninfo[IFLA_IPTUN_LOCAL])
- memcpy(&laddr, RTA_DATA(iptuninfo[IFLA_IPTUN_LOCAL]),
- sizeof(laddr));
+ rta = iptuninfo[IFLA_IPTUN_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+ goto get_failed;
- if (iptuninfo[IFLA_IPTUN_REMOTE])
- memcpy(&raddr, RTA_DATA(iptuninfo[IFLA_IPTUN_REMOTE]),
- sizeof(raddr));
+ rta = iptuninfo[IFLA_IPTUN_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+ goto get_failed;
if (iptuninfo[IFLA_IPTUN_TTL])
hop_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
}
while (argc > 0) {
- if (matches(*argv, "mode") == 0) {
+ if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
if (strcmp(*argv, "ipv6/ipv6") == 0 ||
strcmp(*argv, "ip6ip6") == 0)
else
invarg("Cannot guess tunnel mode.", *argv);
} else if (strcmp(*argv, "remote") == 0) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&raddr, addr.data, sizeof(raddr));
+ get_addr(&daddr, *argv, AF_INET6);
} else if (strcmp(*argv, "local") == 0) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&laddr, addr.data, sizeof(laddr));
+ get_addr(&saddr, *argv, AF_INET6);
} else if (matches(*argv, "dev") == 0) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0)
- invarg("\"dev\" is invalid", *argv);
+ if (!link)
+ exit(nodev(*argv));
} else if (strcmp(*argv, "ttl") == 0 ||
strcmp(*argv, "hoplimit") == 0 ||
strcmp(*argv, "hlim") == 0) {
encap_limit = uval;
flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
}
- } else if (strcmp(*argv, "tclass") == 0 ||
+ } else if (strcmp(*argv, "tos") == 0 ||
+ strcmp(*argv, "tclass") == 0 ||
strcmp(*argv, "tc") == 0 ||
- strcmp(*argv, "tos") == 0 ||
matches(*argv, "dsfield") == 0) {
__u8 uval;
encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "external") == 0) {
metadata = 1;
- } else
- usage();
+ } else {
+ ip6tunnel_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--, argv++;
}
addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
return 0;
}
- addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr));
- addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr));
+
+ if (is_addrtype_inet(&saddr)) {
+ addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
+ saddr.data, saddr.bytelen);
+ }
+ if (is_addrtype_inet(&daddr)) {
+ addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
+ daddr.data, daddr.bytelen);
+ }
addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit);
addattr8(n, 1024, IFLA_IPTUN_ENCAP_LIMIT, encap_limit);
addattr32(n, 1024, IFLA_IPTUN_FLOWINFO, flowinfo);
static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
char s2[64];
- int flags = 0;
+ __u32 flags = 0;
__u32 flowinfo = 0;
__u8 ttl = 0;
tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET6);
if (tb[IFLA_IPTUN_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
IFLA_IPTUN_ENCAP_DPORT);
}
-static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f);
-}
-
struct link_util ip6tnl_link_util = {
.id = "ip6tnl",
.maxattr = IFLA_IPTUN_MAX,
#include "ip_common.h"
#include "tunnel.h"
-static void print_usage(FILE *f, int sit)
+static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
{
- const char *type = sit ? "sit " : "ipip";
+ const char *mode;
fprintf(f,
- "Usage: ... %s [ remote ADDR ]\n"
- " [ local ADDR ]\n"
- " [ ttl TTL ]\n"
- " [ tos TOS ]\n"
- " [ [no]pmtudisc ]\n"
- " [ dev PHYS_DEV ]\n"
- " [ 6rd-prefix ADDR ]\n"
- " [ 6rd-relay_prefix ADDR ]\n"
- " [ 6rd-reset ]\n"
- " [ noencap ]\n"
- " [ encap { fou | gue | none } ]\n"
- " [ encap-sport PORT ]\n"
- " [ encap-dport PORT ]\n"
- " [ [no]encap-csum ]\n"
- " [ [no]encap-csum6 ]\n"
- " [ [no]encap-remcsum ]\n",
- type
+ "Usage: ... %-6s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
+ " [ local ADDR ]\n"
+ " [ ttl TTL ]\n"
+ " [ tos TOS ]\n"
+ " [ [no]pmtudisc ]\n"
+ " [ 6rd-prefix ADDR ]\n"
+ " [ 6rd-relay_prefix ADDR ]\n"
+ " [ 6rd-reset ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
+ " [ external ]\n"
+ " [ noencap ]\n"
+ " [ encap { fou | gue | none } ]\n"
+ " [ encap-sport PORT ]\n"
+ " [ encap-dport PORT ]\n"
+ " [ [no]encap-csum ]\n"
+ " [ [no]encap-csum6 ]\n"
+ " [ [no]encap-remcsum ]\n"
);
- if (sit) {
- fprintf(f, " [ mode { ip6ip | ipip | mplsip | any } ]\n");
- fprintf(f, " [ isatap ]\n");
+ if (strcmp(lu->id, "sit") == 0) {
+ mode = "{ ip6ip | ipip | mplsip | any } ]\n"
+ " [ isatap";
} else {
- fprintf(f, " [ mode { ipip | mplsip | any } ]\n");
+ mode = "{ ipip | mplsip | any }";
}
- fprintf(f, " [ external ]\n");
- fprintf(f, " [ fwmark MARK ]\n");
- fprintf(f, "\n");
- fprintf(f, "Where: ADDR := { IP_ADDRESS | any }\n");
- fprintf(f, " TOS := { NUMBER | inherit }\n");
- fprintf(f, " TTL := { 1..255 | inherit }\n");
- fprintf(f, " MARK := { 0x0..0xffffffff }\n");
-}
-
-static void usage(int sit) __attribute__((noreturn));
-static void usage(int sit)
-{
- print_usage(stderr, sit);
- exit(-1);
+ fprintf(f,
+ " [ mode %s ]\n"
+ "\n",
+ mode
+ );
+ fprintf(f,
+ "Where: ADDR := { IP_ADDRESS | any }\n"
+ " TOS := { NUMBER | inherit }\n"
+ " TTL := { 1..255 | inherit }\n"
+ " MARK := { 0x0..0xffffffff }\n"
+ );
}
static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
int len;
- __u32 link = 0;
- __u32 laddr = 0;
- __u32 raddr = 0;
- __u8 ttl = 0;
- __u8 tos = 0;
+ inet_prefix saddr, daddr, ip6rdprefix, ip6rdrelayprefix;
__u8 pmtudisc = 1;
+ __u8 tos = 0;
__u16 iflags = 0;
+ __u8 ttl = 0;
__u8 proto = 0;
- struct in6_addr ip6rdprefix = {};
- __u16 ip6rdprefixlen = 0;
- __u32 ip6rdrelayprefix = 0;
- __u16 ip6rdrelayprefixlen = 0;
+ __u32 link = 0;
__u16 encaptype = 0;
__u16 encapflags = 0;
__u16 encapsport = 0;
__u8 metadata = 0;
__u32 fwmark = 0;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
+ inet_prefix_reset(&ip6rdprefix);
+ inet_prefix_reset(&ip6rdrelayprefix);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
linkinfo[IFLA_INFO_DATA]);
- if (iptuninfo[IFLA_IPTUN_LOCAL])
- laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]);
+ rta = iptuninfo[IFLA_IPTUN_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET))
+ goto get_failed;
+
+ rta = iptuninfo[IFLA_IPTUN_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET))
+ goto get_failed;
+
+ rta = iptuninfo[IFLA_IPTUN_6RD_PREFIX];
+ if (rta && get_addr_rta(&ip6rdprefix, rta, AF_INET6))
+ goto get_failed;
+
+ rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX];
+ if (rta && get_addr_rta(&ip6rdrelayprefix, rta, AF_INET))
+ goto get_failed;
+
+ rta = iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN];
+ ip6rdprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
- if (iptuninfo[IFLA_IPTUN_REMOTE])
- raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]);
+ rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN];
+ ip6rdrelayprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
if (iptuninfo[IFLA_IPTUN_TTL])
ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
- if (iptuninfo[IFLA_IPTUN_TOS])
- tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
-
if (iptuninfo[IFLA_IPTUN_PMTUDISC])
pmtudisc =
rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);
+ if (iptuninfo[IFLA_IPTUN_TOS])
+ tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
+
if (iptuninfo[IFLA_IPTUN_FLAGS])
iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);
encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]);
if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT])
encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]);
- if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
- memcpy(&ip6rdprefix,
- RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
- sizeof(laddr));
-
- if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN])
- ip6rdprefixlen =
- rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]);
-
- if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX])
- ip6rdrelayprefix =
- rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]);
-
- if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
- ip6rdrelayprefixlen =
- rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+
if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
metadata = 1;
}
while (argc > 0) {
- if (strcmp(*argv, "remote") == 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(lu->id, "sit") == 0 &&
+ (strcmp(*argv, "ipv6/ipv4") == 0 ||
+ strcmp(*argv, "ip6ip") == 0))
+ proto = IPPROTO_IPV6;
+ else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
+ strcmp(*argv, "ipip") == 0 ||
+ strcmp(*argv, "ip4ip4") == 0)
+ proto = IPPROTO_IPIP;
+ else if (strcmp(*argv, "mpls/ipv4") == 0 ||
+ strcmp(*argv, "mplsip") == 0)
+ proto = IPPROTO_MPLS;
+ else if (strcmp(*argv, "any/ipv4") == 0 ||
+ strcmp(*argv, "any") == 0)
+ proto = 0;
+ else
+ invarg("Cannot guess tunnel mode.", *argv);
+ } else if (strcmp(*argv, "remote") == 0) {
NEXT_ARG();
- raddr = get_addr32(*argv);
+ get_addr(&daddr, *argv, AF_INET);
} else if (strcmp(*argv, "local") == 0) {
NEXT_ARG();
- laddr = get_addr32(*argv);
+ get_addr(&saddr, *argv, AF_INET);
} else if (matches(*argv, "dev") == 0) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0)
- invarg("\"dev\" is invalid", *argv);
+ if (!link)
+ exit(nodev(*argv));
} else if (strcmp(*argv, "ttl") == 0 ||
strcmp(*argv, "hoplimit") == 0 ||
strcmp(*argv, "hlim") == 0) {
ttl = 0;
} else if (strcmp(*argv, "tos") == 0 ||
strcmp(*argv, "tclass") == 0 ||
+ strcmp(*argv, "tc") == 0 ||
matches(*argv, "dsfield") == 0) {
__u32 uval;
} else if (strcmp(lu->id, "sit") == 0 &&
strcmp(*argv, "isatap") == 0) {
iflags |= SIT_ISATAP;
- } else if (strcmp(*argv, "mode") == 0) {
- NEXT_ARG();
- if (strcmp(lu->id, "sit") == 0 &&
- (strcmp(*argv, "ipv6/ipv4") == 0 ||
- strcmp(*argv, "ip6ip") == 0))
- proto = IPPROTO_IPV6;
- else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
- strcmp(*argv, "ipip") == 0 ||
- strcmp(*argv, "ip4ip4") == 0)
- proto = IPPROTO_IPIP;
- else if (strcmp(*argv, "mpls/ipv4") == 0 ||
- strcmp(*argv, "mplsip") == 0)
- proto = IPPROTO_MPLS;
- else if (strcmp(*argv, "any/ipv4") == 0 ||
- strcmp(*argv, "any") == 0)
- proto = 0;
- else
- invarg("Cannot guess tunnel mode.", *argv);
} else if (strcmp(*argv, "noencap") == 0) {
encaptype = TUNNEL_ENCAP_NONE;
} else if (strcmp(*argv, "encap") == 0) {
} else if (strcmp(*argv, "external") == 0) {
metadata = 1;
} else if (strcmp(*argv, "6rd-prefix") == 0) {
- inet_prefix prefix;
-
NEXT_ARG();
- if (get_prefix(&prefix, *argv, AF_INET6))
+ if (get_prefix(&ip6rdprefix, *argv, AF_INET6))
invarg("invalid 6rd_prefix\n", *argv);
- memcpy(&ip6rdprefix, prefix.data, 16);
- ip6rdprefixlen = prefix.bitlen;
} else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
- inet_prefix prefix;
-
NEXT_ARG();
- if (get_prefix(&prefix, *argv, AF_INET))
+ if (get_prefix(&ip6rdrelayprefix, *argv, AF_INET))
invarg("invalid 6rd-relay_prefix\n", *argv);
- memcpy(&ip6rdrelayprefix, prefix.data, 4);
- ip6rdrelayprefixlen = prefix.bitlen;
} else if (strcmp(*argv, "6rd-reset") == 0) {
- inet_prefix prefix;
-
- get_prefix(&prefix, "2002::", AF_INET6);
- memcpy(&ip6rdprefix, prefix.data, 16);
- ip6rdprefixlen = 16;
- ip6rdrelayprefix = 0;
- ip6rdrelayprefixlen = 0;
+ get_prefix(&ip6rdprefix, "2002::/16", AF_INET6);
+ inet_prefix_reset(&ip6rdrelayprefix);
} else if (strcmp(*argv, "fwmark") == 0) {
NEXT_ARG();
if (get_u32(&fwmark, *argv, 0))
invarg("invalid fwmark\n", *argv);
- } else
- usage(strcmp(lu->id, "sit") == 0);
+ } else {
+ iptunnel_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--, argv++;
}
return 0;
}
- addattr32(n, 1024, IFLA_IPTUN_LINK, link);
- addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
- addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
- addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
- addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
+ if (is_addrtype_inet(&saddr)) {
+ addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
+ saddr.data, saddr.bytelen);
+ }
+ if (is_addrtype_inet(&daddr)) {
+ addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
+ daddr.data, daddr.bytelen);
+ }
addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
+ addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
+ addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
+ addattr32(n, 1024, IFLA_IPTUN_LINK, link);
addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark);
addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
if (strcmp(lu->id, "sit") == 0) {
addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
- if (ip6rdprefixlen) {
+ if (is_addrtype_inet(&ip6rdprefix)) {
addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
- &ip6rdprefix, sizeof(ip6rdprefix));
+ ip6rdprefix.data, ip6rdprefix.bytelen);
addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
- ip6rdprefixlen);
+ ip6rdprefix.bitlen);
+ }
+ if (is_addrtype_inet(&ip6rdrelayprefix)) {
addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
- ip6rdrelayprefix);
+ ip6rdrelayprefix.data[0]);
addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
- ip6rdrelayprefixlen);
+ ip6rdrelayprefix.bitlen);
}
}
tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET);
if (tb[IFLA_IPTUN_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
IFLA_IPTUN_ENCAP_DPORT);
}
-static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f, strcmp(lu->id, "sit") == 0);
-}
-
struct link_util ipip_link_util = {
.id = "ipip",
.maxattr = IFLA_IPTUN_MAX,
}
static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
- struct nlmsghdr *hdr)
+ struct nlmsghdr *n)
{
- char *dev = NULL;
- char *name = NULL;
- char *link = NULL;
char *type = NULL;
- int index = 0;
int err;
struct rtattr *data;
- int group;
struct ifinfomsg *ifm, *peer_ifm;
- unsigned int ifi_flags, ifi_change;
+ unsigned int ifi_flags, ifi_change, ifi_index;
if (strcmp(argv[0], "peer") != 0) {
usage();
return -1;
}
- ifm = NLMSG_DATA(hdr);
+ ifm = NLMSG_DATA(n);
ifi_flags = ifm->ifi_flags;
ifi_change = ifm->ifi_change;
+ ifi_index = ifm->ifi_index;
ifm->ifi_flags = 0;
ifm->ifi_change = 0;
+ ifm->ifi_index = 0;
- data = NLMSG_TAIL(hdr);
- addattr_l(hdr, 1024, VETH_INFO_PEER, NULL, 0);
+ data = addattr_nest(n, 1024, VETH_INFO_PEER);
- hdr->nlmsg_len += sizeof(struct ifinfomsg);
+ n->nlmsg_len += sizeof(struct ifinfomsg);
- err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
- &name, &type, &link, &dev, &group, &index);
+ err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type);
if (err < 0)
return err;
if (type)
duparg("type", argv[err]);
- if (name) {
- addattr_l(hdr, 1024,
- IFLA_IFNAME, name, strlen(name) + 1);
- }
-
peer_ifm = RTA_DATA(data);
- peer_ifm->ifi_index = index;
+ peer_ifm->ifi_index = ifm->ifi_index;
peer_ifm->ifi_flags = ifm->ifi_flags;
peer_ifm->ifi_change = ifm->ifi_change;
ifm->ifi_flags = ifi_flags;
ifm->ifi_change = ifi_change;
+ ifm->ifi_index = ifi_index;
- if (group != -1)
- addattr32(hdr, 1024, IFLA_GROUP, group);
-
- data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+ addattr_nest_end(n, data);
return argc - 1 - err;
}
#include "ip_common.h"
#include "tunnel.h"
-
-static void print_usage(FILE *f)
+static void vti_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
{
fprintf(f,
- "Usage: ... vti [ remote ADDR ]\n"
- " [ local ADDR ]\n"
- " [ [i|o]key KEY ]\n"
- " [ dev PHYS_DEV ]\n"
- " [ fwmark MARK ]\n"
+ "Usage: ... %-4s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
+ " [ local ADDR ]\n"
+ " [ [i|o]key KEY ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
"\n"
- "Where: ADDR := { IP_ADDRESS }\n"
+ );
+ fprintf(f,
+ "Where: ADDR := { IP%s_ADDRESS }\n"
" KEY := { DOTTED_QUAD | NUMBER }\n"
- " MARK := { 0x0..0xffffffff }\n"
+ " MARK := { 0x0..0xffffffff }\n",
+ ""
);
}
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
- print_usage(stderr);
- exit(-1);
-}
-
static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
__be32 ikey = 0;
__be32 okey = 0;
- unsigned int saddr = 0;
- unsigned int daddr = 0;
+ inet_prefix saddr, daddr;
unsigned int link = 0;
__u32 fwmark = 0;
int len;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
linkinfo[IFLA_INFO_DATA]);
+ rta = vtiinfo[IFLA_VTI_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET))
+ goto get_failed;
+
+ rta = vtiinfo[IFLA_VTI_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET))
+ goto get_failed;
+
if (vtiinfo[IFLA_VTI_IKEY])
ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
if (vtiinfo[IFLA_VTI_OKEY])
okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
- if (vtiinfo[IFLA_VTI_LOCAL])
- saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]);
-
- if (vtiinfo[IFLA_VTI_REMOTE])
- daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]);
-
if (vtiinfo[IFLA_VTI_LINK])
link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
okey = tnl_parse_key("okey", *argv);
} else if (!matches(*argv, "remote")) {
NEXT_ARG();
- daddr = get_addr32(*argv);
+ get_addr(&daddr, *argv, AF_INET);
} else if (!matches(*argv, "local")) {
NEXT_ARG();
- saddr = get_addr32(*argv);
+ get_addr(&saddr, *argv, AF_INET);
} else if (!matches(*argv, "dev")) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- exit(-1);
- }
+ if (!link)
+ exit(nodev(*argv));
} else if (strcmp(*argv, "fwmark") == 0) {
NEXT_ARG();
if (get_u32(&fwmark, *argv, 0))
invarg("invalid fwmark\n", *argv);
- } else
- usage();
+ } else {
+ vti_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--; argv++;
}
addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
addattr32(n, 1024, IFLA_VTI_OKEY, okey);
- addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4);
- addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4);
+ if (is_addrtype_inet(&saddr))
+ addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen);
+ if (is_addrtype_inet(&daddr))
+ addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen);
addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
if (link)
addattr32(n, 1024, IFLA_VTI_LINK, link);
tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET);
if (tb[IFLA_VTI_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
}
}
-static void vti_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f);
-}
-
struct link_util vti_link_util = {
.id = "vti",
.maxattr = IFLA_VTI_MAX,
#include "ip_common.h"
#include "tunnel.h"
-static void print_usage(FILE *f)
+static void vti6_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
{
fprintf(f,
- "Usage: ... vti6 [ remote ADDR ]\n"
+ "Usage: ... %-4s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
" [ local ADDR ]\n"
" [ [i|o]key KEY ]\n"
" [ dev PHYS_DEV ]\n"
" [ fwmark MARK ]\n"
"\n"
- "Where: ADDR := { IPV6_ADDRESS }\n"
+ );
+ fprintf(f,
+ "Where: ADDR := { IP%s_ADDRESS }\n"
" KEY := { DOTTED_QUAD | NUMBER }\n"
- " MARK := { 0x0..0xffffffff }\n"
+ " MARK := { 0x0..0xffffffff }\n",
+ "V6"
);
}
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
- print_usage(stderr);
- exit(-1);
-}
-
static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
struct {
struct nlmsghdr n;
struct ifinfomsg i;
struct rtattr *tb[IFLA_MAX + 1];
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
- struct in6_addr saddr = IN6ADDR_ANY_INIT;
- struct in6_addr daddr = IN6ADDR_ANY_INIT;
__be32 ikey = 0;
__be32 okey = 0;
+ inet_prefix saddr, daddr;
unsigned int link = 0;
__u32 fwmark = 0;
int len;
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
+
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
linkinfo[IFLA_INFO_DATA]);
+ rta = vtiinfo[IFLA_VTI_LOCAL];
+ if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+ goto get_failed;
+
+ rta = vtiinfo[IFLA_VTI_REMOTE];
+ if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+ goto get_failed;
+
if (vtiinfo[IFLA_VTI_IKEY])
ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
if (vtiinfo[IFLA_VTI_OKEY])
okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
- if (vtiinfo[IFLA_VTI_LOCAL])
- memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
-
- if (vtiinfo[IFLA_VTI_REMOTE])
- memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
-
if (vtiinfo[IFLA_VTI_LINK])
link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
NEXT_ARG();
okey = tnl_parse_key("okey", *argv);
} else if (!matches(*argv, "remote")) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&daddr, addr.data, sizeof(daddr));
+ get_addr(&daddr, *argv, AF_INET6);
} else if (!matches(*argv, "local")) {
- inet_prefix addr;
-
NEXT_ARG();
- get_addr(&addr, *argv, AF_INET6);
- memcpy(&saddr, addr.data, sizeof(saddr));
+ get_addr(&saddr, *argv, AF_INET6);
} else if (!matches(*argv, "dev")) {
NEXT_ARG();
link = ll_name_to_index(*argv);
- if (link == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- *argv);
- exit(-1);
- }
+ if (!link)
+ exit(nodev(*argv));
} else if (strcmp(*argv, "fwmark") == 0) {
NEXT_ARG();
if (get_u32(&fwmark, *argv, 0))
invarg("invalid fwmark\n", *argv);
- } else
- usage();
+ } else {
+ vti6_print_help(lu, argc, argv, stderr);
+ return -1;
+ }
argc--; argv++;
}
addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
addattr32(n, 1024, IFLA_VTI_OKEY, okey);
- addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
- addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
+ if (is_addrtype_inet(&saddr))
+ addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen);
+ if (is_addrtype_inet(&daddr))
+ addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen);
addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
if (link)
addattr32(n, 1024, IFLA_VTI_LINK, link);
tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET6);
if (tb[IFLA_VTI_LINK]) {
- unsigned int link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
+ __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
if (link) {
print_string(PRINT_ANY, "link", "dev %s ",
}
}
-static void vti6_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
-{
- print_usage(f);
-}
-
struct link_util vti6_link_util = {
.id = "vti6",
.maxattr = IFLA_VTI_MAX,
/* 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, \
#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 },
{ "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",
[TCP_METRIC_REORDERING] = "reordering",
};
-static struct
-{
+static struct {
int flushed;
char *flushb;
int flushp;
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;
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];
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;
- fprintf(fp, "\n");
+ src = format_host(saddr.family, saddr.bytelen, saddr.data);
+ print_string(PRINT_ANY, "source",
+ " source %s", src);
+ }
+ print_string(PRINT_FP, NULL, "\n", "");
+ close_json_object();
fflush(fp);
return 0;
}
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;
}
#include <linux/if.h>
#include <linux/ip.h>
#include <linux/if_tunnel.h>
+#include <linux/if_arp.h>
#include "utils.h"
#include "tunnel.h"
}
}
-/* tnl_print_stats - print tunnel statistics
- *
- * @buf - tunnel interface's line in /proc/net/dev,
- * starting past the interface name and following colon
- */
-void tnl_print_stats(const char *buf)
+static void tnl_print_stats(const struct rtnl_link_stats64 *s)
{
- unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
- rx_fifo, rx_frame,
- tx_bytes, tx_packets, tx_errs, tx_drops,
- tx_fifo, tx_colls, tx_carrier, rx_multi;
-
- if (sscanf(buf, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
- &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
- &rx_fifo, &rx_frame, &rx_multi,
- &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
- &tx_fifo, &tx_colls, &tx_carrier) != 14)
- return;
-
printf("%s", _SL_);
printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
- printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
- rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+ printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-8lld%s",
+ s->rx_packets, s->rx_bytes, s->rx_errors, s->rx_frame_errors,
+ s->rx_fifo_errors, s->multicast, _SL_);
printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
- printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
- tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+ printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-6lld",
+ s->tx_packets, s->tx_bytes, s->tx_errors, s->collisions,
+ s->tx_carrier_errors, s->tx_dropped);
+}
+
+static int print_nlmsg_tunnel(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ struct tnl_print_nlmsg_info *info = arg;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX+1];
+ const char *name, *n1;
+
+ if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+ return 0;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
+ return -1;
+
+ if (preferred_family == AF_INET) {
+ switch (ifi->ifi_type) {
+ case ARPHRD_TUNNEL:
+ case ARPHRD_IPGRE:
+ case ARPHRD_SIT:
+ break;
+ default:
+ return 0;
+ }
+ } else {
+ switch (ifi->ifi_type) {
+ case ARPHRD_TUNNEL6:
+ case ARPHRD_IP6GRE:
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+ if (!tb[IFLA_IFNAME])
+ return 0;
+
+ name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+ /* Assume p1->name[IFNAMSIZ] is first field of structure */
+ n1 = info->p1;
+ if (n1[0] && strcmp(n1, name))
+ return 0;
+
+ info->ifi = ifi;
+ info->init(info);
+
+ /* TODO: parse netlink attributes */
+ if (tnl_get_ioctl(name, info->p2))
+ return 0;
+
+ if (!info->match(info))
+ return 0;
+
+ info->print(info->p2);
+ if (show_stats) {
+ struct rtnl_link_stats64 s;
+
+ if (get_rtnl_link_stats_rta(&s, tb) <= 0)
+ return -1;
+
+ tnl_print_stats(&s);
+ }
+ fputc('\n', stdout);
+
+ return 0;
+}
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info)
+{
+ if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
+ perror("Cannot send dump request\n");
+ return -1;
+ }
+
+ if (rtnl_dump_filter(&rth, print_nlmsg_tunnel, info) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return -1;
+ }
+
+ return 0;
}
#ifndef __TUNNEL_H__
#define __TUNNEL_H__ 1
+#include <stdbool.h>
#include <linux/types.h>
struct rtattr;
+struct ifinfomsg;
+
+extern struct rtnl_handle rth;
+
+struct tnl_print_nlmsg_info {
+ const struct ifinfomsg *ifi;
+ const void *p1;
+ void *p2;
+
+ void (*init)(const struct tnl_print_nlmsg_info *info);
+ bool (*match)(const struct tnl_print_nlmsg_info *info);
+ void (*print)(const void *t);
+};
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info);
const char *tnl_strproto(__u8 proto);
int encap_sport, int encap_dport);
void tnl_print_endpoint(const char *name,
const struct rtattr *rta, int family);
-void tnl_print_stats(const char *buf);
#endif
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __XDP__
-#define __XDP__
-
-#include "utils.h"
-
-int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
- bool generic, bool drv, bool offload);
-void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
-
-#endif /* __XDP__ */
CFLAGS += -fPIC
-UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
+UTILOBJ = utils.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
inet_proto.o namespace.o json_writer.o json_print.o \
names.o color.o bpf.o exec.o fs.o
-NLOBJ=libgenl.o ll_map.o libnetlink.o
+NLOBJ=libgenl.o libnetlink.o
all: libnetlink.a libutil.a
perror("json object");
exit(1);
}
- jsonw_pretty(_jw, true);
+ if (pretty)
+ jsonw_pretty(_jw, true);
jsonw_start_array(_jw);
}
}
void close_json_array(enum output_type type, const char *str)
{
if (_IS_JSON_CONTEXT(type)) {
- jsonw_pretty(_jw, false);
jsonw_end_array(_jw);
- jsonw_pretty(_jw, true);
} else if (_IS_FP_CONTEXT(type)) {
printf("%s", str);
}
void jsonw_start_array(json_writer_t *self)
{
jsonw_begin(self, '[');
+ if (self->pretty)
+ putc(' ', self->out);
}
void jsonw_end_array(json_writer_t *self)
{
+ if (self->pretty && self->sep)
+ putc(' ', self->out);
+ self->sep = '\0';
jsonw_end(self, ']');
}
return 0;
}
-const char *ll_idx_n2a(unsigned idx, char *buf)
+const char *ll_idx_n2a(unsigned int idx)
{
+ static char buf[IFNAMSIZ];
+
+ snprintf(buf, sizeof(buf), "if%u", idx);
+ return buf;
+}
+
+unsigned int ll_idx_a2n(const char *name)
+{
+ unsigned int idx;
+
+ if (sscanf(name, "if%u", &idx) != 1)
+ return 0;
+ return idx;
+}
+
+const char *ll_index_to_name(unsigned int idx)
+{
+ static char buf[IFNAMSIZ];
const struct ll_cache *im;
if (idx == 0)
return im->name;
if (if_indextoname(idx, buf) == NULL)
- snprintf(buf, IFNAMSIZ, "if%d", idx);
+ snprintf(buf, IFNAMSIZ, "if%u", idx);
return buf;
}
-const char *ll_index_to_name(unsigned idx)
-{
- static char nbuf[IFNAMSIZ];
-
- return ll_idx_n2a(idx, nbuf);
-}
-
int ll_index_to_type(unsigned idx)
{
const struct ll_cache *im;
idx = if_nametoindex(name);
if (idx == 0)
- sscanf(name, "if%u", &idx);
+ idx = ll_idx_a2n(name);
return idx;
}
#include "rt_names.h"
#include "utils.h"
+#include "ll_map.h"
#include "namespace.h"
int resolve_hosts;
int timestamp_short;
+int pretty;
int read_prop(const char *dev, char *prop, long *value)
{
exit(-1);
}
+int nodev(const char *dev)
+{
+ fprintf(stderr, "Cannot find device \"%s\"\n", dev);
+ return -1;
+}
+
int check_ifname(const char *name)
{
/* These checks mimic kernel checks in dev_valid_name */
return ret;
}
+const char *get_ifname_rta(int ifindex, const struct rtattr *rta)
+{
+ const char *name;
+
+ if (rta) {
+ name = rta_getattr_str(rta);
+ } else {
+ fprintf(stderr,
+ "BUG: device with ifindex %d has nil ifname\n",
+ ifindex);
+ name = ll_idx_n2a(ifindex);
+ }
+
+ if (check_ifname(name))
+ return NULL;
+
+ return name;
+}
+
int matches(const char *cmd, const char *pattern)
{
int len = strlen(cmd);
return 0;
}
+unsigned int print_name_and_link(const char *fmt,
+ const char *name, struct rtattr *tb[])
+{
+ const char *link = NULL;
+ unsigned int m_flag = 0;
+ SPRINT_BUF(b1);
+
+ if (tb[IFLA_LINK]) {
+ int iflink = rta_getattr_u32(tb[IFLA_LINK]);
+
+ if (iflink) {
+ if (tb[IFLA_LINK_NETNSID]) {
+ if (is_json_context()) {
+ print_int(PRINT_JSON,
+ "link_index", NULL, iflink);
+ } else {
+ link = ll_idx_n2a(iflink);
+ }
+ } else {
+ link = ll_index_to_name(iflink);
+
+ if (is_json_context()) {
+ print_string(PRINT_JSON,
+ "link", NULL, link);
+ link = NULL;
+ }
+
+ m_flag = ll_index_to_flags(iflink);
+ m_flag = !(m_flag & IFF_UP);
+ }
+ } else {
+ if (is_json_context())
+ print_null(PRINT_JSON, "link", NULL, NULL);
+ else
+ link = "NONE";
+ }
+
+ if (link) {
+ snprintf(b1, sizeof(b1), "%s@%s", name, link);
+ name = b1;
+ }
+ }
+
+ print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, name);
+
+ return m_flag;
+}
+
int cmdlineno;
/* Like glibc getline but handle continuation lines and comments */
return rtm_family;
}
+/* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */
+static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64,
+ const struct rtnl_link_stats *stats)
+{
+ __u64 *a = (__u64 *)stats64;
+ const __u32 *b = (const __u32 *)stats;
+ const __u32 *e = b + sizeof(*stats) / sizeof(*b);
+
+ while (b < e)
+ *a++ = *b++;
+}
+
+int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
+ struct rtattr *tb[])
+{
+ struct rtnl_link_stats stats;
+ void *s;
+ struct rtattr *rta;
+ int size, len;
+
+ if (tb[IFLA_STATS64]) {
+ rta = tb[IFLA_STATS64];
+ size = sizeof(struct rtnl_link_stats64);
+ s = stats64;
+ } else if (tb[IFLA_STATS]) {
+ rta = tb[IFLA_STATS];
+ size = sizeof(struct rtnl_link_stats);
+ s = &stats;
+ } else {
+ return -1;
+ }
+
+ len = RTA_PAYLOAD(rta);
+ if (len < size)
+ memset(s + len, 0, size - len);
+ else
+ len = size;
+
+ memcpy(s, RTA_DATA(rta), len);
+
+ if (s != stats64)
+ copy_rtnl_link_stats64(stats64, s);
+ return size;
+}
+
#ifdef NEED_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t size)
{
\fB\-s\fR[\fItatistics\fR] |
\fB\-n\fR[\fIetns\fR] name |
\fB\-b\fR[\fIatch\fR] filename |
+\fB\-c\fR[\folor\fR] |
+\fB\-p\fR[\fIretty\fR] |
\fB\-j\fR[\fIson\fR] }
.ti -8
.B dev
.IR DEV " { "
.BR local " | " static " | " dynamic " } [ "
-.BR self " ] [ " master " ] [ " router " ] [ " use " ] [ "
+.BR self " ] [ " master " ] [ " router " ] [ " use " ] [ " extern_learn " ] [ "
.B dst
.IR IPADDR " ] [ "
.B vni
return code will be non zero.
.TP
-.BR "\-json"
-Display results in JSON format. Currently available for vlan and fdb.
+.BR "\-c" , " -color"
+Use color output.
+
+.TP
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
+When combined with -j generate a pretty JSON output.
+
.SH BRIDGE - COMMAND SYNTAX
indicate to the kernel that the fdb entry is in use.
.sp
+.B extern_learn
+- this entry was learned externally. This option can be used to
+indicate to the kernel that an entry was hardware or user-space
+controller learnt dynamic entry. Kernel will not age such an entry.
+.sp
+
.in -8
The next command line parameters apply only
when the specified device
] [
.BI "dscp inherit"
] [
+.BI "[no]allow-localremote"
+] [
.BI dev " PHYS_DEV "
] [
.RB external
.BI flowlabel " FLOWLABEL"
- specifies a fixed flowlabel.
+.sp
+.BI [no]allow-localremote
+- specifies whether to allow remote endpoint to have an address configured on
+local host.
+
.sp
.BI tclass " TCLASS"
- specifies the traffic class field on
] [
.BR erspan_hwid " \fIhwid "
] [
+.BI "[no]allow-localremote"
+] [
.RB external
]
.IR hwid
is a 6-bit value for users to configure.
+.sp
+.BI [no]allow-localremote
+- specifies whether to allow remote endpoint to have an address configured on
+local host.
+
.sp
.BR external
- make this tunnel externally controlled (or not, which is the default).
.IR STRING " ] [ "
.B pref
.IR NUMBER " ] [ "
-.BR l3mdev " ]"
+.IR l3mdev " ] [ "
+.B uidrange
+.IR NUMBER "-" NUMBER " ] [ "
+.B ipproto
+.IR PROTOCOL " ] [ "
+.BR sport " [ "
+.IR NUMBER " | "
+.IR NUMBER "-" NUMBER " ] ] [ "
+.BR dport " [ "
+.IR NUMBER " | "
+.IR NUMBER "-" NUMBER " ] ]"
+.BR
+
.ti -8
.IR ACTION " := [ "
.B table
.IR TABLE_ID " ] [ "
+.B protocol
+.IR PROTO " ] [ "
.B nat
.IR ADDRESS " ] [ "
.B realms
.B fwmark
value to match.
+.TP
+.BI uidrange " NUMBER-NUMBER"
+select the
+.B uid
+value to match.
+
+.TP
+.BI ipproto " PROTOCOL"
+select the ip protocol value to match.
+
+.TP
+.BI sport " NUMBER | NUMBER-NUMBER"
+select the source port value to match. supports port range.
+
+.TP
+.BI dport " NUMBER | NUMBER-NUMBER"
+select the destination port value to match. supports port range.
+
.TP
.BI priority " PREFERENCE"
the priority of this rule.
the routing table identifier to lookup if the rule selector matches.
It is also possible to use lookup instead of table.
+.TP
+.BI protocol " PROTO"
+the routing protocol who installed the rule in question. As an example when zebra installs a rule it would get RTPROT_ZEBRA as the installing protocol.
+
.TP
.BI suppress_prefixlength " NUMBER"
reject routing decisions that have a prefix length of NUMBER or less.
.RE
.TP
.B ip rule flush - also dumps all the deleted rules.
-This command has no arguments.
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
.TP
.B ip rule show - list rules
This command has no arguments.
.TP
.B ip rule save
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
+.TP
save rules table information to stdout
.RS
This command behaves like
\fB\-ts\fR[\fIhort\fR] |
\fB\-n\fR[\fIetns\fR] name |
\fB\-a\fR[\fIll\fR] |
-\fB\-c\fR[\fIolor\fR]
-\fB\-br\fR[\fIief\fR] }
-
+\fB\-c\fR[\fIolor\fR] |
+\fB\-br\fR[\fIief\fR] |
+\fB\-j\fR[son\fR] |
+\fB\-p\fR[retty\fR] }
.SH OPTIONS
print human readable rates in IEC units (e.g. 1Ki = 1024).
.TP
-.BR "\-br" , "\-brief"
+.BR "\-br" , " \-brief"
Print only basic information in a tabular format for better readability. This option is currently only supported by
.BR "ip addr show " and " ip link show " commands.
+.TP
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
+The default JSON format is compact and more efficient to parse but hard for most users to read.
+This flag adds indentation for readability.
+
.SH IP - COMMAND SYNTAX
.SS
.BR help " }"
.sp
+.ti -8
+.B rdma
+.RB "[ " -force " ] "
+.BI "-batch " filename
+.sp
+
.ti -8
.IR OBJECT " := { "
.BR dev " | " link " }"
.B rdma
tool and exit.
+.TP
+.BR "\-b", " \-batch " <FILENAME>
+Read commands from provided file or standard input and invoke them.
+First failure will cause termination of rdma.
+
+.TP
+.BR "\-force"
+Don't terminate rdma on errors in batch mode.
+If there were any errors during execution of the commands, the application return code will be non zero.
+
.TP
.BR "\-d" , " --details"
Otuput detailed information.
.B ecn
|
.B noecn
-]
+] [
+.B ce_threshold
+TIME ]
.SH DESCRIPTION
CoDel (pronounced "coddle") is an adaptive "no-knobs" active queue management
.B ecn
is turned off.
+.SS ce_threshold
+sets a threshold above which all packets are marked with ECN Congestion
+Experienced. This is useful for DCTCP-style congestion control algorithms that
+require marking at very shallow queueing thresholds.
+
+
.SH EXAMPLES
# tc qdisc add dev eth0 root codel
# tc -s qdisc show
the interface can be queried using "src,dst (source ip address, outgoing interface) or
"src,src" (source ip address, incoming interface) syntax.
+.SS ipt
+test packet against xtables matches
+
+.IR ipt "( " [-6] " "-m " " MATCH_NAME " " FLAGS " )
+
+.IR MATCH_NAME " := " string
+
+.IR FLAGS " := { " FLAG " [, " FLAGS "] }
+
+The flag options are the same as those used by the xtable match used.
+
.SH CAVEATS
The ematch syntax uses '(' and ')' to group expressions. All braces need to be
# 'ipset(interactive src,src)'
+Check if packet matches an IPSec state with reqid 1:
+
+# 'ipt(-m policy --dir in --pol ipsec --reqid 1)'
+
.SH "AUTHOR"
The extended match infrastructure was added by Thomas Graf.
.BI ip_flags " IP_FLAGS"
.I IP_FLAGS
may be either
-.BR frag " or " nofrag
-to match on fragmented packets or not respectively.
+.BR frag ", " nofrag ", " firstfrag " or " nofirstfrag
+where frag and nofrag could be used to match on fragmented packets or not,
+respectively. firstfrag and nofirstfrag can be used to further distinguish
+fragmented packet. firstfrag can be used to indicate the first fragmented
+packet. nofirstfrag can be used to indicates subsequent fragmented packets
+or non-fragmented packets.
.SH NOTES
As stated above where applicable, matches of a certain layer implicitly depend
on the matches of the next lower layer. Precisely, layer one and two matches
.B ecn
|
.B noecn
-]
+] [
+.B ce_threshold
+TIME ] [
+.B memory_limit
+BYTES ]
.SH DESCRIPTION
FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair
When this limit is reached, incoming packets are dropped. Default is 10240
packets.
+.SS memory_limit
+sets a limit on the total number of bytes that can be queued in this FQ-CoDel
+instance. The lower of the packet limit of the
+.B limit
+parameter and the memory limit will be enforced. Default is 32 MB.
+
+
.SS flows
is the number of flows into which the incoming packets are classified. Due to
the stochastic nature of hashing, multiple flows may end up being hashed into
.B codel, ecn
is turned on by default.
+.SS ce_threshold
+sets a threshold above which all packets are marked with ECN Congestion
+Experienced. This is useful for DCTCP-style congestion control algorithms that
+require marking at very shallow queueing thresholds.
+
.SH EXAMPLES
#tc qdisc add dev eth0 root fq_codel
.br
\fB\-s\fR[\fItatistics\fR] |
\fB\-d\fR[\fIetails\fR] |
\fB\-r\fR[\fIaw\fR] |
-\fB\-p\fR[\fIretty\fR] |
\fB\-i\fR[\fIec\fR] |
\fB\-g\fR[\fIraph\fR] |
-\fB\-j\fR[\fIjson\fR] }
+\fB\-j\fR[\fIjson\fR] |
+\fB\-p\fR[\fIretty\fR] |
+\fB\-col\fR[\fIor\fR] }
.SH DESCRIPTION
.B Tc
.TP
.BR "\-p", " \-pretty"
-decode filter offset and mask values to equivalent filter commands based on TCP/IP.
+for u32 filter, decode offset and mask values to equivalent filter commands based on TCP/IP.
+In JSON output, add whitespace to improve readability.
.TP
.BR "\-iec"
.BR "dev"
option.
+.TP
+.BR "\ -color"
+Use color output.
+
.TP
.BR "\-j", " \-json"
Display results in JSON format.
int scan_interval;
int time_constant;
int show_errors;
-int pretty;
double W;
char **patterns;
int npatterns;
int ignore_history;
int no_output;
int json_output;
-int pretty;
int no_update;
int scan_interval;
int time_constant;
fil++;
}
}
+
+ if (show_mem)
+ print_skmeminfo(tb, PACKET_DIAG_MEMINFO);
return 0;
}
TARGETS :=
ifeq ($(HAVE_MNL),y)
+CFLAGS += -I./include/uapi/
RDMA_OBJ = rdma.o utils.o dev.o link.o res.o
x(SG_GAPS_REG, 32) \
x(VIRTUAL_FUNCTION, 33) \
x(RAW_SCATTER_FCS, 34) \
- x(RDMA_NETDEV_OPA_VNIC, 35)
+ x(RDMA_NETDEV_OPA_VNIC, 35) \
+ x(PCI_WRITE_END_PADDING, 36)
enum { RDMA_DEV_FLAGS(RDMA_BITMAP_ENUM) };
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _RDMA_NETLINK_H
+#define _RDMA_NETLINK_H
+
+#include <linux/types.h>
+
+enum {
+ RDMA_NL_RDMA_CM = 1,
+ RDMA_NL_IWCM,
+ RDMA_NL_RSVD,
+ RDMA_NL_LS, /* RDMA Local Services */
+ RDMA_NL_NLDEV, /* RDMA device interface */
+ RDMA_NL_NUM_CLIENTS
+};
+
+enum {
+ RDMA_NL_GROUP_CM = 1,
+ RDMA_NL_GROUP_IWPM,
+ RDMA_NL_GROUP_LS,
+ RDMA_NL_NUM_GROUPS
+};
+
+#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
+#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
+#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
+
+enum {
+ RDMA_NL_RDMA_CM_ID_STATS = 0,
+ RDMA_NL_RDMA_CM_NUM_OPS
+};
+
+enum {
+ RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
+ RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
+ RDMA_NL_RDMA_CM_NUM_ATTR,
+};
+
+/* iwarp port mapper op-codes */
+enum {
+ RDMA_NL_IWPM_REG_PID = 0,
+ RDMA_NL_IWPM_ADD_MAPPING,
+ RDMA_NL_IWPM_QUERY_MAPPING,
+ RDMA_NL_IWPM_REMOVE_MAPPING,
+ RDMA_NL_IWPM_REMOTE_INFO,
+ RDMA_NL_IWPM_HANDLE_ERR,
+ RDMA_NL_IWPM_MAPINFO,
+ RDMA_NL_IWPM_MAPINFO_NUM,
+ RDMA_NL_IWPM_NUM_OPS
+};
+
+struct rdma_cm_id_stats {
+ __u32 qp_num;
+ __u32 bound_dev_if;
+ __u32 port_space;
+ __s32 pid;
+ __u8 cm_state;
+ __u8 node_type;
+ __u8 port_num;
+ __u8 qp_type;
+};
+
+enum {
+ IWPM_NLA_REG_PID_UNSPEC = 0,
+ IWPM_NLA_REG_PID_SEQ,
+ IWPM_NLA_REG_IF_NAME,
+ IWPM_NLA_REG_IBDEV_NAME,
+ IWPM_NLA_REG_ULIB_NAME,
+ IWPM_NLA_REG_PID_MAX
+};
+
+enum {
+ IWPM_NLA_RREG_PID_UNSPEC = 0,
+ IWPM_NLA_RREG_PID_SEQ,
+ IWPM_NLA_RREG_IBDEV_NAME,
+ IWPM_NLA_RREG_ULIB_NAME,
+ IWPM_NLA_RREG_ULIB_VER,
+ IWPM_NLA_RREG_PID_ERR,
+ IWPM_NLA_RREG_PID_MAX
+
+};
+
+enum {
+ IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
+ IWPM_NLA_MANAGE_MAPPING_SEQ,
+ IWPM_NLA_MANAGE_ADDR,
+ IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
+ IWPM_NLA_RMANAGE_MAPPING_ERR,
+ IWPM_NLA_RMANAGE_MAPPING_MAX
+};
+
+#define IWPM_NLA_MANAGE_MAPPING_MAX 3
+#define IWPM_NLA_QUERY_MAPPING_MAX 4
+#define IWPM_NLA_MAPINFO_SEND_MAX 3
+
+enum {
+ IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
+ IWPM_NLA_QUERY_MAPPING_SEQ,
+ IWPM_NLA_QUERY_LOCAL_ADDR,
+ IWPM_NLA_QUERY_REMOTE_ADDR,
+ IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
+ IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
+ IWPM_NLA_RQUERY_MAPPING_ERR,
+ IWPM_NLA_RQUERY_MAPPING_MAX
+};
+
+enum {
+ IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
+ IWPM_NLA_MAPINFO_ULIB_NAME,
+ IWPM_NLA_MAPINFO_ULIB_VER,
+ IWPM_NLA_MAPINFO_REQ_MAX
+};
+
+enum {
+ IWPM_NLA_MAPINFO_UNSPEC = 0,
+ IWPM_NLA_MAPINFO_LOCAL_ADDR,
+ IWPM_NLA_MAPINFO_MAPPED_ADDR,
+ IWPM_NLA_MAPINFO_MAX
+};
+
+enum {
+ IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
+ IWPM_NLA_MAPINFO_SEQ,
+ IWPM_NLA_MAPINFO_SEND_NUM,
+ IWPM_NLA_MAPINFO_ACK_NUM,
+ IWPM_NLA_MAPINFO_NUM_MAX
+};
+
+enum {
+ IWPM_NLA_ERR_UNSPEC = 0,
+ IWPM_NLA_ERR_SEQ,
+ IWPM_NLA_ERR_CODE,
+ IWPM_NLA_ERR_MAX
+};
+
+/*
+ * Local service operations:
+ * RESOLVE - The client requests the local service to resolve a path.
+ * SET_TIMEOUT - The local service requests the client to set the timeout.
+ * IP_RESOLVE - The client requests the local service to resolve an IP to GID.
+ */
+enum {
+ RDMA_NL_LS_OP_RESOLVE = 0,
+ RDMA_NL_LS_OP_SET_TIMEOUT,
+ RDMA_NL_LS_OP_IP_RESOLVE,
+ RDMA_NL_LS_NUM_OPS
+};
+
+/* Local service netlink message flags */
+#define RDMA_NL_LS_F_ERR 0x0100 /* Failed response */
+
+/*
+ * Local service resolve operation family header.
+ * The layout for the resolve operation:
+ * nlmsg header
+ * family header
+ * attributes
+ */
+
+/*
+ * Local service path use:
+ * Specify how the path(s) will be used.
+ * ALL - For connected CM operation (6 pathrecords)
+ * UNIDIRECTIONAL - For unidirectional UD (1 pathrecord)
+ * GMP - For miscellaneous GMP like operation (at least 1 reversible
+ * pathrecord)
+ */
+enum {
+ LS_RESOLVE_PATH_USE_ALL = 0,
+ LS_RESOLVE_PATH_USE_UNIDIRECTIONAL,
+ LS_RESOLVE_PATH_USE_GMP,
+ LS_RESOLVE_PATH_USE_MAX
+};
+
+#define LS_DEVICE_NAME_MAX 64
+
+struct rdma_ls_resolve_header {
+ __u8 device_name[LS_DEVICE_NAME_MAX];
+ __u8 port_num;
+ __u8 path_use;
+};
+
+struct rdma_ls_ip_resolve_header {
+ __u32 ifindex;
+};
+
+/* Local service attribute type */
+#define RDMA_NLA_F_MANDATORY (1 << 13)
+#define RDMA_NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \
+ RDMA_NLA_F_MANDATORY))
+
+/*
+ * Local service attributes:
+ * Attr Name Size Byte order
+ * -----------------------------------------------------
+ * PATH_RECORD struct ib_path_rec_data
+ * TIMEOUT u32 cpu
+ * SERVICE_ID u64 cpu
+ * DGID u8[16] BE
+ * SGID u8[16] BE
+ * TCLASS u8
+ * PKEY u16 cpu
+ * QOS_CLASS u16 cpu
+ * IPV4 u32 BE
+ * IPV6 u8[16] BE
+ */
+enum {
+ LS_NLA_TYPE_UNSPEC = 0,
+ LS_NLA_TYPE_PATH_RECORD,
+ LS_NLA_TYPE_TIMEOUT,
+ LS_NLA_TYPE_SERVICE_ID,
+ LS_NLA_TYPE_DGID,
+ LS_NLA_TYPE_SGID,
+ LS_NLA_TYPE_TCLASS,
+ LS_NLA_TYPE_PKEY,
+ LS_NLA_TYPE_QOS_CLASS,
+ LS_NLA_TYPE_IPV4,
+ LS_NLA_TYPE_IPV6,
+ LS_NLA_TYPE_MAX
+};
+
+/* Local service DGID/SGID attribute: big endian */
+struct rdma_nla_ls_gid {
+ __u8 gid[16];
+};
+
+enum rdma_nldev_command {
+ RDMA_NLDEV_CMD_UNSPEC,
+
+ RDMA_NLDEV_CMD_GET, /* can dump */
+
+ /* 2 - 4 are free to use */
+
+ RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */
+
+ /* 6 - 8 are free to use */
+
+ RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */
+
+ RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */
+
+ RDMA_NLDEV_NUM_OPS
+};
+
+enum rdma_nldev_attr {
+ /* don't change the order or add anything between, this is ABI! */
+ RDMA_NLDEV_ATTR_UNSPEC,
+
+ /* Identifier for ib_device */
+ RDMA_NLDEV_ATTR_DEV_INDEX, /* u32 */
+
+ RDMA_NLDEV_ATTR_DEV_NAME, /* string */
+ /*
+ * Device index together with port index are identifiers
+ * for port/link properties.
+ *
+ * For RDMA_NLDEV_CMD_GET commamnd, port index will return number
+ * of available ports in ib_device, while for port specific operations,
+ * it will be real port index as it appears in sysfs. Port index follows
+ * sysfs notation and starts from 1 for the first port.
+ */
+ RDMA_NLDEV_ATTR_PORT_INDEX, /* u32 */
+
+ /*
+ * Device and port capabilities
+ */
+ RDMA_NLDEV_ATTR_CAP_FLAGS, /* u64 */
+
+ /*
+ * FW version
+ */
+ RDMA_NLDEV_ATTR_FW_VERSION, /* string */
+
+ /*
+ * Node GUID (in host byte order) associated with the RDMA device.
+ */
+ RDMA_NLDEV_ATTR_NODE_GUID, /* u64 */
+
+ /*
+ * System image GUID (in host byte order) associated with
+ * this RDMA device and other devices which are part of a
+ * single system.
+ */
+ RDMA_NLDEV_ATTR_SYS_IMAGE_GUID, /* u64 */
+
+ /*
+ * Subnet prefix (in host byte order)
+ */
+ RDMA_NLDEV_ATTR_SUBNET_PREFIX, /* u64 */
+
+ /*
+ * Local Identifier (LID),
+ * According to IB specification, It is 16-bit address assigned
+ * by the Subnet Manager. Extended to be 32-bit for OmniPath users.
+ */
+ RDMA_NLDEV_ATTR_LID, /* u32 */
+ RDMA_NLDEV_ATTR_SM_LID, /* u32 */
+
+ /*
+ * LID mask control (LMC)
+ */
+ RDMA_NLDEV_ATTR_LMC, /* u8 */
+
+ RDMA_NLDEV_ATTR_PORT_STATE, /* u8 */
+ RDMA_NLDEV_ATTR_PORT_PHYS_STATE, /* u8 */
+
+ RDMA_NLDEV_ATTR_DEV_NODE_TYPE, /* u8 */
+
+ RDMA_NLDEV_ATTR_RES_SUMMARY, /* nested table */
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY, /* nested table */
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */
+
+ RDMA_NLDEV_ATTR_RES_QP, /* nested table */
+ RDMA_NLDEV_ATTR_RES_QP_ENTRY, /* nested table */
+ /*
+ * Local QPN
+ */
+ RDMA_NLDEV_ATTR_RES_LQPN, /* u32 */
+ /*
+ * Remote QPN,
+ * Applicable for RC and UC only IBTA 11.2.5.3 QUERY QUEUE PAIR
+ */
+ RDMA_NLDEV_ATTR_RES_RQPN, /* u32 */
+ /*
+ * Receive Queue PSN,
+ * Applicable for RC and UC only 11.2.5.3 QUERY QUEUE PAIR
+ */
+ RDMA_NLDEV_ATTR_RES_RQ_PSN, /* u32 */
+ /*
+ * Send Queue PSN
+ */
+ RDMA_NLDEV_ATTR_RES_SQ_PSN, /* u32 */
+ RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE, /* u8 */
+ /*
+ * QP types as visible to RDMA/core, the reserved QPT
+ * are not exported through this interface.
+ */
+ RDMA_NLDEV_ATTR_RES_TYPE, /* u8 */
+ RDMA_NLDEV_ATTR_RES_STATE, /* u8 */
+ /*
+ * Process ID which created object,
+ * in case of kernel origin, PID won't exist.
+ */
+ RDMA_NLDEV_ATTR_RES_PID, /* u32 */
+ /*
+ * The name of process created following resource.
+ * It will exist only for kernel objects.
+ * For user created objects, the user is supposed
+ * to read /proc/PID/comm file.
+ */
+ RDMA_NLDEV_ATTR_RES_KERN_NAME, /* string */
+
+ RDMA_NLDEV_ATTR_MAX
+};
+#endif /* _RDMA_NETLINK_H */
static void help(char *name)
{
pr_out("Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n"
+ " %s [ -f[orce] ] -b[atch] filename\n"
"where OBJECT := { dev | link | resource | help }\n"
- " OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name);
+ " OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name, name);
}
static int cmd_help(struct rd *rd)
return 0;
}
-static int rd_cmd(struct rd *rd)
+static int rd_cmd(struct rd *rd, int argc, char **argv)
{
const struct rd_cmd cmds[] = {
{ NULL, cmd_help },
{ 0 }
};
+ rd->argc = argc;
+ rd->argv = argv;
+
return rd_exec_cmd(rd, cmds, "object");
}
-static int rd_init(struct rd *rd, int argc, char **argv, char *filename)
+static int rd_batch(struct rd *rd, const char *name, bool force)
+{
+ char *line = NULL;
+ size_t len = 0;
+ int ret = 0;
+
+ if (name && strcmp(name, "-") != 0) {
+ if (!freopen(name, "r", stdin)) {
+ pr_err("Cannot open file \"%s\" for reading: %s\n",
+ name, strerror(errno));
+ return errno;
+ }
+ }
+
+ cmdlineno = 0;
+ while (getcmdline(&line, &len, stdin) != -1) {
+ char *largv[512];
+ int largc;
+
+ largc = makeargs(line, largv, ARRAY_SIZE(largv));
+ if (!largc)
+ continue; /* blank line */
+
+ ret = rd_cmd(rd, largc, largv);
+ if (ret) {
+ pr_err("Command failed %s:%d\n", name, cmdlineno);
+ if (!force)
+ break;
+ }
+ }
+
+ free(line);
+
+ return ret;
+}
+
+static int rd_init(struct rd *rd, char *filename)
{
uint32_t seq;
int ret;
rd->filename = filename;
- rd->argc = argc;
- rd->argv = argv;
INIT_LIST_HEAD(&rd->dev_map_list);
INIT_LIST_HEAD(&rd->filter_list);
{ "json", no_argument, NULL, 'j' },
{ "pretty", no_argument, NULL, 'p' },
{ "details", no_argument, NULL, 'd' },
+ { "force", no_argument, NULL, 'f' },
+ { "batch", required_argument, NULL, 'b' },
{ NULL, 0, NULL, 0 }
};
+ const char *batch_file = NULL;
bool pretty_output = false;
bool show_details = false;
bool json_output = false;
+ bool force = false;
char *filename;
struct rd rd;
int opt;
filename = basename(argv[0]);
- while ((opt = getopt_long(argc, argv, "Vhdpj",
+ while ((opt = getopt_long(argc, argv, ":Vhdpjfb:",
long_options, NULL)) >= 0) {
switch (opt) {
case 'V':
case 'j':
json_output = true;
break;
+ case 'f':
+ force = true;
+ break;
+ case 'b':
+ batch_file = optarg;
+ break;
case 'h':
help(filename);
return EXIT_SUCCESS;
+ case ':':
+ pr_err("-%c option requires an argument\n", optopt);
+ return EXIT_FAILURE;
default:
pr_err("Unknown option.\n");
help(filename);
rd.json_output = json_output;
rd.pretty_output = pretty_output;
- err = rd_init(&rd, argc, argv, filename);
+ err = rd_init(&rd, filename);
if (err)
goto out;
- err = rd_cmd(&rd);
+ if (batch_file)
+ err = rd_batch(&rd, batch_file, force);
+ else
+ err = rd_cmd(&rd, argc, argv);
out:
/* Always cleanup */
rd_cleanup(&rd);
ifneq ($(TC_CONFIG_NO_XT),y)
ifeq ($(TC_CONFIG_XT),y)
TCSO += m_xt.so
+ TCMODULES += em_ipt.o
ifeq ($(TC_CONFIG_IPSET),y)
TCMODULES += em_ipset.o
endif
em_ipset.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
+em_ipt.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
+
+ifeq ($(TC_CONFIG_XT),y)
+ LDFLAGS += $$($(PKG_CONFIG) xtables --libs)
+endif
+
%.yacc.c: %.y
$(QUIET_YACC)$(YACC) $(YACCFLAGS) -o $@ $<
--- /dev/null
+/*
+ * em_ipt.c IPtables extenstions matching Ematch
+ *
+ * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <getopt.h>
+
+#include <linux/tc_ematch/tc_em_ipt.h>
+#include <linux/pkt_cls.h>
+#include <xtables.h>
+#include "m_ematch.h"
+
+static void em_ipt_print_usage(FILE *fd)
+{
+ fprintf(fd,
+ "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
+ "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
+}
+
+static struct option original_opts[] = {
+ {
+ .name = "match",
+ .has_arg = 1,
+ .val = 'm'
+ },
+ {
+ .name = "ipv6",
+ .val = '6'
+ },
+ {}
+};
+
+static struct xtables_globals em_tc_ipt_globals = {
+ .option_offset = 0,
+ .program_name = "tc-em-ipt",
+ .program_version = "0.1",
+ .orig_opts = original_opts,
+ .opts = original_opts,
+#if (XTABLES_VERSION_CODE >= 11)
+ .compat_rev = xtables_compatible_revision,
+#endif
+};
+
+static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
+{
+ struct xt_entry_match *m;
+
+ m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
+ if (!m)
+ return NULL;
+
+ if (data)
+ memcpy(m->data, data, data_size);
+
+ m->u.user.match_size = data_size;
+ return m;
+}
+
+static void scrub_match(struct xtables_match *match)
+{
+ match->mflags = 0;
+ free(match->m);
+ match->m = NULL;
+}
+
+/* IPv4 and IPv6 share the same hooking enumeration */
+#define HOOK_PRE_ROUTING 0
+#define HOOK_POST_ROUTING 4
+
+static __u32 em_ipt_hook(struct nlmsghdr *n)
+{
+ struct tcmsg *t = NLMSG_DATA(n);
+
+ if (t->tcm_parent != TC_H_ROOT &&
+ t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
+ return HOOK_PRE_ROUTING;
+
+ return HOOK_POST_ROUTING;
+}
+
+static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
+ struct tcf_ematch_hdr *hdr,
+ int argc, char **argv)
+{
+ struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
+ struct xtables_match *match = NULL;
+ __u8 nfproto = NFPROTO_IPV4;
+
+ while (1) {
+ struct option *opts;
+ int c;
+
+ c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
+ NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'm':
+ xtables_init_all(&tmp_tcipt_globals, nfproto);
+
+ match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
+ if (!match || !match->x6_parse) {
+ fprintf(stderr, " failed to find match %s\n\n",
+ optarg);
+ return -1;
+ }
+
+ match->m = fake_xt_entry_match(match->size, NULL);
+ if (!match->m) {
+ printf(" %s error\n", match->name);
+ return -1;
+ }
+
+ if (match->init)
+ match->init(match->m);
+
+ opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
+ tmp_tcipt_globals.opts,
+ match->x6_options,
+ &match->option_offset);
+ if (!opts) {
+ scrub_match(match);
+ return -1;
+ }
+
+ tmp_tcipt_globals.opts = opts;
+ break;
+
+ case '6':
+ nfproto = NFPROTO_IPV6;
+ break;
+
+ default:
+ if (!match) {
+ fprintf(stderr, "failed to find match %s\n\n",
+ optarg);
+ return -1;
+
+ }
+ xtables_option_mpcall(c, argv, 0, match, NULL);
+ break;
+ }
+ }
+
+ if (!match) {
+ fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
+ return -1;
+ }
+
+ /* check that we passed the correct parameters to the match */
+ xtables_option_mfcall(match);
+
+ addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
+ addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
+ addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
+ addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
+ addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
+ addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
+ match->size);
+
+ xtables_free_opts(1);
+
+ scrub_match(match);
+ return 0;
+}
+
+static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
+ int data_len)
+{
+ struct rtattr *tb[TCA_EM_IPT_MAX + 1];
+ struct xtables_match *match;
+ const char *mname;
+ __u8 nfproto;
+
+ if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
+ return -1;
+
+ nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
+
+ xtables_init_all(&em_tc_ipt_globals, nfproto);
+
+ mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
+ match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
+ if (!match)
+ return -1;
+
+ match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
+ RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
+ if (!match->m)
+ return -1;
+
+ match->print(NULL, match->m, 0);
+
+ scrub_match(match);
+ return 0;
+}
+
+struct ematch_util ipt_ematch_util = {
+ .kind = "ipt",
+ .kind_num = TCF_EM_IPT,
+ .parse_eopt_argv = em_ipt_parse_eopt_argv,
+ .print_eopt = em_ipt_print_epot,
+ .print_usage = em_ipt_print_usage
+};
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
while (argc > 0) {
if (matches(*argv, "map") == 0) {
addattr32(n, 4096, TCA_FLOW_XOR, xor);
}
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
return 0;
}
static struct flag_to_string flags_str[] = {
{ TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOWER_IP_FLAGS, "frag" },
+ { TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, FLOWER_IP_FLAGS, "firstfrag" },
};
static int flower_parse_matching_flags(char *str,
if (argc == 0)
return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
if (mask_set)
addattr32(n, MAX_MSG, TCA_FW_MASK, mask);
}
argc--; argv++;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
if (argc == 0)
return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
while (argc > 0) {
if (matches(*argv, "to") == 0) {
}
argc--; argv++;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
if (order) {
fh &= ~0x7F00;
fh |= (order<<8)&0x7F00;
if (argc == 0)
return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
while (argc > 0) {
if (matches(*argv, "session") == 0) {
if (pinfo_ok)
addattr_l(n, 4096, TCA_RSVP_PINFO, &pinfo, sizeof(pinfo));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
}
}
if (!argc) return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
while (argc) {
if (!strcmp(*argv, "hash")) {
int hash;
argc--;
argv++;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
#include "utils.h"
#include "tc_util.h"
-extern int show_pretty;
-
static void explain(void)
{
fprintf(stderr,
{
int i = 0;
- if (!show_pretty)
+ if (!pretty)
goto show_k;
for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
if (argc == 0)
return 0;
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, TCA_OPTIONS);
while (argc > 0) {
if (matches(*argv, "match") == 0) {
addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
if (argc <= 0)
return -1;
- tail = tail2 = NLMSG_TAIL(n);
-
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail2 = addattr_nest(n, MAX_MSG, tca_id);
while (argc > 0) {
goto bad_val;
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, ++prio, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, ++prio);
addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS,
addattr_l(n, MAX_MSG, TCA_ACT_COOKIE,
&act_ck, act_ck_len);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
ok++;
}
}
goto bad_val;
}
- tail2->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail2;
+ addattr_nest_end(n, tail2);
done:
*argc_p = argc;
argv += 1;
- tail = NLMSG_TAIL(&req.n);
- addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
+ tail = addattr_nest(&req.n, MAX_MSG, TCA_ACT_TAB);
while (argc > 0) {
if (strcmp(*argv, "action") == 0) {
goto bad_val;
}
- tail2 = NLMSG_TAIL(&req.n);
- addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
+ tail2 = addattr_nest(&req.n, MAX_MSG, ++prio);
addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
if (i > 0)
addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
- tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
+ addattr_nest_end(&req.n, tail2);
}
- tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+ addattr_nest_end(&req.n, tail);
req.n.nlmsg_seq = rth.dump = ++rth.seq;
.t.tca_family = AF_UNSPEC,
};
- tail = NLMSG_TAIL(&req.n);
- addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
+ tail = addattr_nest(&req.n, MAX_MSG, TCA_ACT_TAB);
tail2 = NLMSG_TAIL(&req.n);
strncpy(k, *argv, sizeof(k) - 1);
addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
- tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+ addattr_nest_end(&req.n, tail);
tail3 = NLMSG_TAIL(&req.n);
flag_select.value |= TCA_FLAG_LARGE_DUMP_ON;
NEXT_ARG();
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
while (argc > 0) {
if (matches(*argv, "run") == 0) {
}
addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
if (bpf_uds_name)
ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_CONNMARK_PARMS, &sel, sizeof(sel));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
return get_ematch_kind(name);
}
+static int em_parse_call(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
+ struct ematch_util *e, struct ematch *t)
+{
+ if (e->parse_eopt_argv) {
+ int argc = 0, i = 0, ret;
+ struct bstr *args;
+ char **argv;
+
+ for (args = t->args; args; args = bstr_next(args))
+ argc++;
+ argv = calloc(argc, sizeof(char *));
+ if (!argv)
+ return -1;
+ for (args = t->args; args; args = bstr_next(args))
+ argv[i++] = args->data;
+
+ ret = e->parse_eopt_argv(n, hdr, argc, argv);
+
+ free(argv);
+ return ret;
+ }
+
+ return e->parse_eopt(n, hdr, t->args->next);
+}
+
static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
{
int index = 1;
struct ematch *t;
for (t = tree; t; t = t->next) {
- struct rtattr *tail = NLMSG_TAIL(n);
+ struct rtattr *tail;
struct tcf_ematch_hdr hdr = { .flags = t->relation };
if (t->inverted)
hdr.flags |= TCF_EM_INVERT;
- addattr_l(n, MAX_MSG, index++, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, index++);
if (t->child) {
__u32 r = t->child_ref;
}
hdr.kind = num;
- if (e->parse_eopt(n, &hdr, t->args->next) < 0)
+ if (em_parse_call(n, &hdr, e, t) < 0)
return -1;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
}
return 0;
.progid = TCF_EM_PROG_TC
};
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
- tail_list = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);
+ tail_list = addattr_nest(n, MAX_MSG, TCA_EMATCH_TREE_LIST);
if (parse_tree(n, ematch_root) < 0)
return -1;
- tail_list->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail_list;
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail_list);
+ addattr_nest_end(n, tail);
}
*argc_p = ematch_argc;
int kind_num;
int (*parse_eopt)(struct nlmsghdr *,struct tcf_ematch_hdr *,
struct bstr *);
+ int (*parse_eopt_argv)(struct nlmsghdr *, struct tcf_ematch_hdr *,
+ int, char **);
int (*print_eopt)(FILE *, struct tcf_ematch_hdr *, void *, int);
void (*print_usage)(FILE *);
struct ematch_util *next;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p));
#ifdef CONFIG_GACT_PROB
if (rd)
addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp));
#endif
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
ife_usage();
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p));
if (!(p.flags & IFE_ENCODE))
if (saddr)
addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN);
- tail2 = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0);
+ tail2 = addattr_nest(n, MAX_MSG, TCA_IFE_METALST);
if (ife_mark || ife_mark_v) {
if (ife_mark_v)
addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4);
addattr_l(n, MAX_MSG, IFE_META_TCINDEX, NULL, 0);
}
- tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2;
+ addattr_nest_end(n, tail2);
skip_encode:
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
fprintf(stdout, "\ttarget: ");
addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
if (m)
addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
argc -= optind;
argv += optind;
ll_init_map(&rth);
idx = ll_name_to_index(d);
- if (idx == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ if (!idx)
+ return nodev(d);
p.ifindex = idx;
}
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
if (!sel.extended) {
addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
sizeof(sel.sel) +
pedit_keys_ex_addattr(&sel, n);
}
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p));
if (p.rate.rate)
addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024);
if (presult)
addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
res = 0;
*argc_p = argc;
usage();
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_SAMPLE_PARMS, &p, sizeof(p));
if (rate_set)
addattr32(n, MAX_MSG, TCA_SAMPLE_RATE, rate);
if (trunc_set)
addattr32(n, MAX_MSG, TCA_SAMPLE_TRUNC_SIZE, trunc);
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
sel.action = TC_ACT_PIPE;
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel));
if (simpdata)
addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
if (flags & SKBEDIT_F_QUEUE_MAPPING)
addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
if (flags & SKBEDIT_F_PTYPE)
addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE,
&ptype, sizeof(ptype));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
skbmod_usage();
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_SKBMOD_PARMS, &p, sizeof(p));
if (daddr)
if (saddr)
addattr_l(n, MAX_MSG, TCA_SKBMOD_SMAC, sbuf, ETH_ALEN);
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
if (matches(*argv, "tunnel_key") != 0)
return -1;
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
NEXT_ARG();
parm.t_action = action;
addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
parm.v_action = action;
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm));
if (id_set)
addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2);
if (prio_set)
addattr8(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
- tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+ addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
fprintf(stdout, "\ttarget: ");
addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
if (m)
addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
argv += optind;
*argc_p -= argc;
}
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+ tail = addattr_nest(n, MAX_MSG, tca_id);
fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
fprintf(stdout, "\ttarget: ");
addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
if (m)
addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
argc -= optind;
argv += optind;
perror("ioctl ATMARP_MKIP");
return -1;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s));
- if (excess) addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
- if (hdr_len != -1) addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ if (excess)
+ addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
+ if (hdr_len != -1)
+ addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
+ addattr_nest_end(n, tail);
return 0;
}
lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
lss.avpkt = avpkt;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
printf("%u ", rtab[i]);
printf("\n");
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
lss.change |= TCF_CBQ_LSS_EWMA;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (lss.change) {
lss.change |= TCF_CBQ_LSS_FLAGS;
addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
printf("\n");
}
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 2024, TCA_CBS_PARMS, &opt, sizeof(opt));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
if (ecn_ok)
opt.flags |= TC_RED_ECN;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_CHOKE_PARMS, &opt, sizeof(opt));
addattr_l(n, 1024, TCA_CHOKE_STAB, sbuf, 256);
max_P = probability * pow(2, 32);
addattr_l(n, 1024, TCA_CHOKE_MAX_P, &max_P, sizeof(max_P));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (limit)
addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit));
if (interval)
addattr_l(n, 1024, TCA_CODEL_CE_THRESHOLD,
&ce_threshold, sizeof(ce_threshold));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
struct rtattr *tail;
__u32 tmp;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
while (argc > 0) {
if (strcmp(*argv, "quantum") == 0) {
argc--; argv++;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
return 0;
}
explain();
return -1;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_DSMARK_INDICES, &ind, sizeof(ind));
if (dflt != -1) {
__u16 tmp = dflt;
addattr_l(n, 1024, TCA_DSMARK_DEFAULT_INDEX, &tmp, sizeof(tmp));
}
- if (set_tc_index) addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ if (set_tc_index)
+ addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0);
+ addattr_nest_end(n, tail);
return 0;
}
__u8 tmp;
char *end;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
while (argc > 0) {
if (!strcmp(*argv, "mask")) {
NEXT_ARG();
argc--;
argv++;
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (buckets) {
unsigned int log = ilog2(buckets);
if (set_orphan_mask)
addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
&orphan_mask, sizeof(refill_delay));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
static void explain(void)
{
fprintf(stderr, "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n");
+ fprintf(stderr, " [ memory_limit BYTES ]\n");
fprintf(stderr, " [ target TIME ] [ interval TIME ]\n");
fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n");
fprintf(stderr, " [ ce_threshold TIME ]\n");
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (limit)
addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit));
if (flows)
addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT,
&memory, sizeof(memory));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
st = &_st;
}
if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) {
- fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u",
- st->qdisc_stats.maxpacket,
- st->qdisc_stats.drop_overlimit,
- st->qdisc_stats.new_flow_count,
+ print_uint(PRINT_ANY, "maxpacket", " maxpacket %u",
+ st->qdisc_stats.maxpacket);
+ print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u",
+ st->qdisc_stats.drop_overlimit);
+ print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u",
+ st->qdisc_stats.new_flow_count);
+ print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u",
st->qdisc_stats.ecn_mark);
if (st->qdisc_stats.ce_mark)
- fprintf(f, " ce_mark %u", st->qdisc_stats.ce_mark);
+ print_uint(PRINT_ANY, "ce_mark", " ce_mark %u",
+ st->qdisc_stats.ce_mark);
if (st->qdisc_stats.memory_usage)
- fprintf(f, " memory_used %u", st->qdisc_stats.memory_usage);
+ print_uint(PRINT_ANY, "memory_used", " memory_used %u",
+ st->qdisc_stats.memory_usage);
if (st->qdisc_stats.drop_overmemory)
- fprintf(f, " drop_overmemory %u", st->qdisc_stats.drop_overmemory);
- fprintf(f, "\n new_flows_len %u old_flows_len %u",
- st->qdisc_stats.new_flows_len,
+ print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u",
+ st->qdisc_stats.drop_overmemory);
+ print_uint(PRINT_ANY, "new_flows_len", "\n new_flows_len %u",
+ st->qdisc_stats.new_flows_len);
+ print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u",
st->qdisc_stats.old_flows_len);
}
if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) {
- fprintf(f, " deficit %d count %u lastcount %u ldelay %s",
- st->class_stats.deficit,
- st->class_stats.count,
- st->class_stats.lastcount,
+ print_uint(PRINT_ANY, "deficit", " deficit %u",
+ st->class_stats.deficit);
+ print_uint(PRINT_ANY, "count", " count %u",
+ st->class_stats.count);
+ print_uint(PRINT_ANY, "lastcount", " lastcount %u",
+ st->class_stats.lastcount);
+ print_uint(PRINT_JSON, "ldelay", NULL,
+ st->class_stats.ldelay);
+ print_string(PRINT_FP, NULL, " ldelay %s",
sprint_time(st->class_stats.ldelay, b1));
if (st->class_stats.dropping) {
- fprintf(f, " dropping");
+ print_bool(PRINT_ANY, "dropping", " dropping", true);
if (st->class_stats.drop_next < 0)
- fprintf(f, " drop_next -%s",
+ print_string(PRINT_FP, NULL, " drop_next -%s",
sprint_time(-st->class_stats.drop_next, b1));
- else
- fprintf(f, " drop_next %s",
+ else {
+ print_uint(PRINT_JSON, "drop_next", NULL,
+ st->class_stats.drop_next);
+ print_string(PRINT_FP, NULL, " drop_next %s",
sprint_time(st->class_stats.drop_next, b1));
+ }
}
}
return 0;
DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n", opt.DPs, opt.def_DP);
n->nlmsg_flags |= NLM_F_CREATE;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_GRED_DPS, &opt, sizeof(struct tc_gred_sopt));
if (limit)
addattr32(n, 1024, TCA_GRED_LIMIT, limit);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
/*
}
opt.Scell_log = parm;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_GRED_PARMS, &opt, sizeof(opt));
addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
max_P = probability * pow(2, 32);
addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
return -1;
}
- tail = NLMSG_TAIL(n);
-
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (rsc_ok)
addattr_l(n, 1024, TCA_HFSC_RSC, &rsc, sizeof(rsc));
if (fsc_ok)
if (usc_ok)
addattr_l(n, 1024, TCA_HFSC_USC, &usc, sizeof(usc));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (limit)
addattr_l(n, 1024, TCA_HHF_BACKLOG_LIMIT, &limit,
sizeof(limit));
if (non_hh_weight)
addattr_l(n, 1024, TCA_HHF_NON_HH_WEIGHT, &non_hh_weight,
sizeof(non_hh_weight));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 2024, TCA_HTB_INIT, &opt, NLMSG_ALIGN(sizeof(opt)));
if (direct_qlen != ~0U)
addattr_l(n, 2024, TCA_HTB_DIRECT_QLEN,
&direct_qlen, sizeof(direct_qlen));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
}
opt.cbuffer = tc_calc_xmittime(ceil64, cbuffer);
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (rate64 >= (1ULL << 32))
addattr_l(n, 1124, TCA_HTB_RATE64, &rate64, sizeof(rate64));
addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt));
addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024);
addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024);
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
argc--; argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+ tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
if (flags & TC_MQPRIO_F_MODE)
addattr_l(n, 1024, TCA_MQPRIO_MODE,
addattr_nest_end(n, start);
}
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_compat_end(n, tail);
return 0;
}
}
}
- tail = NLMSG_TAIL(n);
-
if (reorder.probability) {
if (opt.latency == 0) {
fprintf(stderr, "reordering not possible without specifying some delay\n");
return -1;
}
- if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
- return -1;
+ tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
if (present[TCA_NETEM_CORR] &&
addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
return -1;
free(dist_data);
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_compat_end(n, tail);
return 0;
}
argv++;
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
if (limit)
addattr_l(n, 1024, TCA_PIE_LIMIT, &limit, sizeof(limit));
if (tupdate)
addattr_l(n, 1024, TCA_PIE_BYTEMODE, &bytemode,
sizeof(bytemode));
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
return 0;
}
struct rtattr *tail;
__u32 tmp;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 4096, TCA_OPTIONS);
while (argc > 0) {
if (matches(*argv, "weight") == 0) {
argc--; argv++;
}
- tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+ addattr_nest_end(n, tail);
return 0;
}
}
opt.Scell_log = parm;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt));
addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256);
max_P = probability * pow(2, 32);
addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
if (opt.bin_size == 0)
opt.bin_size = (opt.max * 4 + 3) / 5;
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 1024, TCA_SFB_PARMS, &opt, sizeof(opt));
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
opt.mtu = tc_calc_xmittime(opt.peakrate.rate, mtu);
}
- tail = NLMSG_TAIL(n);
- addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 2024, TCA_TBF_PARMS, &opt, sizeof(opt));
addattr_l(n, 2124, TCA_TBF_BURST, &buffer, sizeof(buffer));
if (rate64 >= (1ULL << 32))
addattr_l(n, 3224, TCA_TBF_PBURST, &mtu, sizeof(mtu));
addattr_l(n, 4096, TCA_TBF_PTAB, ptab, 1024);
}
- tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ addattr_nest_end(n, tail);
return 0;
}
int show_stats;
int show_details;
int show_raw;
-int show_pretty;
int show_graph;
int timestamp;
int force;
bool use_names;
int json;
+int color;
static char *conf_file;
static void usage(void)
{
fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
- " tc [-force] -batch filename\n"
- "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
- " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n"
- " -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n");
+ " tc [-force] -batch filename\n"
+ "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
+ " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [filename] | -n[etns] name |\n"
+ " -nm | -nam[es] | { -cf | -conf } path } |\n"
+ " -j[son] -p[retty] -c[olor]\n");
}
static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
} else if (matches(argv[1], "-raw") == 0) {
++show_raw;
} else if (matches(argv[1], "-pretty") == 0) {
- ++show_pretty;
+ ++pretty;
} else if (matches(argv[1], "-graph") == 0) {
show_graph = 1;
} else if (matches(argv[1], "-Version") == 0) {
matches(argv[1], "-conf") == 0) {
NEXT_ARG();
conf_file = argv[1];
+ } else if (matches(argv[1], "-color") == 0) {
+ ++color;
} else if (matches(argv[1], "-timestamp") == 0) {
timestamp++;
} else if (matches(argv[1], "-tshort") == 0) {
argc--; argv++;
}
+ if (color & !json)
+ enable_color();
+
if (batch_file)
return batch(batch_file);
if (d[0]) {
ll_init_map(&rth);
- if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ req.t.tcm_ifindex = ll_name_to_index(d);
+ if (!req.t.tcm_ifindex)
+ return -nodev(d);
}
if (rtnl_talk(&rth, &req.n, NULL) < 0)
ll_init_map(&rth);
if (d[0]) {
- if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ t.tcm_ifindex = ll_name_to_index(d);
+ if (!t.tcm_ifindex)
+ return -nodev(d);
filter_ifindex = t.tcm_ifindex;
}
ll_init_map(&rth);
req->t.tcm_ifindex = ll_name_to_index(d);
- if (req->t.tcm_ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ if (!req->t.tcm_ifindex)
+ return -nodev(d);
} else if (block_index) {
req->t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
req->t.tcm_block_index = block_index;
t->tcm_block_index);
} else {
if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
- print_string(PRINT_ANY, "dev", "dev %s ",
- ll_index_to_name(t->tcm_ifindex));
+ print_devname(PRINT_ANY, t->tcm_ifindex);
if (!filter_parent || filter_parent != t->tcm_parent) {
if (t->tcm_parent == TC_H_ROOT)
ll_init_map(&rth);
req.t.tcm_ifindex = ll_name_to_index(d);
- if (req.t.tcm_ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ if (!req.t.tcm_ifindex)
+ return -nodev(d);
filter_ifindex = req.t.tcm_ifindex;
} else if (block_index) {
req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
if (d[0]) {
req.t.tcm_ifindex = ll_name_to_index(d);
- if (req.t.tcm_ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ if (!req.t.tcm_ifindex)
+ return -nodev(d);
filter_ifindex = req.t.tcm_ifindex;
} else if (block_index) {
if (!tc_qdisc_block_exists(block_index)) {
return -1;
}
- tail = NLMSG_TAIL(&req.n);
- addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
+ tail = addattr_nest(&req.n, sizeof(req), TCA_STAB);
addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
sizeof(stab.szopts));
if (stab.data)
addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
stab.szopts.tsize * sizeof(__u16));
- tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
+ addattr_nest_end(&req.n, tail);
if (stab.data)
free(stab.data);
}
ll_init_map(&rth);
idx = ll_name_to_index(d);
- if (idx == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ if (!idx)
+ return -nodev(d);
req.t.tcm_ifindex = idx;
}
print_string(PRINT_FP, NULL, " ", NULL);
if (filter_ifindex == 0)
- print_string(PRINT_ANY, "dev", "dev %s ",
- ll_index_to_name(t->tcm_ifindex));
+ print_devname(PRINT_ANY, t->tcm_ifindex);
if (t->tcm_parent == TC_H_ROOT)
print_bool(PRINT_ANY, "root", "root ", true);
if (d[0]) {
t.tcm_ifindex = ll_name_to_index(d);
- if (t.tcm_ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return 1;
- }
+ if (!t.tcm_ifindex)
+ return -nodev(d);
filter_ifindex = t.tcm_ifindex;
}
return 0;
}
+void print_devname(enum output_type type, int ifindex)
+{
+ const char *ifname = ll_index_to_name(ifindex);
+
+ if (!is_json_context())
+ printf("dev ");
+
+ print_color_string(type, COLOR_IFNAME,
+ "dev", "%s ", ifname);
+}
+
void print_size(char *buf, int len, __u32 sz)
{
double tmp = sz;
void print_qdisc_handle(char *buf, int len, __u32 h);
void print_time(char *buf, int len, __u32 time);
void print_linklayer(char *buf, int len, unsigned int linklayer);
+void print_devname(enum output_type type, int ifindex);
char *sprint_rate(__u64 rate, char *buf);
char *sprint_size(__u32 size, char *buf);