From: David Ahern <dsah...@gmail.com> Add a filter function to rtnl_addrdump_req to set device index in the address dump request if the user is filtering addresses by device. In addition, add a new ipaddr_link_get to do a single RTM_GETLINK request instead of a device dump yet still store the data in the linfo list.
Signed-off-by: David Ahern <dsah...@gmail.com> --- include/libnetlink.h | 3 ++- ip/ipaddress.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------- lib/libnetlink.c | 12 ++++++++++- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/include/libnetlink.h b/include/libnetlink.h index b0051f390980..2621bc99ce7b 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -49,7 +49,8 @@ void rtnl_close(struct rtnl_handle *rth); typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen); -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) __attribute__((warn_unused_result)); int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family) __attribute__((warn_unused_result)); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 746dbfc58627..2bc33f3a3b3f 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -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,6 +1772,36 @@ 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 @@ -1784,7 +1824,7 @@ int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo) static int ip_addr_list(struct nlmsg_chain *ainfo) { - if (rtnl_addrdump_req(&rth, filter.family) < 0) { + if (rtnl_addrdump_req(&rth, filter.family, ipaddr_dump_filter) < 0) { perror("Cannot send dump request"); return 1; } @@ -1908,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); } @@ -1942,8 +1983,13 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) goto out; } - if (ip_link_list(iplink_filter_req, &linfo) != 0) - goto out; + 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 (filter.family != AF_PACKET) { if (filter.oneline) @@ -1972,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; diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 56a1cadeb3db..0ddd646a8775 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -234,11 +234,13 @@ 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 = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), .nlh.nlmsg_type = RTM_GETADDR, @@ -247,6 +249,14 @@ int rtnl_addrdump_req(struct rtnl_handle *rth, int family) .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); } -- 2.11.0