" [ table TABLE_ID ] [ proto RTPROTO ]\n"
" [ scope SCOPE ] [ metric METRIC ]\n"
" [ ttl-propagate { enabled | disabled } ]\n"
- "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"
+ "INFO_SPEC := { NH | nhid ID } OPTIONS FLAGS [ nexthop NH ]...\n"
"NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
" [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
"FAMILY := [ inet | inet6 | mpls | bridge | link ]\n"
"features", "%#llx ", of);
}
-static void print_rt_flags(FILE *fp, unsigned int flags)
+void print_rt_flags(FILE *fp, unsigned int flags)
{
open_json_array(PRINT_JSON,
is_json_context() ? "flags" : "");
print_string(PRINT_ANY, NULL, "%s ", "linkdown");
if (flags & RTNH_F_UNRESOLVED)
print_string(PRINT_ANY, NULL, "%s ", "unresolved");
+ if (flags & RTM_F_OFFLOAD)
+ print_string(PRINT_ANY, NULL, "%s ", "rt_offload");
+ if (flags & RTM_F_TRAP)
+ print_string(PRINT_ANY, NULL, "%s ", "rt_trap");
close_json_array(PRINT_JSON, NULL);
}
}
}
-static void print_rta_if(FILE *fp, const struct rtattr *rta,
- const char *prefix)
+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 (flags)
print_hex(PRINT_ANY, "flags", "%x>", flags);
- if (jw) {
+ if (jw)
jsonw_end_array(jw);
- jsonw_destroy(&jw);
- }
}
static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
}
}
-static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
- const struct rtattr *rta)
+void print_rta_gateway(FILE *fp, unsigned char family, const struct rtattr *rta)
{
- const char *gateway = format_host_rta(r->rtm_family, rta);
+ const char *gateway = format_host_rta(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),
+ ifa_family_color(family),
NULL, "%s ", gateway);
}
}
int i;
open_json_array(PRINT_JSON, "metrics");
+ open_json_object(NULL);
parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
print_rtax_features(fp, val);
break;
default:
- fprintf(fp, "%u ", val);
+ print_uint(PRINT_ANY, mx_names[i], "%u ", val);
break;
case RTAX_RTT:
}
}
+ close_json_object();
close_json_array(PRINT_JSON, NULL);
}
int len = RTA_PAYLOAD(rta);
int first = 1;
+ open_json_array(PRINT_JSON, "nexthops");
+
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_);
- }
+ open_json_object(NULL);
+
+ if ((r->rtm_flags & RTM_F_CLONED) &&
+ r->rtm_type == RTN_MULTICAST) {
+ if (first) {
+ print_string(PRINT_FP, NULL, "Oifs: ", NULL);
+ first = 0;
+ } else {
+ print_string(PRINT_FP, NULL, " ", NULL);
+ }
+ } else
+ print_string(PRINT_FP, NULL, "%s\tnexthop ", _SL_);
if (nh->rtnh_len > sizeof(*nh)) {
parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
if (tb[RTA_NEWDST])
print_rta_newdst(fp, r, tb[RTA_NEWDST]);
if (tb[RTA_GATEWAY])
- print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+ print_rta_gateway(fp, r->rtm_family,
+ tb[RTA_GATEWAY]);
if (tb[RTA_VIA])
print_rta_via(fp, tb[RTA_VIA]);
if (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));
+ print_string(PRINT_ANY, "dev",
+ "%s", ll_index_to_name(nh->rtnh_ifindex));
+
if (nh->rtnh_hops != 1)
- fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
- fprintf(fp, " ");
+ print_int(PRINT_ANY, "ttl", "(ttl>%d)", nh->rtnh_hops);
+
+ print_string(PRINT_FP, NULL, " ", NULL);
} else {
- fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
+ print_string(PRINT_ANY, "dev",
+ "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
+
if (r->rtm_family != AF_MPLS)
- fprintf(fp, "weight %d ",
- nh->rtnh_hops+1);
+ print_int(PRINT_ANY, "weight",
+ "weight %d ", nh->rtnh_hops + 1);
}
print_rt_flags(fp, nh->rtnh_flags);
len -= NLMSG_ALIGN(nh->rtnh_len);
nh = RTNH_NEXT(nh);
+
+ close_json_object();
}
+ close_json_array(PRINT_JSON, NULL);
}
int print_route(struct nlmsghdr *n, void *arg)
if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
(!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
- print_string(PRINT_ANY, NULL, "%s ",
+ print_string(PRINT_ANY, "type", "%s ",
rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
color = COLOR_NONE;
print_string(PRINT_ANY, "src", "from %s ", b1);
}
+ if (tb[RTA_NH_ID])
+ print_uint(PRINT_ANY, "nhid", "nhid %u ",
+ rta_getattr_u32(tb[RTA_NH_ID]));
+
if (tb[RTA_NEWDST])
print_rta_newdst(fp, r, tb[RTA_NEWDST]);
}
if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
- print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+ print_rta_gateway(fp, r->rtm_family, tb[RTA_GATEWAY]);
if (tb[RTA_VIA])
print_rta_via(fp, tb[RTA_VIA]);
} else if (strcmp(*argv, "encap") == 0) {
int old_len = rta->rta_len;
- if (lwt_parse_encap(rta, len, &argc, &argv))
+ if (lwt_parse_encap(rta, len, &argc, &argv,
+ RTA_ENCAP, RTA_ENCAP_TYPE))
return -1;
rtnh->rtnh_len += rta->rta_len - old_len;
} else if (strcmp(*argv, "as") == 0) {
int table_ok = 0;
int raw = 0;
int type_ok = 0;
+ __u32 nhid = 0;
if (cmd != RTM_DELROUTE) {
req.r.rtm_protocol = RTPROT_BOOT;
} else if (strcmp(*argv, "nexthop") == 0) {
nhs_ok = 1;
break;
+ } else if (!strcmp(*argv, "nhid")) {
+ NEXT_ARG();
+ if (get_u32(&nhid, *argv, 0))
+ invarg("\"id\" value is invalid\n", *argv);
+ addattr32(&req.n, sizeof(req), RTA_NH_ID, nhid);
} else if (matches(*argv, "protocol") == 0) {
__u32 prot;
rta->rta_type = RTA_ENCAP;
rta->rta_len = RTA_LENGTH(0);
- lwt_parse_encap(rta, sizeof(buf), &argc, &argv);
+ lwt_parse_encap(rta, sizeof(buf), &argc, &argv,
+ RTA_ENCAP, RTA_ENCAP_TYPE);
if (rta->rta_len > RTA_LENGTH(0))
addraw_l(&req.n, 1024
req.r.rtm_type == RTN_UNSPEC) {
if (cmd == RTM_DELROUTE)
req.r.rtm_scope = RT_SCOPE_NOWHERE;
- else if (!gw_ok && !nhs_ok)
+ else if (!gw_ok && !nhs_ok && !nhid)
req.r.rtm_scope = RT_SCOPE_LINK;
}
}
return 0;
}
+static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
+{
+ struct rtmsg *rtm = NLMSG_DATA(nlh);
+ int err;
+
+ rtm->rtm_protocol = filter.protocol;
+ if (filter.cloned)
+ rtm->rtm_flags |= RTM_F_CLONED;
+
+ if (filter.tb) {
+ err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
+ if (err)
+ return err;
+ }
+
+ if (filter.oif) {
+ err = addattr32(nlh, reqlen, RTA_OIF, filter.oif);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int iproute_flush(int family, rtnl_filter_t filter_fn)
{
time_t start = time(0);
filter.flushe = sizeof(flushb);
for (;;) {
- if (rtnl_routedump_req(&rth, family, NULL) < 0) {
+ if (rtnl_routedump_req(&rth, family, iproute_dump_filter) < 0) {
perror("Cannot send dump request");
return -2;
}
}
}
-static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
-{
- struct rtmsg *rtm = NLMSG_DATA(nlh);
- int err;
-
- rtm->rtm_protocol = filter.protocol;
- if (filter.cloned)
- rtm->rtm_flags |= RTM_F_CLONED;
-
- if (filter.tb) {
- err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
- if (err)
- return err;
- }
-
- if (filter.oif) {
- err = addattr32(nlh, reqlen, RTA_OIF, filter.oif);
- if (err)
- return err;
- }
-
- return 0;
-}
-
static int iproute_list_flush_or_save(int argc, char **argv, int action)
{
int dump_family = preferred_family;
int fib_match = 0;
int from_ok = 0;
unsigned int mark = 0;
+ bool address_found = false;
iproute_reset_filter(0);
filter.cloned = 2;
addattr_l(&req.n, sizeof(req),
RTA_DST, &addr.data, addr.bytelen);
req.r.rtm_dst_len = addr.bitlen;
+ address_found = true;
}
argc--; argv++;
}
- if (req.r.rtm_dst_len == 0) {
+ if (!address_found) {
fprintf(stderr, "need at least a destination address\n");
return -1;
}
if (rtnl_talk(&rth, &req.n, &answer) < 0)
return -2;
+ new_json_obj(json);
+
if (connected && !from_ok) {
struct rtmsg *r = NLMSG_DATA(answer);
int len = answer->nlmsg_len;
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE;
+ delete_json_obj();
free(answer);
if (rtnl_talk(&rth, &req.n, &answer) < 0)
return -2;
return -1;
}
+ delete_json_obj();
free(answer);
return 0;
}