[DCCP]: Provide 10s of microsecond timesource
[safe/jmp/linux-2.6] / net / core / neighbour.c
index 512eed9..2c6577c 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/socket.h>
-#include <linux/sched.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
 #include <linux/times.h>
+#include <net/net_namespace.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/sock.h>
@@ -34,6 +34,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/random.h>
 #include <linux/string.h>
+#include <linux/log2.h>
 
 #define NEIGH_DEBUG 1
 
@@ -55,9 +56,8 @@
 #define PNEIGH_HASHMASK                0xF
 
 static void neigh_timer_handler(unsigned long arg);
-#ifdef CONFIG_ARPD
-static void neigh_app_notify(struct neighbour *n);
-#endif
+static void __neigh_notify(struct neighbour *n, int type, int flags);
+static void neigh_update_notify(struct neighbour *neigh);
 static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
 void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
 
@@ -105,6 +105,15 @@ static int neigh_blackhole(struct sk_buff *skb)
        return -ENETDOWN;
 }
 
+static void neigh_cleanup_and_release(struct neighbour *neigh)
+{
+       if (neigh->parms->neigh_cleanup)
+               neigh->parms->neigh_cleanup(neigh);
+
+       __neigh_notify(neigh, RTM_DELNEIGH, 0);
+       neigh_release(neigh);
+}
+
 /*
  * It is random distribution in the interval (1/2)*base...(3/2)*base.
  * It corresponds to default IPv6 settings and is not overridable,
@@ -141,7 +150,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
                                n->dead = 1;
                                shrunk  = 1;
                                write_unlock(&n->lock);
-                               neigh_release(n);
+                               neigh_cleanup_and_release(n);
                                continue;
                        }
                        write_unlock(&n->lock);
@@ -212,7 +221,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
                                NEIGH_PRINTK2("neigh %p is stray.\n", n);
                        }
                        write_unlock(&n->lock);
-                       neigh_release(n);
+                       neigh_cleanup_and_release(n);
                }
        }
 }
@@ -308,7 +317,7 @@ static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries)
 
        NEIGH_CACHE_STAT_INC(tbl, hash_grows);
 
-       BUG_ON(new_entries & (new_entries - 1));
+       BUG_ON(!is_power_of_2(new_entries));
        new_hash = neigh_hash_alloc(new_entries);
        if (!new_hash)
                return;
@@ -583,9 +592,6 @@ void neigh_destroy(struct neighbour *neigh)
                        kfree(hh);
        }
 
-       if (neigh->parms->neigh_destructor)
-               (neigh->parms->neigh_destructor)(neigh);
-
        skb_queue_purge(&neigh->arp_queue);
 
        dev_put(neigh->dev);
@@ -676,7 +682,7 @@ static void neigh_periodic_timer(unsigned long arg)
                        *np = n->next;
                        n->dead = 1;
                        write_unlock(&n->lock);
-                       neigh_release(n);
+                       neigh_cleanup_and_release(n);
                        continue;
                }
                write_unlock(&n->lock);
@@ -825,13 +831,10 @@ static void neigh_timer_handler(unsigned long arg)
 out:
                write_unlock(&neigh->lock);
        }
+
        if (notify)
-               call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
+               neigh_update_notify(neigh);
 
-#ifdef CONFIG_ARPD
-       if (notify && neigh->parms->app_probes)
-               neigh_app_notify(neigh);
-#endif
        neigh_release(neigh);
 }
 
@@ -1060,11 +1063,8 @@ out:
        write_unlock_bh(&neigh->lock);
 
        if (notify)
-               call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
-#ifdef CONFIG_ARPD
-       if (notify && neigh->parms->app_probes)
-               neigh_app_notify(neigh);
-#endif
+               neigh_update_notify(neigh);
+
        return err;
 }
 
@@ -1123,7 +1123,7 @@ int neigh_compat_output(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
 
-       __skb_pull(skb, skb->nh.raw - skb->data);
+       __skb_pull(skb, skb_network_offset(skb));
 
        if (dev->hard_header &&
            dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
@@ -1145,7 +1145,7 @@ int neigh_resolve_output(struct sk_buff *skb)
        if (!dst || !(neigh = dst->neighbour))
                goto discard;
 
-       __skb_pull(skb, skb->nh.raw - skb->data);
+       __skb_pull(skb, skb_network_offset(skb));
 
        if (!neigh_event_send(neigh, skb)) {
                int err;
@@ -1188,7 +1188,7 @@ int neigh_connected_output(struct sk_buff *skb)
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
 
-       __skb_pull(skb, skb->nh.raw - skb->data);
+       __skb_pull(skb, skb_network_offset(skb));
 
        read_lock_bh(&neigh->lock);
        err = dev->hard_header(skb, dev, ntohs(skb->protocol),
@@ -1329,6 +1329,8 @@ void neigh_parms_destroy(struct neigh_parms *parms)
        kfree(parms);
 }
 
+static struct lock_class_key neigh_table_proxy_queue_class;
+
 void neigh_table_init_no_netlink(struct neigh_table *tbl)
 {
        unsigned long now = jiffies;
@@ -1343,13 +1345,13 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
                tbl->kmem_cachep =
                        kmem_cache_create(tbl->id, tbl->entry_size, 0,
                                          SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                         NULL, NULL);
+                                         NULL);
        tbl->stats = alloc_percpu(struct neigh_statistics);
        if (!tbl->stats)
                panic("cannot create neighbour cache statistics");
 
 #ifdef CONFIG_PROC_FS
-       tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat);
+       tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat);
        if (!tbl->pde)
                panic("cannot create neighbour proc dir entry");
        tbl->pde->proc_fops = &neigh_stat_seq_fops;
@@ -1377,7 +1379,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
        init_timer(&tbl->proxy_timer);
        tbl->proxy_timer.data     = (unsigned long)tbl;
        tbl->proxy_timer.function = neigh_proxy_process;
-       skb_queue_head_init(&tbl->proxy_queue);
+       skb_queue_head_init_class(&tbl->proxy_queue,
+                       &neigh_table_proxy_queue_class);
 
        tbl->last_flush = now;
        tbl->last_rand  = now + tbl->parms.reachable_time * 20;
@@ -1436,8 +1439,9 @@ int neigh_table_clear(struct neigh_table *tbl)
        return 0;
 }
 
-int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ndmsg *ndm;
        struct nlattr *dst_attr;
        struct neigh_table *tbl;
@@ -1453,7 +1457,7 @@ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
        ndm = nlmsg_data(nlh);
        if (ndm->ndm_ifindex) {
-               dev = dev_get_by_index(ndm->ndm_ifindex);
+               dev = dev_get_by_index(net, ndm->ndm_ifindex);
                if (dev == NULL) {
                        err = -ENODEV;
                        goto out;
@@ -1501,8 +1505,9 @@ out:
        return err;
 }
 
-int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ndmsg *ndm;
        struct nlattr *tb[NDA_MAX+1];
        struct neigh_table *tbl;
@@ -1519,7 +1524,7 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
        ndm = nlmsg_data(nlh);
        if (ndm->ndm_ifindex) {
-               dev = dev_get_by_index(ndm->ndm_ifindex);
+               dev = dev_get_by_index(net, ndm->ndm_ifindex);
                if (dev == NULL) {
                        err = -ENODEV;
                        goto out;
@@ -1756,7 +1761,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
        return NULL;
 }
 
-static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = {
+static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
        [NDTA_NAME]             = { .type = NLA_STRING },
        [NDTA_THRESH1]          = { .type = NLA_U32 },
        [NDTA_THRESH2]          = { .type = NLA_U32 },
@@ -1765,7 +1770,7 @@ static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = {
        [NDTA_PARMS]            = { .type = NLA_NESTED },
 };
 
-static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] __read_mostly = {
+static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
        [NDTPA_IFINDEX]                 = { .type = NLA_U32 },
        [NDTPA_QUEUE_LEN]               = { .type = NLA_U32 },
        [NDTPA_PROXY_QLEN]              = { .type = NLA_U32 },
@@ -1781,7 +1786,7 @@ static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] __read_mostly = {
        [NDTPA_LOCKTIME]                = { .type = NLA_U64 },
 };
 
-int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct neigh_table *tbl;
        struct ndtmsg *ndtmsg;
@@ -1905,7 +1910,7 @@ errout:
        return err;
 }
 
-int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int family, tidx, nidx = 0;
        int tbl_skip = cb->args[0];
@@ -1994,6 +1999,11 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static void neigh_update_notify(struct neighbour *neigh)
+{
+       call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
+       __neigh_notify(neigh, RTM_NEWNEIGH, 0);
+}
 
 static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
                            struct netlink_callback *cb)
@@ -2029,7 +2039,7 @@ out:
        return rc;
 }
 
-int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct neigh_table *tbl;
        int t, family, s_t;
@@ -2090,7 +2100,7 @@ void __neigh_for_each_release(struct neigh_table *tbl,
                                np = &n->next;
                        write_unlock(&n->lock);
                        if (release)
-                               neigh_release(n);
+                               neigh_cleanup_and_release(n);
                }
        }
 }
@@ -2385,7 +2395,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations neigh_stat_seq_ops = {
+static const struct seq_operations neigh_stat_seq_ops = {
        .start  = neigh_stat_seq_start,
        .next   = neigh_stat_seq_next,
        .stop   = neigh_stat_seq_stop,
@@ -2413,7 +2423,6 @@ static const struct file_operations neigh_stat_seq_fops = {
 
 #endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_ARPD
 static inline size_t neigh_nlmsg_size(void)
 {
        return NLMSG_ALIGN(sizeof(struct ndmsg))
@@ -2445,16 +2454,11 @@ errout:
                rtnl_set_sk_err(RTNLGRP_NEIGH, err);
 }
 
+#ifdef CONFIG_ARPD
 void neigh_app_ns(struct neighbour *n)
 {
        __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
 }
-
-static void neigh_app_notify(struct neighbour *n)
-{
-       __neigh_notify(n, RTM_NEWNEIGH, 0);
-}
-
 #endif /* CONFIG_ARPD */
 
 #ifdef CONFIG_SYSCTL
@@ -2708,7 +2712,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        t->neigh_proto_dir[0].child    = t->neigh_neigh_dir;
        t->neigh_root_dir[0].child     = t->neigh_proto_dir;
 
-       t->sysctl_header = register_sysctl_table(t->neigh_root_dir, 0);
+       t->sysctl_header = register_sysctl_table(t->neigh_root_dir);
        if (!t->sysctl_header) {
                err = -ENOBUFS;
                goto free_procname;
@@ -2738,14 +2742,26 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
 
 #endif /* CONFIG_SYSCTL */
 
+static int __init neigh_init(void)
+{
+       rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
+
+       rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
+       rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
+
+       return 0;
+}
+
+subsys_initcall(neigh_init);
+
 EXPORT_SYMBOL(__neigh_event_send);
 EXPORT_SYMBOL(neigh_changeaddr);
 EXPORT_SYMBOL(neigh_compat_output);
 EXPORT_SYMBOL(neigh_connected_output);
 EXPORT_SYMBOL(neigh_create);
-EXPORT_SYMBOL(neigh_delete);
 EXPORT_SYMBOL(neigh_destroy);
-EXPORT_SYMBOL(neigh_dump_info);
 EXPORT_SYMBOL(neigh_event_ns);
 EXPORT_SYMBOL(neigh_ifdown);
 EXPORT_SYMBOL(neigh_lookup);