diff mbox

[RFC] extend RTM_GETNEIGH to allow getting more precise information

Message ID 201001151842.59813.cratiu@ixiacom.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Cosmin Ratiu Jan. 15, 2010, 4:42 p.m. UTC
Hello.

Please have a look at this patch which tries to solve a problem we 
encountered.

The background is that RTM_GETNEIGH netlink message is used to get a complete 
dump of a neighbor table. Sometimes, that's too much (especially when you have 
a lot of neighbors). This patch allows one to specify the IPv4/6 address of a 
neighbor and the device index through which it is accessible in order to 
obtain only that entry.

If you have other suggestions on how to accomplish this task, please let us 
know.

Thanks,
Cosmin.

Comments

David Miller Jan. 23, 2010, 10:12 a.m. UTC | #1
From: Cosmin Ratiu <cratiu@ixiacom.com>
Date: Fri, 15 Jan 2010 18:42:59 +0200

> Please have a look at this patch which tries to solve a problem we 
> encountered.
> 
> The background is that RTM_GETNEIGH netlink message is used to get a complete 
> dump of a neighbor table. Sometimes, that's too much (especially when you have 
> a lot of neighbors). This patch allows one to specify the IPv4/6 address of a 
> neighbor and the device index through which it is accessible in order to 
> obtain only that entry.
> 
> If you have other suggestions on how to accomplish this task, please let us 
> know.

Please add a netlink attribute to specify lookup keys.

Adding specifiers to the end of the existing request message
error prone and creates trouble in the future if someone gets
the idea to add something more.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Patrick McHardy Jan. 25, 2010, 1:51 p.m. UTC | #2
David Miller wrote:
> From: Cosmin Ratiu <cratiu@ixiacom.com>
> Date: Fri, 15 Jan 2010 18:42:59 +0200
> 
>> Please have a look at this patch which tries to solve a problem we 
>> encountered.
>>
>> The background is that RTM_GETNEIGH netlink message is used to get a complete 
>> dump of a neighbor table. Sometimes, that's too much (especially when you have 
>> a lot of neighbors). This patch allows one to specify the IPv4/6 address of a 
>> neighbor and the device index through which it is accessible in order to 
>> obtain only that entry.
>>
>> If you have other suggestions on how to accomplish this task, please let us 
>> know.
> 
> Please add a netlink attribute to specify lookup keys.
> 
> Adding specifiers to the end of the existing request message
> error prone and creates trouble in the future if someone gets
> the idea to add something more.

It should also use a seperate callback for looking up individual
entries instead of the NLM_F_DUMP callback.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

From beb2cd45109f28b9067d7fa902e49cbbc7667ff5 Mon Sep 17 00:00:00 2001
From: Cosmin Ratiu <cratiu@ixiacom.com>
Date: Fri, 15 Jan 2010 18:34:39 +0200
Subject: [PATCH] Extend RTM_GETNEIGH to allow getting more precise information.

RTM_GETNEIGH makes a complete dump of the neighbour table for a given
net and address family. The patch allows requests for a single entry
by specifying the device and IP address. This should increase
performance when there are many neighbour entries and a specific one is
desired.

Signed-off-by: Pinaki Chakrabarti <pchakrabarti@ixiacom.com>
Signed-off-by: Cosmin Ratiu <cratiu@ixiacom.com>
---
 net/core/neighbour.c |   75 ++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index f35377b..243fa5b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2119,24 +2119,71 @@  out:
 static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct neigh_table *tbl;
-	int t, family, s_t;
+	struct net *net = sock_net(skb->sk);
+	const struct nlmsghdr *nlh = cb->nlh;
+	int min_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+	int family = ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family;
 
-	read_lock(&neigh_tbl_lock);
-	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
-	s_t = cb->args[0];
+	if (nlh->nlmsg_len <= min_len) {
+		struct neigh_table *tbl;
+		int t, s_t;
 
-	for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
-		if (t < s_t || (family && tbl->family != family))
-			continue;
-		if (t > s_t)
-			memset(&cb->args[1], 0, sizeof(cb->args) -
-						sizeof(cb->args[0]));
-		if (neigh_dump_table(tbl, skb, cb) < 0)
+		read_lock(&neigh_tbl_lock);
+		s_t = cb->args[0];
+
+		for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
+			if (t < s_t || (family && tbl->family != family))
+				continue;
+			if (t > s_t)
+				memset(&cb->args[1], 0, sizeof(cb->args) -
+							sizeof(cb->args[0]));
+			if (neigh_dump_table(tbl, skb, cb) < 0)
+				break;
+		}
+		read_unlock(&neigh_tbl_lock);
+		cb->args[0] = t;
+	} else {
+		char key[16] = {0};
+		struct ndmsg *ndm = NULL;
+		struct net_device *dev = NULL;
+		struct rtattr *attr = NULL;
+		int attrlen;
+		struct neighbour *n;
+
+		if (cb->args[0])
+			goto out;
+		cb->args[0] = 1;
+
+		ndm = NLMSG_DATA(nlh);
+		if (!(dev = dev_get_by_index(net, ndm->ndm_ifindex)))
+			goto out;
+
+		attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+		attr = (void*)nlh + NLMSG_ALIGN(min_len);
+		if (!RTA_OK(attr, attrlen) || attr->rta_type != NDA_DST)
+			goto out;
+		memcpy(key, RTA_DATA(attr), attr->rta_len);
+
+		/* look for the neighbor */
+		read_lock(&neigh_tbl_lock);
+		for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+			if (tbl->family != family)
+				continue;
+			n = neigh_lookup(tbl, key, dev);
+			if (!n)
+				continue;
+			if (n->nud_state & NUD_CONNECTED) {
+				neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
+						nlh->nlmsg_seq, RTM_NEWNEIGH, 0);
+				neigh_release(n);
+			}
 			break;
+		}
+		read_unlock(&neigh_tbl_lock);
+out:
+		if (dev)
+			dev_put(dev);
 	}
-	read_unlock(&neigh_tbl_lock);
-
-	cb->args[0] = t;
 	return skb->len;
 }
 
-- 
1.6.5