" [ from ADDRESS iif STRING ]\n"
" [ oif STRING ] [ tos TOS ]\n"
" [ mark NUMBER ] [ vrf NAME ]\n"
- " [ uid NUMBER ]\n"
+ " [ uid NUMBER ] [ ipproto PROTOCOL ]\n"
+ " [ sport NUMBER ] [ dport NUMBER ]\n"
" ip route { add | del | change | append | replace } ROUTE\n"
"SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n"
" [ table TABLE_ID ] [ vrf NAME ] [ proto RTPROTO ]\n"
" [ 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 | ipx | dnet | mpls | bridge | link ]\n"
+ "FAMILY := [ inet | inet6 | mpls | bridge | link ]\n"
"OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
" [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
" [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\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"
if (features)
print_0xhex(PRINT_ANY,
- "features", "0x%x ", of);
+ "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));
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)
hz = get_user_hz();
if (ci->rta_expires != 0)
- print_uint(PRINT_ANY, "expires",
- "expires %usec ", ci->rta_expires/hz);
+ print_int(PRINT_ANY, "expires",
+ "expires %dsec ", ci->rta_expires/hz);
if (ci->rta_error != 0)
print_uint(PRINT_ANY, "error",
"error %u ", ci->rta_error);
}
if (ci->rta_id)
print_0xhex(PRINT_ANY, "ipid",
- "ipid 0x%04x ", ci->rta_id);
+ "ipid 0x%04llx ", ci->rta_id);
if (ci->rta_ts || ci->rta_tsage) {
print_0xhex(PRINT_ANY, "ts",
- "ts 0x%x", ci->rta_ts);
+ "ts 0x%llx", ci->rta_ts);
print_uint(PRINT_ANY, "tsage",
"tsage %usec ", ci->rta_tsage);
}
}
}
-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;
- while (len > sizeof(*nh)) {
+ 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(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int print_route(struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct rtmsg *r = NLMSG_DATA(n);
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]);
print_uint(PRINT_JSON, "mark", NULL, mark);
else if (mark >= 16)
print_0xhex(PRINT_FP, NULL,
- "mark 0x%x ", mark);
+ "mark 0x%llx ", mark);
else
print_uint(PRINT_FP, NULL,
"mark %u ", mark);
rta_getattr_u32(tb[RTA_UID]));
if (r->rtm_family == AF_INET) {
- if (r->rtm_flags & RTM_F_CLONED) {
+ if (r->rtm_flags & RTM_F_CLONED)
print_cache_flags(fp, r->rtm_flags);
- if (tb[RTA_CACHEINFO])
- print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
- }
+ if (tb[RTA_CACHEINFO])
+ print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
} else if (r->rtm_family == AF_INET6) {
- if (r->rtm_flags & RTM_F_CLONED) {
- if (tb[RTA_CACHEINFO])
- print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
- }
+ if (tb[RTA_CACHEINFO])
+ print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
}
if (tb[RTA_METRICS])
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]));
if (tb[RTA_TTL_PROPAGATE]) {
- bool propogate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
+ bool propagate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
if (is_json_context())
print_bool(PRINT_JSON, "ttl-propogate", NULL,
- propogate);
+ propagate);
else
print_string(PRINT_FP, NULL,
"ttl-propogate %s",
- propogate ? "enabled" : "disabled");
+ 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);
}
static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
- struct rtattr *rta, struct rtnexthop *rtnh,
+ struct rtattr *rta, size_t len, struct rtnexthop *rtnh,
int *argcp, char ***argvp)
{
int argc = *argcp;
if (r->rtm_family == AF_UNSPEC)
r->rtm_family = addr.family;
if (addr.family == r->rtm_family) {
- rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
- rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
+ if (rta_addattr_l(rta, len, RTA_GATEWAY,
+ &addr.data, addr.bytelen))
+ return -1;
+ rtnh->rtnh_len += sizeof(struct rtattr)
+ + addr.bytelen;
} else {
- rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
- rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2);
+ if (rta_addattr_l(rta, len, RTA_VIA,
+ &addr.family, addr.bytelen + 2))
+ return -1;
+ rtnh->rtnh_len += RTA_SPACE(addr.bytelen + 2);
}
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
NEXT_ARG();
if (get_rt_realms_or_raw(&realm, *argv))
invarg("\"realm\" value is invalid\n", *argv);
- rta_addattr32(rta, 4096, RTA_FLOW, realm);
+ if (rta_addattr32(rta, len, RTA_FLOW, realm))
+ return -1;
rtnh->rtnh_len += sizeof(struct rtattr) + 4;
} else if (strcmp(*argv, "encap") == 0) {
- int len = rta->rta_len;
+ int old_len = rta->rta_len;
- lwt_parse_encap(rta, 4096, &argc, &argv);
- rtnh->rtnh_len += rta->rta_len - len;
+ 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) {
inet_prefix addr;
if (strcmp(*argv, "to") == 0)
NEXT_ARG();
get_addr(&addr, *argv, r->rtm_family);
- rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data,
- addr.bytelen);
+ if (rta_addattr_l(rta, len, RTA_NEWDST,
+ &addr.data, addr.bytelen))
+ return -1;
rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
} else
break;
static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
int argc, char **argv)
{
- char buf[1024];
+ char buf[4096];
struct rtattr *rta = (void *)buf;
struct rtnexthop *rtnh;
memset(rtnh, 0, sizeof(*rtnh));
rtnh->rtnh_len = sizeof(*rtnh);
rta->rta_len += rtnh->rtnh_len;
- parse_one_nh(n, r, rta, rtnh, &argc, &argv);
+ if (parse_one_nh(n, r, rta, 4096, rtnh, &argc, &argv)) {
+ fprintf(stderr, "Error: cannot parse nexthop\n");
+ exit(-1);
+ }
rtnh = RTNH_NEXT(rtnh);
}
if (rta->rta_len > RTA_LENGTH(0))
- addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
+ return addattr_l(n, 4096, RTA_MULTIPATH,
+ RTA_DATA(rta), RTA_PAYLOAD(rta));
return 0;
}
struct {
struct nlmsghdr n;
struct rtmsg r;
- char buf[1024];
+ char buf[4096];
} req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
.n.nlmsg_flags = NLM_F_REQUEST | flags,
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
addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
}
- if (nhs_ok)
- parse_nexthops(&req.n, &req.r, argc, argv);
+ if (nhs_ok && parse_nexthops(&req.n, &req.r, argc, argv))
+ return -1;
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
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 rtnl_rtcache_request(struct rtnl_handle *rth, int family)
-{
- struct {
- struct nlmsghdr nlh;
- struct rtmsg rtm;
- } req = {
- .nlh.nlmsg_len = sizeof(req),
- .nlh.nlmsg_type = RTM_GETROUTE,
- .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST,
- .nlh.nlmsg_seq = rth->dump = ++rth->seq,
- .rtm.rtm_family = family,
- .rtm.rtm_flags = RTM_F_CLONED,
- };
- struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
-
- return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr));
-}
-
static int iproute_flush_cache(void)
{
#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
static __u32 route_dump_magic = 0x45311224;
-static int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n,
- void *arg)
+static int save_route(struct nlmsghdr *n, void *arg)
{
int ret;
int len = n->nlmsg_len;
return 0;
}
-static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
+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);
char flushb[4096-512];
int ret;
if (filter.cloned) {
- if (do_ipv6 != AF_INET6) {
+ if (family != AF_INET6) {
iproute_flush_cache();
if (show_stats)
printf("*** IPv4 routing cache is flushed.\n");
}
- if (do_ipv6 == AF_INET)
+ if (family == AF_INET)
return 0;
}
filter.flushe = sizeof(flushb);
for (;;) {
- if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+ if (rtnl_routedump_req(&rth, family, iproute_dump_filter) < 0) {
perror("Cannot send dump request");
return -2;
}
if (filter.flushed == 0) {
if (show_stats) {
if (round == 0 &&
- (!filter.cloned || do_ipv6 == AF_INET6))
+ (!filter.cloned || family == AF_INET6))
printf("Nothing to flush.\n");
else
printf("*** Flush is complete after %d round%s ***\n",
static int iproute_list_flush_or_save(int argc, char **argv, int action)
{
- int do_ipv6 = preferred_family;
+ int dump_family = preferred_family;
char *id = NULL;
char *od = NULL;
unsigned int mark = 0;
NEXT_ARG();
family = read_family(*argv);
if (family == AF_UNSPEC)
- family = do_ipv6;
+ family = dump_family;
else
NEXT_ARG();
get_prefix(&filter.rvia, *argv, family);
} else if (strcmp(*argv, "src") == 0) {
NEXT_ARG();
- get_prefix(&filter.rprefsrc, *argv, do_ipv6);
+ get_prefix(&filter.rprefsrc, *argv, dump_family);
} else if (matches(*argv, "realms") == 0) {
__u32 realm;
NEXT_ARG();
if (matches(*argv, "root") == 0) {
NEXT_ARG();
- get_prefix(&filter.rsrc, *argv, do_ipv6);
+ get_prefix(&filter.rsrc, *argv, dump_family);
} else if (matches(*argv, "match") == 0) {
NEXT_ARG();
- get_prefix(&filter.msrc, *argv, do_ipv6);
+ get_prefix(&filter.msrc, *argv, dump_family);
} else {
if (matches(*argv, "exact") == 0) {
NEXT_ARG();
}
- get_prefix(&filter.msrc, *argv, do_ipv6);
+ get_prefix(&filter.msrc, *argv, dump_family);
filter.rsrc = filter.msrc;
}
} else {
}
if (matches(*argv, "root") == 0) {
NEXT_ARG();
- get_prefix(&filter.rdst, *argv, do_ipv6);
+ get_prefix(&filter.rdst, *argv, dump_family);
} else if (matches(*argv, "match") == 0) {
NEXT_ARG();
- get_prefix(&filter.mdst, *argv, do_ipv6);
+ get_prefix(&filter.mdst, *argv, dump_family);
} else {
if (matches(*argv, "exact") == 0) {
NEXT_ARG();
}
- get_prefix(&filter.mdst, *argv, do_ipv6);
+ get_prefix(&filter.mdst, *argv, dump_family);
filter.rdst = filter.mdst;
}
}
argc--; argv++;
}
- if (do_ipv6 == AF_UNSPEC && filter.tb)
- do_ipv6 = AF_INET;
+ if (dump_family == AF_UNSPEC && filter.tb)
+ dump_family = AF_INET;
if (id || od) {
int idx;
filter.mark = mark;
if (action == IPROUTE_FLUSH)
- return iproute_flush(do_ipv6, filter_fn);
+ return iproute_flush(dump_family, filter_fn);
- if (!filter.cloned) {
- if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
- perror("Cannot send dump request");
- return -2;
- }
- } else {
- if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
- perror("Cannot send dump request");
- return -2;
- }
+ if (rtnl_routedump_req(&rth, dump_family, iproute_dump_filter) < 0) {
+ perror("Cannot send dump request");
+ return -2;
}
new_json_obj(json);
int fib_match = 0;
int from_ok = 0;
unsigned int mark = 0;
+ bool address_found = false;
iproute_reset_filter(0);
filter.cloned = 2;
req.r.rtm_family = addr.family;
addattr_l(&req.n, sizeof(req), RTA_NEWDST,
&addr.data, addr.bytelen);
+ } else if (matches(*argv, "sport") == 0) {
+ __be16 sport;
+
+ NEXT_ARG();
+ if (get_be16(&sport, *argv, 0))
+ invarg("invalid sport\n", *argv);
+ addattr16(&req.n, sizeof(req), RTA_SPORT, sport);
+ } else if (matches(*argv, "dport") == 0) {
+ __be16 dport;
+
+ NEXT_ARG();
+ if (get_be16(&dport, *argv, 0))
+ invarg("invalid dport\n", *argv);
+ addattr16(&req.n, sizeof(req), RTA_DPORT, dport);
+ } else if (matches(*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), RTA_IP_PROTO, ipproto);
} else {
inet_prefix addr;
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 (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
- req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
+ /* Only IPv4 supports the RTM_F_LOOKUP_TABLE flag */
+ if (req.r.rtm_family == AF_INET)
+ req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
if (fib_match)
req.r.rtm_flags |= RTM_F_FIB_MATCH;
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;
struct rtattr *tb[RTA_MAX+1];
- if (print_route(NULL, answer, (void *)stdout) < 0) {
+ if (print_route(answer, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
free(answer);
return -1;
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;
}
- if (print_route(NULL, answer, (void *)stdout) < 0) {
+ if (print_route(answer, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
free(answer);
return -1;
}
+ delete_json_obj();
free(answer);
return 0;
}
return memcmp(RTA_DATA(rta1), RTA_DATA(rta2), RTA_PAYLOAD(rta1));
}
-static int restore_handler(const struct sockaddr_nl *nl,
- struct rtnl_ctrl_data *ctrl,
+static int restore_handler(struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{
struct rtmsg *r = NLMSG_DATA(n);
return 0;
}
-static int show_handler(const struct sockaddr_nl *nl,
- struct rtnl_ctrl_data *ctrl,
+static int show_handler(struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{
- print_route(nl, n, stdout);
+ print_route(n, stdout);
return 0;
}