Right now we have a neigh_param PROXY_QLEN which specifies maximum length
of neigh_table->proxy_queue. But in fact, this limitation doesn't work well
because check condition looks like:
tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)

The problem is that p (struct neigh_parms) is a per-device thing,
but tbl (struct neigh_table) is a system-wide global thing.

It seems reasonable to make proxy_queue limit per-device based.

https://jira.sw.ru/browse/PSBM-140896

Cc: "David S. Miller" <da...@davemloft.net>
Cc: Eric Dumazet <eduma...@google.com>
Cc: Jakub Kicinski <k...@kernel.org>
Cc: Paolo Abeni <pab...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David Ahern <dsah...@kernel.org>
Cc: Yajun Deng <yajun.d...@linux.dev>
Cc: Roopa Prabhu <ro...@nvidia.com>
Cc: Christian Brauner <brau...@kernel.org>
Cc: net...@vger.kernel.org
Cc: linux-ker...@vger.kernel.org
Cc: Alexey Kuznetsov <kuz...@ms2.inr.ac.ru>
Cc: Alexander Mikhalitsyn <alexander.mikhalit...@virtuozzo.com>
Cc: Konstantin Khorenko <khore...@virtuozzo.com>
Cc: ker...@openvz.org
Cc: devel@openvz.org
Suggested-by: Denis V. Lunev <d...@openvz.org>
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalit...@virtuozzo.com>
Reviewed-by: Denis V. Lunev <d...@openvz.org>
---
 include/net/neighbour.h |  1 +
 net/core/neighbour.c    | 25 ++++++++++++++++++++++---
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 22ced1381ede..8c8b8605bf98 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -81,6 +81,7 @@ struct neigh_parms {
        struct rcu_head rcu_head;
 
        int     reachable_time;
+       int     qlen;
        int     data[NEIGH_VAR_DATA_MAX];
        DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
 };
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index f33e01a0ed5e..4f7edf22c2fd 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -292,9 +292,18 @@ static void pneigh_queue_purge(struct sk_buff_head *list, 
struct net *net)
        skb = skb_peek(list);
        while (skb != NULL) {
                struct sk_buff *skb_next = skb_peek_next(skb, list);
-               if (net == NULL || net_eq(dev_net(skb->dev), net)) {
+               struct net_device *dev = skb->dev;
+               if (net == NULL || net_eq(dev_net(dev), net)) {
+                       struct in_device *in_dev;
+
+                       rcu_read_lock();
+                       in_dev = __in_dev_get_rcu(dev);
+                       if (in_dev)
+                               in_dev->arp_parms->qlen--;
+                       rcu_read_unlock();
                        __skb_unlink(skb, list);
-                       dev_put(skb->dev);
+
+                       dev_put(dev);
                        kfree_skb(skb);
                }
                skb = skb_next;
@@ -1589,8 +1598,15 @@ static void neigh_proxy_process(struct timer_list *t)
 
                if (tdif <= 0) {
                        struct net_device *dev = skb->dev;
+                       struct in_device *in_dev;
 
+                       rcu_read_lock();
+                       in_dev = __in_dev_get_rcu(dev);
+                       if (in_dev)
+                               in_dev->arp_parms->qlen--;
+                       rcu_read_unlock();
                        __skb_unlink(skb, &tbl->proxy_queue);
+
                        if (tbl->proxy_redo && netif_running(dev)) {
                                rcu_read_lock();
                                tbl->proxy_redo(skb);
@@ -1615,7 +1631,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct 
neigh_parms *p,
        unsigned long sched_next = jiffies +
                        prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
 
-       if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
+       if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
                kfree_skb(skb);
                return;
        }
@@ -1631,6 +1647,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct 
neigh_parms *p,
        skb_dst_drop(skb);
        dev_hold(skb->dev);
        __skb_queue_tail(&tbl->proxy_queue, skb);
+       p->qlen++;
        mod_timer(&tbl->proxy_timer, sched_next);
        spin_unlock(&tbl->proxy_queue.lock);
 }
@@ -1663,6 +1680,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device 
*dev,
                refcount_set(&p->refcnt, 1);
                p->reachable_time =
                                neigh_rand_reach_time(NEIGH_VAR(p, 
BASE_REACHABLE_TIME));
+               p->qlen = 0;
                dev_hold(dev);
                p->dev = dev;
                write_pnet(&p->net, net);
@@ -1726,6 +1744,7 @@ void neigh_table_init(int index, struct neigh_table *tbl)
        refcount_set(&tbl->parms.refcnt, 1);
        tbl->parms.reachable_time =
                          neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, 
BASE_REACHABLE_TIME));
+       tbl->parms.qlen = 0;
 
        tbl->stats = alloc_percpu(struct neigh_statistics);
        if (!tbl->stats)
-- 
2.36.1

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to