neighbor: Add skip_cache argument to neigh_output
authorDavid Ahern <dsahern@gmail.com>
Fri, 5 Apr 2019 23:30:33 +0000 (16:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Apr 2019 22:22:41 +0000 (15:22 -0700)
A later patch allows an IPv6 gateway with an IPv4 route. The neighbor
entry will exist in the v6 ndisc table and the cached header will contain
the ipv6 protocol which is wrong for an IPv4 packet. For an IPv4 packet to
use the v6 neighbor entry, neigh_output needs to skip the cached header
and just use the output callback for the neigh entry.

A future patchset can look at expanding the hh_cache to handle 2
protocols. For now, IPv6 gateways with an IPv4 route will take the
extra overhead of generating the header.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/vrf.c
include/net/neighbour.h
net/ipv4/ip_output.c
net/ipv6/ip6_output.c

index 6d1a1abbed27e161f173f63ccb5aba5c6dca18ed..fd1337736aa04f3acfcca75cc40381b357ff266c 100644 (file)
@@ -370,7 +370,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
                neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
-               ret = neigh_output(neigh, skb);
+               ret = neigh_output(neigh, skb, false);
                rcu_read_unlock_bh();
                return ret;
        }
@@ -578,7 +578,7 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
                neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
-               ret = neigh_output(neigh, skb);
+               ret = neigh_output(neigh, skb, false);
                rcu_read_unlock_bh();
                return ret;
        }
index 7c1ab9edba03873ffc9ea029e7925e12051f6b02..3e5438bd0101cda2b9b6c7eecf051e9f73beef0d 100644 (file)
@@ -498,11 +498,12 @@ static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb
        return dev_queue_xmit(skb);
 }
 
-static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
+static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
+                              bool skip_cache)
 {
        const struct hh_cache *hh = &n->hh;
 
-       if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
+       if ((n->nud_state & NUD_CONNECTED) && hh->hh_len && !skip_cache)
                return neigh_hh_output(hh, skb);
        else
                return n->output(n, skb);
index a2bd4a6d9e6b6107e2a3c713328e40982bda5224..cca4892b8cb2eb4ecdaba34566a3eab239901be5 100644 (file)
@@ -226,7 +226,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
                int res;
 
                sock_confirm_neigh(skb, neigh);
-               res = neigh_output(neigh, skb);
+               res = neigh_output(neigh, skb, false);
 
                rcu_read_unlock_bh();
                return res;
index e51f3c648b094afe1d60a518db36a42444c4c55d..adef2236abe2e767602a9d4afbf23fc6db5750dd 100644 (file)
@@ -117,7 +117,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
                neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
-               ret = neigh_output(neigh, skb);
+               ret = neigh_output(neigh, skb, false);
                rcu_read_unlock_bh();
                return ret;
        }