]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/core/neighbour.c
neigh: Use neigh table index for neigh_packet_xmit
[karo-tx-linux.git] / net / core / neighbour.c
index 70fe9e10ac867f495086810dc6ea619f69d59368..ad07990e943da544dd292e29bf132adb6f2cc0c8 100644 (file)
@@ -397,25 +397,15 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
                               struct net_device *dev)
 {
        struct neighbour *n;
-       int key_len = tbl->key_len;
-       u32 hash_val;
-       struct neigh_hash_table *nht;
 
        NEIGH_CACHE_STAT_INC(tbl, lookups);
 
        rcu_read_lock_bh();
-       nht = rcu_dereference_bh(tbl->nht);
-       hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
-
-       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
-            n != NULL;
-            n = rcu_dereference_bh(n->next)) {
-               if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
-                       if (!atomic_inc_not_zero(&n->refcnt))
-                               n = NULL;
-                       NEIGH_CACHE_STAT_INC(tbl, hits);
-                       break;
-               }
+       n = __neigh_lookup_noref(tbl, pkey, dev);
+       if (n) {
+               if (!atomic_inc_not_zero(&n->refcnt))
+                       n = NULL;
+               NEIGH_CACHE_STAT_INC(tbl, hits);
        }
 
        rcu_read_unlock_bh();
@@ -1263,10 +1253,10 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
 EXPORT_SYMBOL(neigh_event_ns);
 
 /* called with read_lock_bh(&n->lock); */
-static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
+static void neigh_hh_init(struct neighbour *n)
 {
-       struct net_device *dev = dst->dev;
-       __be16 prot = dst->ops->protocol;
+       struct net_device *dev = n->dev;
+       __be16 prot = n->tbl->protocol;
        struct hh_cache *hh = &n->hh;
 
        write_lock_bh(&n->lock);
@@ -1280,43 +1270,19 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
        write_unlock_bh(&n->lock);
 }
 
-/* This function can be used in contexts, where only old dev_queue_xmit
- * worked, f.e. if you want to override normal output path (eql, shaper),
- * but resolution is not made yet.
- */
-
-int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
-{
-       struct net_device *dev = skb->dev;
-
-       __skb_pull(skb, skb_network_offset(skb));
-
-       if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
-                           skb->len) < 0 &&
-           dev_rebuild_header(skb))
-               return 0;
-
-       return dev_queue_xmit(skb);
-}
-EXPORT_SYMBOL(neigh_compat_output);
-
 /* Slow and careful. */
 
 int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb_dst(skb);
        int rc = 0;
 
-       if (!dst)
-               goto discard;
-
        if (!neigh_event_send(neigh, skb)) {
                int err;
                struct net_device *dev = neigh->dev;
                unsigned int seq;
 
                if (dev->header_ops->cache && !neigh->hh.hh_len)
-                       neigh_hh_init(neigh, dst);
+                       neigh_hh_init(neigh);
 
                do {
                        __skb_pull(skb, skb_network_offset(skb));
@@ -1332,8 +1298,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
        }
 out:
        return rc;
-discard:
-       neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
 out_kfree_skb:
        rc = -EINVAL;
        kfree_skb(skb);
@@ -2427,6 +2391,40 @@ void __neigh_for_each_release(struct neigh_table *tbl,
 }
 EXPORT_SYMBOL(__neigh_for_each_release);
 
+int neigh_xmit(int index, struct net_device *dev,
+              const void *addr, struct sk_buff *skb)
+{
+       int err = -EAFNOSUPPORT;
+       if (likely(index < NEIGH_NR_TABLES)) {
+               struct neigh_table *tbl;
+               struct neighbour *neigh;
+
+               tbl = neigh_tables[index];
+               if (!tbl)
+                       goto out;
+               neigh = __neigh_lookup_noref(tbl, addr, dev);
+               if (!neigh)
+                       neigh = __neigh_create(tbl, addr, dev, false);
+               err = PTR_ERR(neigh);
+               if (IS_ERR(neigh))
+                       goto out_kfree_skb;
+               err = neigh->output(neigh, skb);
+       }
+       else if (index == NEIGH_LINK_TABLE) {
+               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+                                     addr, NULL, skb->len);
+               if (err < 0)
+                       goto out_kfree_skb;
+               err = dev_queue_xmit(skb);
+       }
+out:
+       return err;
+out_kfree_skb:
+       kfree_skb(skb);
+       goto out;
+}
+EXPORT_SYMBOL(neigh_xmit);
+
 #ifdef CONFIG_PROC_FS
 
 static struct neighbour *neigh_get_first(struct seq_file *seq)