diff mbox

[iproute2] ip link: Add support for kernel side filtering

Message ID 1462974718-12860-1-git-send-email-dsa@cumulusnetworks.com
State Accepted, archived
Delegated to: stephen hemminger
Headers show

Commit Message

David Ahern May 11, 2016, 1:51 p.m. UTC
Kernel gained support for filtering link dumps with commit dc599f76c22b
("net: Add support for filtering link dump by master device and kind").
Add support to ip link command. If a user passes master device or
kind to ip link command they are added to the link dump request message.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 include/libnetlink.h |  6 ++++++
 ip/ipaddress.c       | 33 ++++++++++++++++++++++++++++++++-
 lib/libnetlink.c     | 28 ++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletion(-)

Comments

Stephen Hemminger May 16, 2016, 6:19 p.m. UTC | #1
On Wed, 11 May 2016 06:51:58 -0700
David Ahern <dsa@cumulusnetworks.com> wrote:

> Kernel gained support for filtering link dumps with commit dc599f76c22b
> ("net: Add support for filtering link dump by master device and kind").
> Add support to ip link command. If a user passes master device or
> kind to ip link command they are added to the link dump request message.
> 
> Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
> ---
>  include/libnetlink.h |  6 ++++++
>  ip/ipaddress.c       | 33 ++++++++++++++++++++++++++++++++-
>  lib/libnetlink.c     | 28 ++++++++++++++++++++++++++++
>  3 files changed, 66 insertions(+), 1 deletion(-)
> 

Was this tested on older kernels?  Don't want to add something that breaks
when run on old kernels that are in stable distros.
David Ahern May 16, 2016, 6:27 p.m. UTC | #2
On 5/16/16 12:19 PM, Stephen Hemminger wrote:
> On Wed, 11 May 2016 06:51:58 -0700
> David Ahern <dsa@cumulusnetworks.com> wrote:
>
>> Kernel gained support for filtering link dumps with commit dc599f76c22b
>> ("net: Add support for filtering link dump by master device and kind").
>> Add support to ip link command. If a user passes master device or
>> kind to ip link command they are added to the link dump request message.
>>
>> Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
>> ---
>>  include/libnetlink.h |  6 ++++++
>>  ip/ipaddress.c       | 33 ++++++++++++++++++++++++++++++++-
>>  lib/libnetlink.c     | 28 ++++++++++++++++++++++++++++
>>  3 files changed, 66 insertions(+), 1 deletion(-)
>>
>
> Was this tested on older kernels?  Don't want to add something that breaks
> when run on old kernels that are in stable distros.
>

Yes. Not really far back but older 4.x kernels.

In general older kernels do not parse the attributes appended to the get 
request. This is very similar to the neigh filter added by 
b8c753245bad3f13a03b105b724ff406d278c753.
David Ahern May 16, 2016, 6:30 p.m. UTC | #3
On 5/16/16 12:27 PM, David Ahern wrote:
> In general older kernels do not parse the attributes appended to the get
> request.

sorry, wrong wording: the attributes are parsed but ignored. I just 
checked an older 3.4 kernel tree and that is true there as well as prior 
to the kernel commit for this feature.
diff mbox

Patch

diff --git a/include/libnetlink.h b/include/libnetlink.h
index 491263f7e103..f7b85dccef36 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -38,6 +38,12 @@  int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type)
 int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type,
 				    __u32 filt_mask)
 	__attribute__((warn_unused_result));
+
+typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
+
+int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type,
+				req_filter_fn_t fn)
+	__attribute__((warn_unused_result));
 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
 			     int len)
 	__attribute__((warn_unused_result));
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index aac7970e16dd..0692fbacd669 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1476,6 +1476,36 @@  static int ipaddr_flush(void)
 	return 1;
 }
 
+static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
+{
+	int err;
+
+	err = addattr32(nlh, reqlen, IFLA_EXT_MASK, RTEXT_FILTER_VF);
+	if (err)
+		return err;
+
+	if (filter.master) {
+		err = addattr32(nlh, reqlen, IFLA_MASTER, filter.master);
+		if (err)
+			return err;
+	}
+
+	if (filter.kind) {
+		struct rtattr *linkinfo;
+
+		linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
+
+		err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, filter.kind,
+				strlen(filter.kind));
+		if (err)
+			return err;
+
+		addattr_nest_end(nlh, linkinfo);
+	}
+
+	return 0;
+}
+
 static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
 {
 	struct nlmsg_chain linfo = { NULL, NULL};
@@ -1638,7 +1668,8 @@  static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
 		exit(0);
 	}
 
-	if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
+	if (rtnl_wilddump_req_filter_fn(&rth, preferred_family, RTM_GETLINK,
+					iplink_filter_req) < 0) {
 		perror("Cannot send dump request");
 		exit(1);
 	}
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index a90e52ca2c0a..0adcbf3f6e38 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -129,6 +129,34 @@  int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type,
 	return send(rth->fd, (void*)&req, sizeof(req), 0);
 }
 
+int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
+				req_filter_fn_t filter_fn)
+{
+	struct {
+		struct nlmsghdr nlh;
+		struct ifinfomsg ifm;
+		char buf[1024];
+	} req;
+	int err;
+
+	if (!filter_fn)
+		return -EINVAL;
+
+	memset(&req, 0, sizeof(req));
+	req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlh.nlmsg_type = type;
+	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+	req.ifm.ifi_family = family;
+
+	err = filter_fn(&req.nlh, sizeof(req));
+	if (err)
+		return err;
+
+	return send(rth->fd, (void*)&req, sizeof(req), 0);
+}
+
 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
 {
 	return send(rth->fd, buf, len, 0);