Merge branch 'strict-dumps' into iproute2-next
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
0c187b7f24
|
|
@ -97,6 +97,8 @@ static int batch(const char *name)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rtnl_set_strict_dump(&rth);
|
||||
|
||||
cmdlineno = 0;
|
||||
while (getcmdline(&line, &len, stdin) != -1) {
|
||||
char *largv[100];
|
||||
|
|
@ -205,6 +207,8 @@ main(int argc, char **argv)
|
|||
if (rtnl_open(&rth, 0) < 0)
|
||||
exit(1);
|
||||
|
||||
rtnl_set_strict_dump(&rth);
|
||||
|
||||
if (argc > 1)
|
||||
return do_cmd(argv[1], argc-1, argv+1);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,12 +46,17 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
|
|||
__attribute__((warn_unused_result));
|
||||
|
||||
void rtnl_close(struct rtnl_handle *rth);
|
||||
void rtnl_set_strict_dump(struct rtnl_handle *rth);
|
||||
|
||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
|
||||
typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
|
||||
|
||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family)
|
||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
||||
__attribute__((warn_unused_result));
|
||||
|
|
@ -71,8 +76,6 @@ int rtnl_linkdump_req(struct rtnl_handle *rth, int fam)
|
|||
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
|
||||
|
||||
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam,
|
||||
req_filter_fn_t fn)
|
||||
__attribute__((warn_unused_result));
|
||||
|
|
|
|||
2
ip/ip.c
2
ip/ip.c
|
|
@ -308,6 +308,8 @@ int main(int argc, char **argv)
|
|||
if (rtnl_open(&rth, 0) < 0)
|
||||
exit(1);
|
||||
|
||||
rtnl_set_strict_dump(&rth);
|
||||
|
||||
if (strlen(basename) > 2)
|
||||
return do_cmd(basename+2, argc, argv);
|
||||
|
||||
|
|
|
|||
|
|
@ -84,8 +84,7 @@ int do_seg6(int argc, char **argv);
|
|||
int iplink_get(char *name, __u32 filt_mask);
|
||||
int iplink_ifla_xstats(int argc, char **argv);
|
||||
|
||||
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
||||
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo);
|
||||
int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo);
|
||||
void free_nlmsg_chain(struct nlmsg_chain *info);
|
||||
|
||||
static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
|
||||
|
|
|
|||
|
|
@ -1679,6 +1679,15 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
|
|||
}
|
||||
}
|
||||
|
||||
static int ipaddr_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(nlh);
|
||||
|
||||
ifa->ifa_index = filter.ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipaddr_flush(void)
|
||||
{
|
||||
int round = 0;
|
||||
|
|
@ -1689,7 +1698,8 @@ static int ipaddr_flush(void)
|
|||
filter.flushe = sizeof(flushb);
|
||||
|
||||
while ((max_flush_loops == 0) || (round < max_flush_loops)) {
|
||||
if (rtnl_addrdump_req(&rth, filter.family) < 0) {
|
||||
if (rtnl_addrdump_req(&rth, filter.family,
|
||||
ipaddr_dump_filter) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -1762,12 +1772,41 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ipaddr_link_get(int index, struct nlmsg_chain *linfo)
|
||||
{
|
||||
struct iplink_req req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_GETLINK,
|
||||
.i.ifi_family = filter.family,
|
||||
.i.ifi_index = index,
|
||||
};
|
||||
__u32 filt_mask = RTEXT_FILTER_VF;
|
||||
struct nlmsghdr *answer;
|
||||
|
||||
if (!show_stats)
|
||||
filt_mask |= RTEXT_FILTER_SKIP_STATS;
|
||||
|
||||
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
|
||||
perror("Cannot send link request");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (store_nlmsg(answer, linfo) < 0) {
|
||||
fprintf(stderr, "Failed to process link information\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fills in linfo with link data and optionally ainfo with address info
|
||||
* caller can walk lists as desired and must call free_nlmsg_chain for
|
||||
* both when done
|
||||
*/
|
||||
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
||||
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
|
||||
int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo)
|
||||
{
|
||||
if (rtnl_linkdump_req_filter_fn(&rth, preferred_family,
|
||||
filter_fn) < 0) {
|
||||
|
|
@ -1780,16 +1819,19 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (ainfo) {
|
||||
if (rtnl_addrdump_req(&rth, family) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
return 1;
|
||||
}
|
||||
static int ip_addr_list(struct nlmsg_chain *ainfo)
|
||||
{
|
||||
if (rtnl_addrdump_req(&rth, filter.family, ipaddr_dump_filter) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1798,7 +1840,7 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
|||
static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||
{
|
||||
struct nlmsg_chain linfo = { NULL, NULL};
|
||||
struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = NULL;
|
||||
struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = &_ainfo;
|
||||
struct nlmsg_list *l;
|
||||
char *filter_dev = NULL;
|
||||
int no_link = 0;
|
||||
|
|
@ -1906,7 +1948,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
|||
if (ipadd_save_prep())
|
||||
exit(1);
|
||||
|
||||
if (rtnl_addrdump_req(&rth, preferred_family) < 0) {
|
||||
if (rtnl_addrdump_req(&rth, preferred_family,
|
||||
ipaddr_dump_filter) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -1940,19 +1983,23 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (filter.family != AF_PACKET) {
|
||||
ainfo = &_ainfo;
|
||||
|
||||
if (filter.oneline)
|
||||
no_link = 1;
|
||||
if (filter.ifindex) {
|
||||
if (ipaddr_link_get(filter.ifindex, &linfo) != 0)
|
||||
goto out;
|
||||
} else {
|
||||
if (ip_link_list(iplink_filter_req, &linfo) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ip_linkaddr_list(filter.family, iplink_filter_req,
|
||||
&linfo, ainfo) != 0)
|
||||
goto out;
|
||||
if (filter.family != AF_PACKET) {
|
||||
if (filter.oneline)
|
||||
no_link = 1;
|
||||
|
||||
if (ip_addr_list(ainfo) != 0)
|
||||
goto out;
|
||||
|
||||
if (filter.family != AF_PACKET)
|
||||
ipaddr_filter(&linfo, ainfo);
|
||||
}
|
||||
|
||||
for (l = linfo.head; l; l = l->next) {
|
||||
struct nlmsghdr *n = &l->h;
|
||||
|
|
@ -1971,8 +2018,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
|||
fflush(stdout);
|
||||
|
||||
out:
|
||||
if (ainfo)
|
||||
free_nlmsg_chain(ainfo);
|
||||
free_nlmsg_chain(ainfo);
|
||||
free_nlmsg_chain(&linfo);
|
||||
delete_json_obj();
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -220,21 +220,36 @@ void ipmroute_reset_filter(int ifindex)
|
|||
filter.iif = ifindex;
|
||||
}
|
||||
|
||||
static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (filter.tb) {
|
||||
err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mroute_list(int argc, char **argv)
|
||||
{
|
||||
char *id = NULL;
|
||||
int family;
|
||||
int family = preferred_family;
|
||||
|
||||
ipmroute_reset_filter(0);
|
||||
if (preferred_family == AF_UNSPEC)
|
||||
family = AF_INET;
|
||||
else
|
||||
family = AF_INET6;
|
||||
if (family == AF_INET) {
|
||||
if (family == AF_INET || family == AF_UNSPEC) {
|
||||
family = RTNL_FAMILY_IPMR;
|
||||
filter.af = RTNL_FAMILY_IPMR;
|
||||
filter.tb = RT_TABLE_DEFAULT; /* for backward compatibility */
|
||||
} else
|
||||
} else if (family == AF_INET6) {
|
||||
family = RTNL_FAMILY_IP6MR;
|
||||
filter.af = RTNL_FAMILY_IP6MR;
|
||||
} else {
|
||||
/* family does not have multicast routing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
filter.msrc.family = filter.mdst.family = family;
|
||||
|
||||
|
|
@ -283,7 +298,7 @@ static int mroute_list(int argc, char **argv)
|
|||
filter.iif = idx;
|
||||
}
|
||||
|
||||
if (rtnl_routedump_req(&rth, filter.af) < 0) {
|
||||
if (rtnl_routedump_req(&rth, filter.af, iproute_dump_filter) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
39
ip/ipneigh.c
39
ip/ipneigh.c
|
|
@ -40,6 +40,7 @@ static struct
|
|||
int flushp;
|
||||
int flushe;
|
||||
int master;
|
||||
int protocol;
|
||||
} filter;
|
||||
|
||||
static void usage(void) __attribute__((noreturn));
|
||||
|
|
@ -48,7 +49,7 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n"
|
||||
" { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");
|
||||
fprintf(stderr, " [ router ] [ extern_learn ]\n\n");
|
||||
fprintf(stderr, " [ router ] [ extern_learn ] [ protocol PROTO ]\n\n");
|
||||
fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
|
||||
fprintf(stderr, " [ vrf NAME ]\n\n");
|
||||
fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
|
||||
|
|
@ -148,6 +149,14 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
|
|||
NEXT_ARG();
|
||||
dev = *argv;
|
||||
dev_ok = 1;
|
||||
} else if (matches(*argv, "protocol") == 0) {
|
||||
__u32 proto;
|
||||
|
||||
NEXT_ARG();
|
||||
if (rtnl_rtprot_a2n(&proto, *argv))
|
||||
invarg("\"protocol\" value is invalid\n", *argv);
|
||||
if (addattr8(&req.n, sizeof(req), NDA_PROTOCOL, proto))
|
||||
return -1;
|
||||
} else {
|
||||
if (strcmp(*argv, "to") == 0) {
|
||||
NEXT_ARG();
|
||||
|
|
@ -244,6 +253,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
int len = n->nlmsg_len;
|
||||
struct rtattr *tb[NDA_MAX+1];
|
||||
static int logit = 1;
|
||||
__u8 protocol = 0;
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
||||
n->nlmsg_type != RTM_GETNEIGH) {
|
||||
|
|
@ -285,6 +295,12 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
|
||||
return 0;
|
||||
|
||||
if (tb[NDA_PROTOCOL])
|
||||
protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
|
||||
|
||||
if (filter.protocol && filter.protocol != protocol)
|
||||
return 0;
|
||||
|
||||
if (filter.unused_only && tb[NDA_CACHEINFO]) {
|
||||
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
|
||||
|
||||
|
|
@ -371,6 +387,13 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
if (r->ndm_state)
|
||||
print_neigh_state(r->ndm_state);
|
||||
|
||||
if (protocol) {
|
||||
SPRINT_BUF(b1);
|
||||
|
||||
print_string(PRINT_ANY, "protocol", " proto %s ",
|
||||
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
print_string(PRINT_FP, NULL, "\n", "");
|
||||
close_json_object();
|
||||
fflush(stdout);
|
||||
|
|
@ -458,9 +481,19 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
|||
if (state == 0)
|
||||
state = 0x100;
|
||||
filter.state |= state;
|
||||
} else if (strcmp(*argv, "proxy") == 0)
|
||||
} else if (strcmp(*argv, "proxy") == 0) {
|
||||
req.ndm.ndm_flags = NTF_PROXY;
|
||||
else {
|
||||
} else if (matches(*argv, "protocol") == 0) {
|
||||
__u32 prot;
|
||||
|
||||
NEXT_ARG();
|
||||
if (rtnl_rtprot_a2n(&prot, *argv)) {
|
||||
if (strcmp(*argv, "all"))
|
||||
invarg("invalid \"protocol\"\n", *argv);
|
||||
prot = 0;
|
||||
}
|
||||
filter.protocol = prot;
|
||||
} else {
|
||||
if (strcmp(*argv, "to") == 0) {
|
||||
NEXT_ARG();
|
||||
}
|
||||
|
|
|
|||
89
ip/iproute.c
89
ip/iproute.c
|
|
@ -1535,24 +1535,6 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|||
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"
|
||||
|
|
@ -1622,7 +1604,7 @@ static int save_route_prep(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
||||
static int iproute_flush(int family, rtnl_filter_t filter_fn)
|
||||
{
|
||||
time_t start = time(0);
|
||||
char flushb[4096-512];
|
||||
|
|
@ -1630,12 +1612,12 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -1644,7 +1626,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
|||
filter.flushe = sizeof(flushb);
|
||||
|
||||
for (;;) {
|
||||
if (rtnl_routedump_req(&rth, do_ipv6) < 0) {
|
||||
if (rtnl_routedump_req(&rth, family, NULL) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
return -2;
|
||||
}
|
||||
|
|
@ -1656,7 +1638,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
|||
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",
|
||||
|
|
@ -1684,9 +1666,33 @@ 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_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;
|
||||
|
|
@ -1805,13 +1811,13 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
|||
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;
|
||||
|
||||
|
|
@ -1831,15 +1837,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
|||
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 {
|
||||
|
|
@ -1848,23 +1854,23 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
|||
}
|
||||
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;
|
||||
|
|
@ -1887,18 +1893,11 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
|||
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_routedump_req(&rth, do_ipv6) < 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);
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ static int ipvrf_show(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (ip_linkaddr_list(0, ipvrf_filter_req, &linfo, NULL) == 0) {
|
||||
if (ip_link_list(ipvrf_filter_req, &linfo) == 0) {
|
||||
struct nlmsg_list *l;
|
||||
unsigned nvrf = 0;
|
||||
int n;
|
||||
|
|
|
|||
202
lib/libnetlink.c
202
lib/libnetlink.c
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include "libnetlink.h"
|
||||
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
|
@ -67,6 +69,14 @@ static int err_attr_cb(const struct nlattr *attr, void *data)
|
|||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static void print_ext_ack_msg(bool is_err, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
|
||||
if (msg[strlen(msg) - 1] != '.')
|
||||
fprintf(stderr, ".");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* dump netlink extended ack error message */
|
||||
int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
||||
{
|
||||
|
|
@ -108,12 +118,29 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
|||
if (msg && *msg != '\0') {
|
||||
bool is_err = !!err->error;
|
||||
|
||||
fprintf(stderr, "%s: %s",
|
||||
is_err ? "Error" : "Warning", msg);
|
||||
if (msg[strlen(msg) - 1] != '.')
|
||||
fprintf(stderr, ".");
|
||||
fprintf(stderr, "\n");
|
||||
print_ext_ack_msg(is_err, msg);
|
||||
return is_err ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
|
||||
{
|
||||
struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
|
||||
unsigned int hlen = sizeof(int);
|
||||
const char *msg = NULL;
|
||||
|
||||
if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
|
||||
return 0;
|
||||
|
||||
if (tb[NLMSGERR_ATTR_MSG])
|
||||
msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
|
||||
|
||||
if (msg && *msg != '\0') {
|
||||
bool is_err = !!error;
|
||||
|
||||
print_ext_ack_msg(is_err, msg);
|
||||
return is_err ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
@ -127,8 +154,22 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Older kernels may not support strict dump and filtering */
|
||||
void rtnl_set_strict_dump(struct rtnl_handle *rth)
|
||||
{
|
||||
int one = 1;
|
||||
|
||||
setsockopt(rth->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
|
||||
&one, sizeof(one));
|
||||
}
|
||||
|
||||
void rtnl_close(struct rtnl_handle *rth)
|
||||
{
|
||||
if (rth->fd >= 0) {
|
||||
|
|
@ -202,19 +243,29 @@ int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
|
|||
return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
|
||||
}
|
||||
|
||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
|
||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifaddrmsg ifm;
|
||||
char buf[128];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETADDR,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.ifm.ifa_family = family,
|
||||
};
|
||||
|
||||
if (filter_fn) {
|
||||
int err;
|
||||
|
||||
err = filter_fn(&req.nlh, sizeof(req));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +275,7 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
|||
struct nlmsghdr nlh;
|
||||
struct ifaddrlblmsg ifal;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETADDRLABEL,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -234,19 +285,29 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
|||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family)
|
||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
char buf[128];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETROUTE,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.rtm.rtm_family = family,
|
||||
};
|
||||
|
||||
if (filter_fn) {
|
||||
int err;
|
||||
|
||||
err = filter_fn(&req.nlh, sizeof(req));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +317,7 @@ int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
|||
struct nlmsghdr nlh;
|
||||
struct fib_rule_hdr frh;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
|
||||
.nlh.nlmsg_type = RTM_GETRULE,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -272,7 +333,7 @@ int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
|
|||
struct nlmsghdr nlh;
|
||||
struct ndmsg ndm;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETNEIGH,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -288,7 +349,7 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
|
|||
struct nlmsghdr nlh;
|
||||
struct ndtmsg ndtmsg;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETNEIGHTBL,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -304,7 +365,7 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
|
|||
struct nlmsghdr nlh;
|
||||
struct br_port_msg bpm;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
|
||||
.nlh.nlmsg_type = RTM_GETMDB,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -319,8 +380,9 @@ int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
|
|||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct netconfmsg ncm;
|
||||
char buf[0] __aligned(NLMSG_ALIGNTO);
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg))),
|
||||
.nlh.nlmsg_type = RTM_GETNETCONF,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -335,8 +397,9 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
|
|||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtgenmsg rtm;
|
||||
char buf[0] __aligned(NLMSG_ALIGNTO);
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
|
||||
.nlh.nlmsg_type = RTM_GETNSID,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
|
|
@ -346,41 +409,11 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
|
|||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
||||
{
|
||||
return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
|
||||
}
|
||||
|
||||
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
|
||||
__u32 filt_mask)
|
||||
static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifinfomsg ifm;
|
||||
/* attribute has to be NLMSG aligned */
|
||||
struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
|
||||
__u32 ext_filter_mask;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_type = RTM_GETLINK,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.ifm.ifi_family = family,
|
||||
.ext_req.rta_type = IFLA_EXT_MASK,
|
||||
.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
|
||||
.ext_filter_mask = filt_mask,
|
||||
};
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifinfomsg ifm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.nlh.nlmsg_type = RTM_GETLINK,
|
||||
|
|
@ -388,16 +421,73 @@ int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
|||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.ifm.ifi_family = family,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!filter_fn)
|
||||
return -EINVAL;
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
err = filter_fn(&req.nlh, sizeof(req));
|
||||
if (err)
|
||||
return err;
|
||||
int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
||||
{
|
||||
if (family == AF_UNSPEC)
|
||||
return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
|
||||
|
||||
return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
|
||||
return __rtnl_linkdump_req(rth, family);
|
||||
}
|
||||
|
||||
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
|
||||
__u32 filt_mask)
|
||||
{
|
||||
if (family == AF_UNSPEC) {
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifinfomsg ifm;
|
||||
/* attribute has to be NLMSG aligned */
|
||||
struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
|
||||
__u32 ext_filter_mask;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = sizeof(req),
|
||||
.nlh.nlmsg_type = RTM_GETLINK,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.ifm.ifi_family = family,
|
||||
.ext_req.rta_type = IFLA_EXT_MASK,
|
||||
.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
|
||||
.ext_filter_mask = filt_mask,
|
||||
};
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
return __rtnl_linkdump_req(rth, family);
|
||||
}
|
||||
|
||||
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
{
|
||||
if (family == AF_UNSPEC) {
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifinfomsg ifm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.nlh.nlmsg_type = RTM_GETLINK,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.ifm.ifi_family = family,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!filter_fn)
|
||||
return -EINVAL;
|
||||
|
||||
err = filter_fn(&req.nlh, sizeof(req));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
|
||||
}
|
||||
|
||||
return __rtnl_linkdump_req(rth, family);
|
||||
}
|
||||
|
||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||
|
|
@ -512,6 +602,10 @@ static int rtnl_dump_done(struct nlmsghdr *h)
|
|||
}
|
||||
|
||||
if (len < 0) {
|
||||
/* check for any messages returned from kernel */
|
||||
if (nl_dump_ext_ack_done(h, len))
|
||||
return len;
|
||||
|
||||
errno = -len;
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
|
|
|
|||
Loading…
Reference in New Issue