From f610b74b14d74a069f61583131e689550fd5bab3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 11 Jul 2011 01:37:28 -0700 Subject: ipv4: Use universal hash for ARP. We need to make sure the multiplier is odd. Signed-off-by: David S. Miller --- net/ipv4/arp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/ipv4/arp.c') diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 1b74d3b6437..4412b57f6ff 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -97,7 +97,6 @@ #include #include #include -#include #include #ifdef CONFIG_SYSCTL #include @@ -232,7 +231,7 @@ static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 hash_rnd) { - return jhash_2words(*(u32 *)pkey, dev->ifindex, hash_rnd); + return arp_hashfn(*(u32 *)pkey, dev, hash_rnd); } static int arp_constructor(struct neighbour *neigh) -- cgit v1.2.3-70-g09d2 From 3769cffb1c48f64640ffab7ce3bffe867342c0f0 Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 11 Jul 2011 22:44:24 +0000 Subject: ipv4: Inline neigh binding. Get rid of all of the useless and costly indirection by doing the neigh hash table lookup directly inside of the neighbour binding. Rename from arp_bind_neighbour to rt_bind_neighbour. Use new helpers {__,}ipv4_neigh_lookup() In rt_bind_neighbour() get rid of useless tests which are never true in the context this function is called, namely dev is never NULL and the dst->neighbour is always NULL. Signed-off-by: David S. Miller --- include/net/arp.h | 33 ++++++++++++++++++++++++++++++++- net/ipv4/arp.c | 24 ------------------------ net/ipv4/route.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 28 deletions(-) (limited to 'net/ipv4/arp.c') diff --git a/include/net/arp.h b/include/net/arp.h index 723bde501c6..5e669e6ffb4 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -15,6 +15,38 @@ static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd return val * hash_rnd; } +static inline struct neighbour *__ipv4_neigh_lookup(struct neigh_table *tbl, struct net_device *dev, u32 key) +{ + struct neigh_hash_table *nht; + struct neighbour *n; + u32 hash_val; + + rcu_read_lock_bh(); + nht = rcu_dereference_bh(tbl->nht); + hash_val = arp_hashfn(key, 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 (n->dev == dev && *(u32 *)n->primary_key == key) { + if (!atomic_inc_not_zero(&n->refcnt)) + n = NULL; + break; + } + } + rcu_read_unlock_bh(); + + return n; +} + +static inline struct neighbour *ipv4_neigh_lookup(struct neigh_table *tbl, struct net_device *dev, const __be32 *pkey) +{ + struct neighbour *n = __ipv4_neigh_lookup(tbl, dev, + *(__force u32 *)pkey); + if (n) + return n; + return neigh_create(tbl, pkey, dev); +} + extern void arp_init(void); extern int arp_find(unsigned char *haddr, struct sk_buff *skb); extern int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg); @@ -22,7 +54,6 @@ extern void arp_send(int type, int ptype, __be32 dest_ip, struct net_device *dev, __be32 src_ip, const unsigned char *dest_hw, const unsigned char *src_hw, const unsigned char *th); -extern int arp_bind_neighbour(struct dst_entry *dst); extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 4412b57f6ff..3e5545675cc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -517,30 +517,6 @@ EXPORT_SYMBOL(arp_find); /* END OF OBSOLETE FUNCTIONS */ -int arp_bind_neighbour(struct dst_entry *dst) -{ - struct net_device *dev = dst->dev; - struct neighbour *n = dst->neighbour; - - if (dev == NULL) - return -EINVAL; - if (n == NULL) { - __be32 nexthop = ((struct rtable *)dst)->rt_gateway; - if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) - nexthop = 0; - n = __neigh_lookup_errno( -#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) - dev->type == ARPHRD_ATM ? - clip_tbl_hook : -#endif - &arp_tbl, &nexthop, dev); - if (IS_ERR(n)) - return PTR_ERR(n); - dst->neighbour = n; - } - return 0; -} - /* * Check if we can use proxy ARP for this path */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a8ccd9bca09..c6388e825ed 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -108,6 +108,7 @@ #ifdef CONFIG_SYSCTL #include #endif +#include #define RT_FL_TOS(oldflp4) \ ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) @@ -1006,6 +1007,29 @@ static int slow_chain_length(const struct rtable *head) return length >> FRACT_BITS; } +static int rt_bind_neighbour(struct rtable *rt) +{ + static const __be32 inaddr_any = 0; + struct net_device *dev = rt->dst.dev; + struct neigh_table *tbl = &arp_tbl; + const __be32 *nexthop; + struct neighbour *n; + +#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) + if (dev->type == ARPHRD_ATM) + tbl = clip_tbl_hook; +#endif + nexthop = &rt->rt_gateway; + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) + nexthop = &inaddr_any; + n = ipv4_neigh_lookup(tbl, dev, nexthop); + if (IS_ERR(n)) + return PTR_ERR(n); + rt->dst.neighbour = n; + + return 0; +} + static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt, struct sk_buff *skb, int ifindex) { @@ -1042,7 +1066,7 @@ restart: rt->dst.flags |= DST_NOCACHE; if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { - int err = arp_bind_neighbour(&rt->dst); + int err = rt_bind_neighbour(rt); if (err) { if (net_ratelimit()) printk(KERN_WARNING @@ -1138,7 +1162,7 @@ restart: route or unicast forwarding path. */ if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { - int err = arp_bind_neighbour(&rt->dst); + int err = rt_bind_neighbour(rt); if (err) { spin_unlock_bh(rt_hash_lock_addr(hash)); @@ -1599,7 +1623,7 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) rt->dst.neighbour = NULL; rt->rt_gateway = peer->redirect_learned.a4; - if (arp_bind_neighbour(&rt->dst) || + if (rt_bind_neighbour(rt) || !(rt->dst.neighbour->nud_state & NUD_VALID)) { if (rt->dst.neighbour) neigh_event_send(rt->dst.neighbour, NULL); -- cgit v1.2.3-70-g09d2 From 47ec132a40d788d45e2f088545dea68798034dab Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 16 Jul 2011 17:39:57 -0700 Subject: neigh: Kill neigh_ops->hh_output It's always dev_queue_xmit(). Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 - net/atm/clip.c | 1 - net/core/neighbour.c | 4 ++-- net/decnet/dn_neigh.c | 3 --- net/ipv4/arp.c | 4 ---- net/ipv6/ndisc.c | 3 --- 6 files changed, 2 insertions(+), 14 deletions(-) (limited to 'net/ipv4/arp.c') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 337da241a80..97990ddca66 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -122,7 +122,6 @@ struct neigh_ops { void (*error_report)(struct neighbour *, struct sk_buff*); int (*output)(struct sk_buff*); int (*connected_output)(struct sk_buff*); - int (*hh_output)(struct sk_buff*); int (*queue_xmit)(struct sk_buff*); }; diff --git a/net/atm/clip.c b/net/atm/clip.c index 1d4be60e139..036cd43c13a 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -273,7 +273,6 @@ static const struct neigh_ops clip_neigh_ops = { .error_report = clip_neigh_error, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 83f9998f334..c22def5ae48 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -746,7 +746,7 @@ static void neigh_connect(struct neighbour *neigh) hh = &neigh->hh; if (hh->hh_len) - hh->hh_output = neigh->ops->hh_output; + hh->hh_output = dev_queue_xmit; } static void neigh_periodic_work(struct work_struct *work) @@ -1222,7 +1222,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst) goto end; if (n->nud_state & NUD_CONNECTED) - hh->hh_output = n->ops->hh_output; + hh->hh_output = dev_queue_xmit; else hh->hh_output = n->ops->output; diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 03eb2261180..abf4de851c6 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -64,7 +64,6 @@ static const struct neigh_ops dn_long_ops = { .error_report = dn_long_error_report, .output = dn_long_output, .connected_output = dn_long_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -76,7 +75,6 @@ static const struct neigh_ops dn_short_ops = { .error_report = dn_short_error_report, .output = dn_short_output, .connected_output = dn_short_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -88,7 +86,6 @@ static const struct neigh_ops dn_phase3_ops = { .error_report = dn_short_error_report, /* Can use short version here */ .output = dn_phase3_output, .connected_output = dn_phase3_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit }; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 3e5545675cc..f5f0aa1cd3a 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -138,7 +138,6 @@ static const struct neigh_ops arp_generic_ops = { .error_report = arp_error_report, .output = neigh_resolve_output, .connected_output = neigh_connected_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -148,7 +147,6 @@ static const struct neigh_ops arp_hh_ops = { .error_report = arp_error_report, .output = neigh_resolve_output, .connected_output = neigh_resolve_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -156,7 +154,6 @@ static const struct neigh_ops arp_direct_ops = { .family = AF_INET, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -166,7 +163,6 @@ static const struct neigh_ops arp_broken_ops = { .error_report = arp_error_report, .output = neigh_compat_output, .connected_output = neigh_compat_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7596f071d30..db782d2f7cc 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -107,7 +107,6 @@ static const struct neigh_ops ndisc_generic_ops = { .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_connected_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -117,7 +116,6 @@ static const struct neigh_ops ndisc_hh_ops = { .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_resolve_output, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; @@ -126,7 +124,6 @@ static const struct neigh_ops ndisc_direct_ops = { .family = AF_INET6, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .hh_output = dev_queue_xmit, .queue_xmit = dev_queue_xmit, }; -- cgit v1.2.3-70-g09d2 From 542d4d685febf3110d1a08d0bcb9f6ef060b76f7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 16 Jul 2011 18:06:24 -0700 Subject: neigh: Kill ndisc_ops->queue_xmit It is always dev_queue_xmit(). Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 - net/atm/clip.c | 1 - net/core/neighbour.c | 4 ++-- net/decnet/dn_neigh.c | 5 +---- net/ipv4/arp.c | 6 +----- net/ipv6/ndisc.c | 5 +---- 6 files changed, 5 insertions(+), 17 deletions(-) (limited to 'net/ipv4/arp.c') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 60bac8112d8..334e92f95bb 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -122,7 +122,6 @@ struct neigh_ops { void (*error_report)(struct neighbour *, struct sk_buff*); int (*output)(struct sk_buff*); int (*connected_output)(struct sk_buff*); - int (*queue_xmit)(struct sk_buff*); }; struct pneigh_entry { diff --git a/net/atm/clip.c b/net/atm/clip.c index 036cd43c13a..40d73689967 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -273,7 +273,6 @@ static const struct neigh_ops clip_neigh_ops = { .error_report = clip_neigh_error, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .queue_xmit = dev_queue_xmit, }; static int clip_constructor(struct neighbour *neigh) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 2feda6e7a31..b031cf63d6a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1257,7 +1257,7 @@ int neigh_resolve_output(struct sk_buff *skb) } while (read_seqretry(&neigh->ha_lock, seq)); if (err >= 0) - rc = neigh->ops->queue_xmit(skb); + rc = dev_queue_xmit(skb); else goto out_kfree_skb; } @@ -1292,7 +1292,7 @@ int neigh_connected_output(struct sk_buff *skb) } while (read_seqretry(&neigh->ha_lock, seq)); if (err >= 0) - err = neigh->ops->queue_xmit(skb); + err = dev_queue_xmit(skb); else { err = -EINVAL; kfree_skb(skb); diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index abf4de851c6..84fee8a4f89 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -64,7 +64,6 @@ static const struct neigh_ops dn_long_ops = { .error_report = dn_long_error_report, .output = dn_long_output, .connected_output = dn_long_output, - .queue_xmit = dev_queue_xmit, }; /* @@ -75,7 +74,6 @@ static const struct neigh_ops dn_short_ops = { .error_report = dn_short_error_report, .output = dn_short_output, .connected_output = dn_short_output, - .queue_xmit = dev_queue_xmit, }; /* @@ -86,7 +84,6 @@ static const struct neigh_ops dn_phase3_ops = { .error_report = dn_short_error_report, /* Can use short version here */ .output = dn_phase3_output, .connected_output = dn_phase3_output, - .queue_xmit = dev_queue_xmit }; static u32 dn_neigh_hash(const void *pkey, @@ -212,7 +209,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) dn_dn2eth(mac_addr, rt->rt_local_src); if (dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0) - return neigh->ops->queue_xmit(skb); + return dev_queue_xmit(skb); if (net_ratelimit()) printk(KERN_DEBUG "dn_neigh_output_packet: oops, can't send packet\n"); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f5f0aa1cd3a..8a21403cdd3 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -138,7 +138,6 @@ static const struct neigh_ops arp_generic_ops = { .error_report = arp_error_report, .output = neigh_resolve_output, .connected_output = neigh_connected_output, - .queue_xmit = dev_queue_xmit, }; static const struct neigh_ops arp_hh_ops = { @@ -147,14 +146,12 @@ static const struct neigh_ops arp_hh_ops = { .error_report = arp_error_report, .output = neigh_resolve_output, .connected_output = neigh_resolve_output, - .queue_xmit = dev_queue_xmit, }; static const struct neigh_ops arp_direct_ops = { .family = AF_INET, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .queue_xmit = dev_queue_xmit, }; static const struct neigh_ops arp_broken_ops = { @@ -163,7 +160,6 @@ static const struct neigh_ops arp_broken_ops = { .error_report = arp_error_report, .output = neigh_compat_output, .connected_output = neigh_compat_output, - .queue_xmit = dev_queue_xmit, }; struct neigh_table arp_tbl = { @@ -254,7 +250,7 @@ static int arp_constructor(struct neighbour *neigh) if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; - neigh->output = neigh->ops->queue_xmit; + neigh->output = dev_queue_xmit; } else { /* Good devices (checked by reading texts, but only Ethernet is tested) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index db782d2f7cc..482b970b835 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -107,7 +107,6 @@ static const struct neigh_ops ndisc_generic_ops = { .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_connected_output, - .queue_xmit = dev_queue_xmit, }; static const struct neigh_ops ndisc_hh_ops = { @@ -116,7 +115,6 @@ static const struct neigh_ops ndisc_hh_ops = { .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_resolve_output, - .queue_xmit = dev_queue_xmit, }; @@ -124,7 +122,6 @@ static const struct neigh_ops ndisc_direct_ops = { .family = AF_INET6, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, - .queue_xmit = dev_queue_xmit, }; struct neigh_table nd_tbl = { @@ -389,7 +386,7 @@ static int ndisc_constructor(struct neighbour *neigh) if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; - neigh->output = neigh->ops->queue_xmit; + neigh->output = dev_queue_xmit; } else { if (is_multicast) { neigh->nud_state = NUD_NOARP; -- cgit v1.2.3-70-g09d2 From 8f40b161de4f27402b4c0659ad2ae83fad5a0cdd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Jul 2011 13:34:11 -0700 Subject: neigh: Pass neighbour entry to output ops. This will get us closer to being able to do "neigh stuff" completely independent of the underlying dst_entry for protocols (ipv4/ipv6) that wish to do so. We will also be able to make dst entries neigh-less. Signed-off-by: David S. Miller --- include/net/neighbour.h | 19 ++++++++++--------- net/atm/clip.c | 4 ++-- net/bridge/br_netfilter.c | 4 ++-- net/core/neighbour.c | 25 ++++++++++++++----------- net/decnet/dn_neigh.c | 18 ++++++------------ net/decnet/dn_route.c | 13 ++++++++++--- net/ipv4/arp.c | 6 +++--- net/ipv6/ndisc.c | 6 +++--- 8 files changed, 50 insertions(+), 45 deletions(-) (limited to 'net/ipv4/arp.c') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 334e92f95bb..4ba8521490b 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -109,7 +109,7 @@ struct neighbour { seqlock_t ha_lock; unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; struct hh_cache hh; - int (*output)(struct sk_buff *skb); + int (*output)(struct neighbour *, struct sk_buff *); const struct neigh_ops *ops; struct rcu_head rcu; struct net_device *dev; @@ -118,10 +118,10 @@ struct neighbour { struct neigh_ops { int family; - void (*solicit)(struct neighbour *, struct sk_buff*); - void (*error_report)(struct neighbour *, struct sk_buff*); - int (*output)(struct sk_buff*); - int (*connected_output)(struct sk_buff*); + void (*solicit)(struct neighbour *, struct sk_buff *); + void (*error_report)(struct neighbour *, struct sk_buff *); + int (*output)(struct neighbour *, struct sk_buff *); + int (*connected_output)(struct neighbour *, struct sk_buff *); }; struct pneigh_entry { @@ -203,9 +203,10 @@ extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags); extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); -extern int neigh_resolve_output(struct sk_buff *skb); -extern int neigh_connected_output(struct sk_buff *skb); -extern int neigh_compat_output(struct sk_buff *skb); +extern int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); +extern int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); +extern int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb); +extern int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); extern struct neighbour *neigh_event_ns(struct neigh_table *tbl, u8 *lladdr, void *saddr, struct net_device *dev); @@ -348,7 +349,7 @@ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb) if ((n->nud_state & NUD_CONNECTED) && hh->hh_len) return neigh_hh_output(hh, skb); else - return n->output(skb); + return n->output(n, skb); } static inline struct neighbour * diff --git a/net/atm/clip.c b/net/atm/clip.c index 40d73689967..c6cd5318be3 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -271,8 +271,8 @@ static const struct neigh_ops clip_neigh_ops = { .family = AF_INET, .solicit = clip_neigh_solicit, .error_report = clip_neigh_error, - .output = dev_queue_xmit, - .connected_output = dev_queue_xmit, + .output = neigh_direct_output, + .connected_output = neigh_direct_output, }; static int clip_constructor(struct neighbour *neigh) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 75ee421917c..1fe43fdf997 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -355,14 +355,14 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) neigh_hh_bridge(&neigh->hh, skb); skb->dev = nf_bridge->physindev; return br_handle_frame_finish(skb); - } else if (dst->neighbour) { + } else { /* the neighbour function below overwrites the complete * MAC header, so we save the Ethernet source address and * protocol number. */ skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); /* tell br_dev_xmit to continue with forwarding */ nf_bridge->mask |= BRNF_BRIDGED_DNAT; - return dst->neighbour->output(skb); + return neigh->output(neigh, skb); } free_skb: kfree_skb(skb); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b031cf63d6a..cefb8e52615 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -98,7 +98,7 @@ static const struct file_operations neigh_stat_seq_fops; static DEFINE_RWLOCK(neigh_tbl_lock); -static int neigh_blackhole(struct sk_buff *skb) +static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb) { kfree_skb(skb); return -ENETDOWN; @@ -1158,7 +1158,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, /* On shaper/eql skb->dst->neighbour != neigh :( */ if (skb_dst(skb) && skb_dst(skb)->neighbour) n1 = skb_dst(skb)->neighbour; - n1->output(skb); + n1->output(n1, skb); write_lock_bh(&neigh->lock); } skb_queue_purge(&neigh->arp_queue); @@ -1214,7 +1214,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst) * but resolution is not made yet. */ -int neigh_compat_output(struct sk_buff *skb) +int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb) { struct net_device *dev = skb->dev; @@ -1231,13 +1231,12 @@ EXPORT_SYMBOL(neigh_compat_output); /* Slow and careful. */ -int neigh_resolve_output(struct sk_buff *skb) +int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh; int rc = 0; - if (!dst || !(neigh = dst->neighbour)) + if (!dst) goto discard; __skb_pull(skb, skb_network_offset(skb)); @@ -1265,7 +1264,7 @@ out: return rc; discard: NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n", - dst, dst ? dst->neighbour : NULL); + dst, neigh); out_kfree_skb: rc = -EINVAL; kfree_skb(skb); @@ -1275,13 +1274,11 @@ EXPORT_SYMBOL(neigh_resolve_output); /* As fast as possible without hh cache */ -int neigh_connected_output(struct sk_buff *skb) +int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb) { - int err; - struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; unsigned int seq; + int err; __skb_pull(skb, skb_network_offset(skb)); @@ -1301,6 +1298,12 @@ int neigh_connected_output(struct sk_buff *skb) } EXPORT_SYMBOL(neigh_connected_output); +int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb) +{ + return dev_queue_xmit(skb); +} +EXPORT_SYMBOL(neigh_direct_output); + static void neigh_proxy_process(unsigned long arg) { struct neigh_table *tbl = (struct neigh_table *)arg; diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 84fee8a4f89..5d61e8965b6 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -51,9 +51,9 @@ static int dn_neigh_construct(struct neighbour *); static void dn_long_error_report(struct neighbour *, struct sk_buff *); static void dn_short_error_report(struct neighbour *, struct sk_buff *); -static int dn_long_output(struct sk_buff *); -static int dn_short_output(struct sk_buff *); -static int dn_phase3_output(struct sk_buff *); +static int dn_long_output(struct neighbour *, struct sk_buff *); +static int dn_short_output(struct neighbour *, struct sk_buff *); +static int dn_phase3_output(struct neighbour *, struct sk_buff *); /* @@ -218,10 +218,8 @@ static int dn_neigh_output_packet(struct sk_buff *skb) return -EINVAL; } -static int dn_long_output(struct sk_buff *skb) +static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb) { - struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; unsigned char *data; @@ -265,10 +263,8 @@ static int dn_long_output(struct sk_buff *skb) neigh->dev, dn_neigh_output_packet); } -static int dn_short_output(struct sk_buff *skb) +static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb) { - struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; struct dn_short_packet *sp; @@ -309,10 +305,8 @@ static int dn_short_output(struct sk_buff *skb) * Phase 3 output is the same is short output, execpt that * it clears the area bits before transmission. */ -static int dn_phase3_output(struct sk_buff *skb) +static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb) { - struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; struct dn_short_packet *sp; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index fceb86ca011..3b6400d17dc 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -705,6 +705,14 @@ out: return NET_RX_DROP; } +static int dn_to_neigh_output(struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + struct neighbour *n = dst->neighbour; + + return n->output(n, skb); +} + static int dn_output(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); @@ -733,7 +741,7 @@ static int dn_output(struct sk_buff *skb) cb->hops = 0; return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev, - neigh->output); + dn_to_neigh_output); error: if (net_ratelimit()) @@ -750,7 +758,6 @@ static int dn_forward(struct sk_buff *skb) struct dst_entry *dst = skb_dst(skb); struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr); struct dn_route *rt; - struct neighbour *neigh = dst->neighbour; int header_len; #ifdef CONFIG_NETFILTER struct net_device *dev = skb->dev; @@ -783,7 +790,7 @@ static int dn_forward(struct sk_buff *skb) cb->rt_flags |= DN_RT_F_IE; return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev, - neigh->output); + dn_to_neigh_output); drop: kfree_skb(skb); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8a21403cdd3..96a164aa136 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -150,8 +150,8 @@ static const struct neigh_ops arp_hh_ops = { static const struct neigh_ops arp_direct_ops = { .family = AF_INET, - .output = dev_queue_xmit, - .connected_output = dev_queue_xmit, + .output = neigh_direct_output, + .connected_output = neigh_direct_output, }; static const struct neigh_ops arp_broken_ops = { @@ -250,7 +250,7 @@ static int arp_constructor(struct neighbour *neigh) if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; - neigh->output = dev_queue_xmit; + neigh->output = neigh_direct_output; } else { /* Good devices (checked by reading texts, but only Ethernet is tested) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 482b970b835..e08ce552d80 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -120,8 +120,8 @@ static const struct neigh_ops ndisc_hh_ops = { static const struct neigh_ops ndisc_direct_ops = { .family = AF_INET6, - .output = dev_queue_xmit, - .connected_output = dev_queue_xmit, + .output = neigh_direct_output, + .connected_output = neigh_direct_output, }; struct neigh_table nd_tbl = { @@ -386,7 +386,7 @@ static int ndisc_constructor(struct neighbour *neigh) if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; - neigh->output = dev_queue_xmit; + neigh->output = neigh_direct_output; } else { if (is_multicast) { neigh->nud_state = NUD_NOARP; -- cgit v1.2.3-70-g09d2