Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f564f45c authored by Cong Wang's avatar Cong Wang Committed by David S. Miller
Browse files

vxlan: add ipv6 proxy support



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: default avatarCong Wang <amwang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f39dc102
Loading
Loading
Loading
Loading
+80 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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)
	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;
+4 −0
Original line number Diff line number Diff line
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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
@@ -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,
};

+4 −4
Original line number Diff line number Diff line
@@ -461,7 +461,7 @@ static void ndisc_send_skb(struct sk_buff *skb,
	rcu_read_unlock();
}

static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
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)