" [ 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"
"TIME := NUMBER[s|ms]\n"
"BOOL := [1|0]\n"
"FEATURES := ecn\n"
- "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local ]\n"
+ "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl ]\n"
"ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n"
"SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n"
"SEGMODE := [ encap | inline ]\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 ", "pervasive");
if (flags & RTNH_F_OFFLOAD)
print_string(PRINT_ANY, NULL, "%s ", "offload");
+ if (flags & RTNH_F_TRAP)
+ print_string(PRINT_ANY, NULL, "%s ", "trap");
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");
+ 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));
}
}
-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 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)
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]);
if (tb[RTA_IIF] && filter.iifmask != -1)
print_rta_if(fp, tb[RTA_IIF], "iif");
- if (tb[RTA_MULTIPATH])
- print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
-
if (tb[RTA_PREF])
print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
propagate ? "enabled" : "disabled");
}
+ if (tb[RTA_MULTIPATH])
+ print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
+
+ /* If you are adding new route RTA_XXXX then place it above
+ * the RTA_MULTIPATH else it will appear that the last nexthop
+ * in the ECMP has new attributes
+ */
+
print_string(PRINT_FP, NULL, "\n", NULL);
close_json_object();
fflush(fp);
} 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;
}
}