Merge branch 'strict-dumps' into iproute2-next

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2018-12-27 15:37:44 -08:00
commit 0c187b7f24
10 changed files with 337 additions and 142 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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;

View File

@ -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: