Skip to content

Commit

Permalink
vxlan: add ipv6 proxy support
Browse files Browse the repository at this point in the history
This patch adds the IPv6 version of "arp_reduce", ndisc_send_na()
will be needed.

Cc: David S. Miller <davem@davemloft.net>
Cc: David Stevens <dlstevens@us.ibm.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Cong Wang authored and davem330 committed Sep 1, 2013
1 parent f39dc10 commit f564f45
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 6 deletions.
82 changes: 80 additions & 2 deletions drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,70 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
return NETDEV_TX_OK;
}

#if IS_ENABLED(CONFIG_IPV6)
static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct neighbour *n;
union vxlan_addr ipa;
const struct ipv6hdr *iphdr;
const struct in6_addr *saddr, *daddr;
struct nd_msg *msg;
struct inet6_dev *in6_dev = NULL;

in6_dev = __in6_dev_get(dev);
if (!in6_dev)
goto out;

if (!pskb_may_pull(skb, skb->len))
goto out;

iphdr = ipv6_hdr(skb);
saddr = &iphdr->saddr;
daddr = &iphdr->daddr;

if (ipv6_addr_loopback(daddr) ||
ipv6_addr_is_multicast(daddr))
goto out;

msg = (struct nd_msg *)skb_transport_header(skb);
if (msg->icmph.icmp6_code != 0 ||
msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
goto out;

n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);

if (n) {
struct vxlan_fdb *f;

if (!(n->nud_state & NUD_CONNECTED)) {
neigh_release(n);
goto out;
}

f = vxlan_find_mac(vxlan, n->ha);
if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
/* bridge-local neighbor */
neigh_release(n);
goto out;
}

ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
!!in6_dev->cnf.forwarding,
true, false, false);
neigh_release(n);
} else if (vxlan->flags & VXLAN_F_L3MISS) {
ipa.sin6.sin6_addr = *daddr;
ipa.sa.sa_family = AF_INET6;
vxlan_ip_miss(dev, &ipa);
}

out:
consume_skb(skb);
return NETDEV_TX_OK;
}
#endif

static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
Expand Down Expand Up @@ -1677,8 +1741,22 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
skb_reset_mac_header(skb);
eth = eth_hdr(skb);

if ((vxlan->flags & VXLAN_F_PROXY) && ntohs(eth->h_proto) == ETH_P_ARP)
return arp_reduce(dev, skb);
if ((vxlan->flags & VXLAN_F_PROXY)) {
if (ntohs(eth->h_proto) == ETH_P_ARP)
return arp_reduce(dev, skb);
#if IS_ENABLED(CONFIG_IPV6)
else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
skb->len >= sizeof(struct ipv6hdr) + sizeof(struct nd_msg) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
struct nd_msg *msg;

msg = (struct nd_msg *)skb_transport_header(skb);
if (msg->icmph.icmp6_code == 0 &&
msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
return neigh_reduce(dev, skb);
}
#endif
}

f = vxlan_find_mac(vxlan, eth->h_dest);
did_rsc = false;
Expand Down
4 changes: 4 additions & 0 deletions include/net/addrconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ struct ipv6_stub {
int (*ipv6_dst_lookup)(struct sock *sk, struct dst_entry **dst,
struct flowi6 *fl6);
void (*udpv6_encap_enable)(void);
void (*ndisc_send_na)(struct net_device *dev, struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *solicited_addr,
bool router, bool solicited, bool override, bool inc_opt);
struct neigh_table *nd_tbl;
};
extern const struct ipv6_stub *ipv6_stub __read_mostly;
Expand Down
5 changes: 5 additions & 0 deletions include/net/ndisc.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ extern void ndisc_send_ns(struct net_device *dev,
extern void ndisc_send_rs(struct net_device *dev,
const struct in6_addr *saddr,
const struct in6_addr *daddr);
extern void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *solicited_addr,
bool router, bool solicited, bool override,
bool inc_opt);

extern void ndisc_send_redirect(struct sk_buff *skb,
const struct in6_addr *target);
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/ndisc.h>
#ifdef CONFIG_IPV6_TUNNEL
#include <net/ip6_tunnel.h>
#endif
Expand Down Expand Up @@ -815,6 +816,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
.ipv6_sock_mc_drop = ipv6_sock_mc_drop,
.ipv6_dst_lookup = ip6_dst_lookup,
.udpv6_encap_enable = udpv6_encap_enable,
.ndisc_send_na = ndisc_send_na,
.nd_tbl = &nd_tbl,
};

Expand Down
8 changes: 4 additions & 4 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,10 @@ static void ndisc_send_skb(struct sk_buff *skb,
rcu_read_unlock();
}

static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *solicited_addr,
bool router, bool solicited, bool override, bool inc_opt)
void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *solicited_addr,
bool router, bool solicited, bool override, bool inc_opt)
{
struct sk_buff *skb;
struct in6_addr tmpaddr;
Expand Down

0 comments on commit f564f45

Please sign in to comment.