neigh: new unresolved queue limits
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / core / neighbour.c
index 039d51e6c284e7ab655319d399b9d40060357dcf..2684794458ca00ff1476e178115fed5a6f56e2b0 100644 (file)
@@ -238,6 +238,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
                                   it to safe state.
                                 */
                                skb_queue_purge(&n->arp_queue);
+                               n->arp_queue_len_bytes = 0;
                                n->output = neigh_blackhole;
                                if (n->nud_state & NUD_VALID)
                                        n->nud_state = NUD_NOARP;
@@ -702,6 +703,7 @@ void neigh_destroy(struct neighbour *neigh)
                printk(KERN_WARNING "Impossible event.\n");
 
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 
        dev_put(neigh->dev);
        neigh_parms_put(neigh->parms);
@@ -842,6 +844,7 @@ static void neigh_invalidate(struct neighbour *neigh)
                write_lock(&neigh->lock);
        }
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 }
 
 static void neigh_probe(struct neighbour *neigh)
@@ -980,15 +983,20 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 
        if (neigh->nud_state == NUD_INCOMPLETE) {
                if (skb) {
-                       if (skb_queue_len(&neigh->arp_queue) >=
-                           neigh->parms->queue_len) {
+                       while (neigh->arp_queue_len_bytes + skb->truesize >
+                              neigh->parms->queue_len_bytes) {
                                struct sk_buff *buff;
+
                                buff = __skb_dequeue(&neigh->arp_queue);
+                               if (!buff)
+                                       break;
+                               neigh->arp_queue_len_bytes -= buff->truesize;
                                kfree_skb(buff);
                                NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
                        skb_dst_force(skb);
                        __skb_queue_tail(&neigh->arp_queue, skb);
+                       neigh->arp_queue_len_bytes += skb->truesize;
                }
                rc = 1;
        }
@@ -1175,6 +1183,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                        write_lock_bh(&neigh->lock);
                }
                skb_queue_purge(&neigh->arp_queue);
+               neigh->arp_queue_len_bytes = 0;
        }
 out:
        if (update_isrouter) {
@@ -1747,7 +1756,11 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
                NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
 
        NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
-       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
+       /* approximative value for deprecated QUEUE_LEN (in packets) */
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
+                   DIV_ROUND_UP(parms->queue_len_bytes,
+                                SKB_TRUESIZE(ETH_FRAME_LEN)));
        NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
        NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
        NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
@@ -1974,7 +1987,11 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
                        switch (i) {
                        case NDTPA_QUEUE_LEN:
-                               p->queue_len = nla_get_u32(tbp[i]);
+                               p->queue_len_bytes = nla_get_u32(tbp[i]) *
+                                                    SKB_TRUESIZE(ETH_FRAME_LEN);
+                               break;
+                       case NDTPA_QUEUE_LENBYTES:
+                               p->queue_len_bytes = nla_get_u32(tbp[i]);
                                break;
                        case NDTPA_PROXY_QLEN:
                                p->proxy_qlen = nla_get_u32(tbp[i]);
@@ -2635,117 +2652,158 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 
-#define NEIGH_VARS_MAX 19
+static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
+                          size_t *lenp, loff_t *ppos)
+{
+       int size, ret;
+       ctl_table tmp = *ctl;
+
+       tmp.data = &size;
+       size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
+       ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+       if (write && !ret)
+               *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
+       return ret;
+}
+
+enum {
+       NEIGH_VAR_MCAST_PROBE,
+       NEIGH_VAR_UCAST_PROBE,
+       NEIGH_VAR_APP_PROBE,
+       NEIGH_VAR_RETRANS_TIME,
+       NEIGH_VAR_BASE_REACHABLE_TIME,
+       NEIGH_VAR_DELAY_PROBE_TIME,
+       NEIGH_VAR_GC_STALETIME,
+       NEIGH_VAR_QUEUE_LEN,
+       NEIGH_VAR_QUEUE_LEN_BYTES,
+       NEIGH_VAR_PROXY_QLEN,
+       NEIGH_VAR_ANYCAST_DELAY,
+       NEIGH_VAR_PROXY_DELAY,
+       NEIGH_VAR_LOCKTIME,
+       NEIGH_VAR_RETRANS_TIME_MS,
+       NEIGH_VAR_BASE_REACHABLE_TIME_MS,
+       NEIGH_VAR_GC_INTERVAL,
+       NEIGH_VAR_GC_THRESH1,
+       NEIGH_VAR_GC_THRESH2,
+       NEIGH_VAR_GC_THRESH3,
+       NEIGH_VAR_MAX
+};
 
 static struct neigh_sysctl_table {
        struct ctl_table_header *sysctl_header;
-       struct ctl_table neigh_vars[NEIGH_VARS_MAX];
+       struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
        char *dev_name;
 } neigh_sysctl_template __read_mostly = {
        .neigh_vars = {
-               {
+               [NEIGH_VAR_MCAST_PROBE] = {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME] = {
                        .procname       = "base_reachable_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_DELAY_PROBE_TIME] = {
                        .procname       = "delay_first_probe_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_STALETIME] = {
                        .procname       = "gc_stale_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_QUEUE_LEN] = {
                        .procname       = "unres_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
+                       .proc_handler   = proc_unres_qlen,
+               },
+               [NEIGH_VAR_QUEUE_LEN_BYTES] = {
+                       .procname       = "unres_qlen_bytes",
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_PROXY_QLEN] = {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_PROXY_DELAY] = {
                        .procname       = "proxy_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_LOCKTIME] = {
                        .procname       = "locktime",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME_MS] = {
                        .procname       = "retrans_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
                        .procname       = "base_reachable_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_INTERVAL] = {
                        .procname       = "gc_interval",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_THRESH1] = {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2778,47 +2836,49 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       t->neigh_vars[0].data  = &p->mcast_probes;
-       t->neigh_vars[1].data  = &p->ucast_probes;
-       t->neigh_vars[2].data  = &p->app_probes;
-       t->neigh_vars[3].data  = &p->retrans_time;
-       t->neigh_vars[4].data  = &p->base_reachable_time;
-       t->neigh_vars[5].data  = &p->delay_probe_time;
-       t->neigh_vars[6].data  = &p->gc_staletime;
-       t->neigh_vars[7].data  = &p->queue_len;
-       t->neigh_vars[8].data  = &p->proxy_qlen;
-       t->neigh_vars[9].data  = &p->anycast_delay;
-       t->neigh_vars[10].data = &p->proxy_delay;
-       t->neigh_vars[11].data = &p->locktime;
-       t->neigh_vars[12].data  = &p->retrans_time;
-       t->neigh_vars[13].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data  = &p->mcast_probes;
+       t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data  = &p->ucast_probes;
+       t->neigh_vars[NEIGH_VAR_APP_PROBE].data  = &p->app_probes;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data  = &p->delay_probe_time;
+       t->neigh_vars[NEIGH_VAR_GC_STALETIME].data  = &p->gc_staletime;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data  = &p->proxy_qlen;
+       t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data  = &p->anycast_delay;
+       t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
+       t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data  = &p->base_reachable_time;
 
        if (dev) {
                dev_name_source = dev->name;
                /* Terminate the table early */
-               memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
+               memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
+                      sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
        } else {
                dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
-               t->neigh_vars[14].data = (int *)(p + 1);
-               t->neigh_vars[15].data = (int *)(p + 1) + 1;
-               t->neigh_vars[16].data = (int *)(p + 1) + 2;
-               t->neigh_vars[17].data = (int *)(p + 1) + 3;
+               t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
+               t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
        }
 
 
        if (handler) {
                /* RetransTime */
-               t->neigh_vars[3].proc_handler = handler;
-               t->neigh_vars[3].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
                /* ReachableTime */
-               t->neigh_vars[4].proc_handler = handler;
-               t->neigh_vars[4].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
                /* RetransTime (in milliseconds)*/
-               t->neigh_vars[12].proc_handler = handler;
-               t->neigh_vars[12].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
                /* ReachableTime (in milliseconds) */
-               t->neigh_vars[13].proc_handler = handler;
-               t->neigh_vars[13].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
        }
 
        t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);