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 <davem@davemloft.net>
This commit is contained in:
parent
69ecca86da
commit
8f40b161de
@ -109,7 +109,7 @@ struct neighbour {
|
|||||||
seqlock_t ha_lock;
|
seqlock_t ha_lock;
|
||||||
unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
|
unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
|
||||||
struct hh_cache hh;
|
struct hh_cache hh;
|
||||||
int (*output)(struct sk_buff *skb);
|
int (*output)(struct neighbour *, struct sk_buff *);
|
||||||
const struct neigh_ops *ops;
|
const struct neigh_ops *ops;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
@ -118,10 +118,10 @@ struct neighbour {
|
|||||||
|
|
||||||
struct neigh_ops {
|
struct neigh_ops {
|
||||||
int family;
|
int family;
|
||||||
void (*solicit)(struct neighbour *, struct sk_buff*);
|
void (*solicit)(struct neighbour *, struct sk_buff *);
|
||||||
void (*error_report)(struct neighbour *, struct sk_buff*);
|
void (*error_report)(struct neighbour *, struct sk_buff *);
|
||||||
int (*output)(struct sk_buff*);
|
int (*output)(struct neighbour *, struct sk_buff *);
|
||||||
int (*connected_output)(struct sk_buff*);
|
int (*connected_output)(struct neighbour *, struct sk_buff *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pneigh_entry {
|
struct pneigh_entry {
|
||||||
@ -203,9 +203,10 @@ extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
|
|||||||
u32 flags);
|
u32 flags);
|
||||||
extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
|
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_ifdown(struct neigh_table *tbl, struct net_device *dev);
|
||||||
extern int neigh_resolve_output(struct sk_buff *skb);
|
extern int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb);
|
||||||
extern int neigh_connected_output(struct sk_buff *skb);
|
extern int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb);
|
||||||
extern int neigh_compat_output(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,
|
extern struct neighbour *neigh_event_ns(struct neigh_table *tbl,
|
||||||
u8 *lladdr, void *saddr,
|
u8 *lladdr, void *saddr,
|
||||||
struct net_device *dev);
|
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)
|
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
|
||||||
return neigh_hh_output(hh, skb);
|
return neigh_hh_output(hh, skb);
|
||||||
else
|
else
|
||||||
return n->output(skb);
|
return n->output(n, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct neighbour *
|
static inline struct neighbour *
|
||||||
|
@ -271,8 +271,8 @@ static const struct neigh_ops clip_neigh_ops = {
|
|||||||
.family = AF_INET,
|
.family = AF_INET,
|
||||||
.solicit = clip_neigh_solicit,
|
.solicit = clip_neigh_solicit,
|
||||||
.error_report = clip_neigh_error,
|
.error_report = clip_neigh_error,
|
||||||
.output = dev_queue_xmit,
|
.output = neigh_direct_output,
|
||||||
.connected_output = dev_queue_xmit,
|
.connected_output = neigh_direct_output,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int clip_constructor(struct neighbour *neigh)
|
static int clip_constructor(struct neighbour *neigh)
|
||||||
|
@ -355,14 +355,14 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
|
|||||||
neigh_hh_bridge(&neigh->hh, skb);
|
neigh_hh_bridge(&neigh->hh, skb);
|
||||||
skb->dev = nf_bridge->physindev;
|
skb->dev = nf_bridge->physindev;
|
||||||
return br_handle_frame_finish(skb);
|
return br_handle_frame_finish(skb);
|
||||||
} else if (dst->neighbour) {
|
} else {
|
||||||
/* the neighbour function below overwrites the complete
|
/* the neighbour function below overwrites the complete
|
||||||
* MAC header, so we save the Ethernet source address and
|
* MAC header, so we save the Ethernet source address and
|
||||||
* protocol number. */
|
* protocol number. */
|
||||||
skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
|
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 */
|
/* tell br_dev_xmit to continue with forwarding */
|
||||||
nf_bridge->mask |= BRNF_BRIDGED_DNAT;
|
nf_bridge->mask |= BRNF_BRIDGED_DNAT;
|
||||||
return dst->neighbour->output(skb);
|
return neigh->output(neigh, skb);
|
||||||
}
|
}
|
||||||
free_skb:
|
free_skb:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -98,7 +98,7 @@ static const struct file_operations neigh_stat_seq_fops;
|
|||||||
|
|
||||||
static DEFINE_RWLOCK(neigh_tbl_lock);
|
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);
|
kfree_skb(skb);
|
||||||
return -ENETDOWN;
|
return -ENETDOWN;
|
||||||
@ -1158,7 +1158,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
|
|||||||
/* On shaper/eql skb->dst->neighbour != neigh :( */
|
/* On shaper/eql skb->dst->neighbour != neigh :( */
|
||||||
if (skb_dst(skb) && skb_dst(skb)->neighbour)
|
if (skb_dst(skb) && skb_dst(skb)->neighbour)
|
||||||
n1 = skb_dst(skb)->neighbour;
|
n1 = skb_dst(skb)->neighbour;
|
||||||
n1->output(skb);
|
n1->output(n1, skb);
|
||||||
write_lock_bh(&neigh->lock);
|
write_lock_bh(&neigh->lock);
|
||||||
}
|
}
|
||||||
skb_queue_purge(&neigh->arp_queue);
|
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.
|
* 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;
|
struct net_device *dev = skb->dev;
|
||||||
|
|
||||||
@ -1231,13 +1231,12 @@ EXPORT_SYMBOL(neigh_compat_output);
|
|||||||
|
|
||||||
/* Slow and careful. */
|
/* 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 dst_entry *dst = skb_dst(skb);
|
||||||
struct neighbour *neigh;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (!dst || !(neigh = dst->neighbour))
|
if (!dst)
|
||||||
goto discard;
|
goto discard;
|
||||||
|
|
||||||
__skb_pull(skb, skb_network_offset(skb));
|
__skb_pull(skb, skb_network_offset(skb));
|
||||||
@ -1265,7 +1264,7 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
discard:
|
discard:
|
||||||
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
|
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
|
||||||
dst, dst ? dst->neighbour : NULL);
|
dst, neigh);
|
||||||
out_kfree_skb:
|
out_kfree_skb:
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
@ -1275,13 +1274,11 @@ EXPORT_SYMBOL(neigh_resolve_output);
|
|||||||
|
|
||||||
/* As fast as possible without hh cache */
|
/* 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;
|
struct net_device *dev = neigh->dev;
|
||||||
unsigned int seq;
|
unsigned int seq;
|
||||||
|
int err;
|
||||||
|
|
||||||
__skb_pull(skb, skb_network_offset(skb));
|
__skb_pull(skb, skb_network_offset(skb));
|
||||||
|
|
||||||
@ -1301,6 +1298,12 @@ int neigh_connected_output(struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(neigh_connected_output);
|
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)
|
static void neigh_proxy_process(unsigned long arg)
|
||||||
{
|
{
|
||||||
struct neigh_table *tbl = (struct neigh_table *)arg;
|
struct neigh_table *tbl = (struct neigh_table *)arg;
|
||||||
|
@ -51,9 +51,9 @@
|
|||||||
static int dn_neigh_construct(struct neighbour *);
|
static int dn_neigh_construct(struct neighbour *);
|
||||||
static void dn_long_error_report(struct neighbour *, struct sk_buff *);
|
static void dn_long_error_report(struct neighbour *, struct sk_buff *);
|
||||||
static void dn_short_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_long_output(struct neighbour *, struct sk_buff *);
|
||||||
static int dn_short_output(struct sk_buff *);
|
static int dn_short_output(struct neighbour *, struct sk_buff *);
|
||||||
static int dn_phase3_output(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;
|
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;
|
struct net_device *dev = neigh->dev;
|
||||||
int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
|
int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
@ -265,10 +263,8 @@ static int dn_long_output(struct sk_buff *skb)
|
|||||||
neigh->dev, dn_neigh_output_packet);
|
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;
|
struct net_device *dev = neigh->dev;
|
||||||
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
||||||
struct dn_short_packet *sp;
|
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
|
* Phase 3 output is the same is short output, execpt that
|
||||||
* it clears the area bits before transmission.
|
* 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;
|
struct net_device *dev = neigh->dev;
|
||||||
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
||||||
struct dn_short_packet *sp;
|
struct dn_short_packet *sp;
|
||||||
|
@ -705,6 +705,14 @@ out:
|
|||||||
return NET_RX_DROP;
|
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)
|
static int dn_output(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct dst_entry *dst = skb_dst(skb);
|
struct dst_entry *dst = skb_dst(skb);
|
||||||
@ -733,7 +741,7 @@ static int dn_output(struct sk_buff *skb)
|
|||||||
cb->hops = 0;
|
cb->hops = 0;
|
||||||
|
|
||||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev,
|
return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev,
|
||||||
neigh->output);
|
dn_to_neigh_output);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
@ -750,7 +758,6 @@ static int dn_forward(struct sk_buff *skb)
|
|||||||
struct dst_entry *dst = skb_dst(skb);
|
struct dst_entry *dst = skb_dst(skb);
|
||||||
struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
|
struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
|
||||||
struct dn_route *rt;
|
struct dn_route *rt;
|
||||||
struct neighbour *neigh = dst->neighbour;
|
|
||||||
int header_len;
|
int header_len;
|
||||||
#ifdef CONFIG_NETFILTER
|
#ifdef CONFIG_NETFILTER
|
||||||
struct net_device *dev = skb->dev;
|
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;
|
cb->rt_flags |= DN_RT_F_IE;
|
||||||
|
|
||||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev,
|
return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev,
|
||||||
neigh->output);
|
dn_to_neigh_output);
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -150,8 +150,8 @@ static const struct neigh_ops arp_hh_ops = {
|
|||||||
|
|
||||||
static const struct neigh_ops arp_direct_ops = {
|
static const struct neigh_ops arp_direct_ops = {
|
||||||
.family = AF_INET,
|
.family = AF_INET,
|
||||||
.output = dev_queue_xmit,
|
.output = neigh_direct_output,
|
||||||
.connected_output = dev_queue_xmit,
|
.connected_output = neigh_direct_output,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct neigh_ops arp_broken_ops = {
|
static const struct neigh_ops arp_broken_ops = {
|
||||||
@ -250,7 +250,7 @@ static int arp_constructor(struct neighbour *neigh)
|
|||||||
if (!dev->header_ops) {
|
if (!dev->header_ops) {
|
||||||
neigh->nud_state = NUD_NOARP;
|
neigh->nud_state = NUD_NOARP;
|
||||||
neigh->ops = &arp_direct_ops;
|
neigh->ops = &arp_direct_ops;
|
||||||
neigh->output = dev_queue_xmit;
|
neigh->output = neigh_direct_output;
|
||||||
} else {
|
} else {
|
||||||
/* Good devices (checked by reading texts, but only Ethernet is
|
/* Good devices (checked by reading texts, but only Ethernet is
|
||||||
tested)
|
tested)
|
||||||
|
@ -120,8 +120,8 @@ static const struct neigh_ops ndisc_hh_ops = {
|
|||||||
|
|
||||||
static const struct neigh_ops ndisc_direct_ops = {
|
static const struct neigh_ops ndisc_direct_ops = {
|
||||||
.family = AF_INET6,
|
.family = AF_INET6,
|
||||||
.output = dev_queue_xmit,
|
.output = neigh_direct_output,
|
||||||
.connected_output = dev_queue_xmit,
|
.connected_output = neigh_direct_output,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct neigh_table nd_tbl = {
|
struct neigh_table nd_tbl = {
|
||||||
@ -386,7 +386,7 @@ static int ndisc_constructor(struct neighbour *neigh)
|
|||||||
if (!dev->header_ops) {
|
if (!dev->header_ops) {
|
||||||
neigh->nud_state = NUD_NOARP;
|
neigh->nud_state = NUD_NOARP;
|
||||||
neigh->ops = &ndisc_direct_ops;
|
neigh->ops = &ndisc_direct_ops;
|
||||||
neigh->output = dev_queue_xmit;
|
neigh->output = neigh_direct_output;
|
||||||
} else {
|
} else {
|
||||||
if (is_multicast) {
|
if (is_multicast) {
|
||||||
neigh->nud_state = NUD_NOARP;
|
neigh->nud_state = NUD_NOARP;
|
||||||
|
Loading…
Reference in New Issue
Block a user