From patchwork Fri Jan 15 16:42:59 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cosmin Ratiu X-Patchwork-Id: 42976 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id DA273B7CC1 for ; Sat, 16 Jan 2010 03:43:13 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753739Ab0AOQnF (ORCPT ); Fri, 15 Jan 2010 11:43:05 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752177Ab0AOQnE (ORCPT ); Fri, 15 Jan 2010 11:43:04 -0500 Received: from ixro-out-rtc.ixiacom.com ([92.87.192.98]:15063 "EHLO ixro-ex1.ixiacom.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753159Ab0AOQnD (ORCPT ); Fri, 15 Jan 2010 11:43:03 -0500 Received: from ixro-cratiu.localnet ([10.205.9.78]) by ixro-ex1.ixiacom.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 15 Jan 2010 18:43:00 +0200 From: Cosmin Ratiu Organization: IXIA To: netdev@vger.kernel.org Subject: [RFC PATCH] extend RTM_GETNEIGH to allow getting more precise information Date: Fri, 15 Jan 2010 18:42:59 +0200 User-Agent: KMail/1.12.2 (Linux/2.6.30-2-686; KDE/4.3.2; i686; ; ) Cc: ixlk-cr@farscape.ixiacom.com, Pinaki Chakrabarti MIME-Version: 1.0 Message-Id: <201001151842.59813.cratiu@ixiacom.com> X-OriginalArrivalTime: 15 Jan 2010 16:43:00.0345 (UTC) FILETIME=[CC7E6690:01CA9601] Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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. From beb2cd45109f28b9067d7fa902e49cbbc7667ff5 Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu 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 Signed-off-by: Cosmin Ratiu --- 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