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

Commit 08617f47 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'lwt-ipv6'



Jiri Benc says:

====================
lwtunnel: per route ipv6 support for vxlan

v3: Moved LWTUNNEL_ENCAP_IP6 definition in patch 13.
v2: Fixed issues in patch 4 pointed out by Alexei.

This series enables IPv6 tunnels based on lwtunnel infrastructure. Only
vxlan is supported for now.

Tested in all combinations of IPv4 over IPv6, IPv6 over IPv4 and IPv6 over
IPv6.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 938049e1 32a2b002
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -295,7 +295,6 @@ static struct rtable *vrf_rtable_create(struct net_device *dev)
		rth->rt_uses_gateway = 0;
		INIT_LIST_HEAD(&rth->rt_uncached);
		rth->rt_uncached_list = NULL;
		rth->rt_lwtstate = NULL;
	}

	return rth;
+50 −39
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,

	hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
		if (inet_sk(vs->sock->sk)->inet_sport == port &&
		    inet_sk(vs->sock->sk)->sk.sk_family == family &&
		    vxlan_get_sk_family(vs) == family &&
		    vs->flags == flags)
			return vs;
	}
@@ -625,7 +625,7 @@ static void vxlan_notify_add_rx_port(struct vxlan_sock *vs)
	struct net_device *dev;
	struct sock *sk = vs->sock->sk;
	struct net *net = sock_net(sk);
	sa_family_t sa_family = sk->sk_family;
	sa_family_t sa_family = vxlan_get_sk_family(vs);
	__be16 port = inet_sk(sk)->inet_sport;
	int err;

@@ -650,7 +650,7 @@ static void vxlan_notify_del_rx_port(struct vxlan_sock *vs)
	struct net_device *dev;
	struct sock *sk = vs->sock->sk;
	struct net *net = sock_net(sk);
	sa_family_t sa_family = sk->sk_family;
	sa_family_t sa_family = vxlan_get_sk_family(vs);
	__be16 port = inet_sk(sk)->inet_sport;

	rcu_read_lock();
@@ -1269,17 +1269,27 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
	}

	if (vxlan_collect_metadata(vs)) {
		const struct iphdr *iph = ip_hdr(skb);

		tun_dst = metadata_dst_alloc(sizeof(*md), GFP_ATOMIC);
		if (!tun_dst)
			goto drop;

		info = &tun_dst->u.tun_info;
		info->key.ipv4_src = iph->saddr;
		info->key.ipv4_dst = iph->daddr;
		info->key.ipv4_tos = iph->tos;
		info->key.ipv4_ttl = iph->ttl;
		if (vxlan_get_sk_family(vs) == AF_INET) {
			const struct iphdr *iph = ip_hdr(skb);

			info->key.u.ipv4.src = iph->saddr;
			info->key.u.ipv4.dst = iph->daddr;
			info->key.tos = iph->tos;
			info->key.ttl = iph->ttl;
		} else {
			const struct ipv6hdr *ip6h = ipv6_hdr(skb);

			info->key.u.ipv6.src = ip6h->saddr;
			info->key.u.ipv6.dst = ip6h->daddr;
			info->key.tos = ipv6_get_dsfield(ip6h);
			info->key.ttl = ip6h->hop_limit;
		}

		info->key.tp_src = udp_hdr(skb)->source;
		info->key.tp_dst = udp_hdr(skb)->dest;

@@ -1894,6 +1904,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
	struct ip_tunnel_info *info;
	struct vxlan_dev *vxlan = netdev_priv(dev);
	struct sock *sk = vxlan->vn_sock->sock->sk;
	unsigned short family = vxlan_get_sk_family(vxlan->vn_sock);
	struct rtable *rt = NULL;
	const struct iphdr *old_iph;
	struct flowi4 fl4;
@@ -1908,8 +1919,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
	int err;
	u32 flags = vxlan->flags;

	/* FIXME: Support IPv6 */
	info = skb_tunnel_info(skb, AF_INET);
	info = skb_tunnel_info(skb);

	if (rdst) {
		dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
@@ -1924,8 +1934,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,

		dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
		vni = be64_to_cpu(info->key.tun_id);
		remote_ip.sin.sin_family = AF_INET;
		remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst;
		remote_ip.sa.sa_family = family;
		if (family == AF_INET)
			remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst;
		else
			remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
		dst = &remote_ip;
	}

@@ -1951,17 +1964,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
	src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
				     vxlan->cfg.port_max, true);

	if (dst->sa.sa_family == AF_INET) {
	if (info) {
			if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
				df = htons(IP_DF);
		if (info->key.tun_flags & TUNNEL_CSUM)
			flags |= VXLAN_F_UDP_CSUM;
		else
			flags &= ~VXLAN_F_UDP_CSUM;

			ttl = info->key.ipv4_ttl;
			tos = info->key.ipv4_tos;
		ttl = info->key.ttl;
		tos = info->key.tos;

		if (info->options_len)
			md = ip_tunnel_info_opts(info, sizeof(*md));
@@ -1969,6 +1979,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
		md->gbp = skb->mark;
	}

	if (dst->sa.sa_family == AF_INET) {
		if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT))
			df = htons(IP_DF);

		memset(&fl4, 0, sizeof(fl4));
		fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0;
		fl4.flowi4_tos = RT_TOS(tos);
@@ -2025,7 +2039,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
	} else {
		struct dst_entry *ndst;
		struct flowi6 fl6;
		u32 flags;
		u32 rt6i_flags;

		memset(&fl6, 0, sizeof(fl6));
		fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0;
@@ -2050,9 +2064,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
		}

		/* Bypass encapsulation if the destination is local */
		flags = ((struct rt6_info *)ndst)->rt6i_flags;
		if (flags & RTF_LOCAL &&
		    !(flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
		rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
		if (rt6i_flags & RTF_LOCAL &&
		    !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
			struct vxlan_dev *dst_vxlan;

			dst_release(ndst);
@@ -2066,12 +2080,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
		}

		ttl = ttl ? : ip6_dst_hoplimit(ndst);
		md->gbp = skb->mark;

		err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr,
				      0, ttl, src_port, dst_port, htonl(vni << 8), md,
				      !net_eq(vxlan->net, dev_net(vxlan->dev)),
				      vxlan->flags);
				      flags);
#endif
	}

@@ -2104,8 +2116,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
	struct vxlan_rdst *rdst, *fdst = NULL;
	struct vxlan_fdb *f;

	/* FIXME: Support IPv6 */
	info = skb_tunnel_info(skb, AF_INET);
	info = skb_tunnel_info(skb);

	skb_reset_mac_header(skb);
	eth = eth_hdr(skb);
@@ -2390,7 +2401,7 @@ void vxlan_get_rx_port(struct net_device *dev)
	for (i = 0; i < PORT_HASH_SIZE; ++i) {
		hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
			port = inet_sk(vs->sock->sk)->inet_sport;
			sa_family = vs->sock->sk->sk_family;
			sa_family = vxlan_get_sk_family(vs);
			dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
							    port);
		}
+2 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct dst_entry {
#else
	void			*__pad1;
#endif
	struct lwtunnel_state   *lwtstate;
	int			(*input)(struct sk_buff *);
	int			(*output)(struct sock *sk, struct sk_buff *skb);

@@ -89,7 +90,7 @@ struct dst_entry {
	 * (L1_CACHE_SIZE would be too much)
	 */
#ifdef CONFIG_64BIT
	long			__pad_to_align_refcnt[2];
	long			__pad_to_align_refcnt[1];
#endif
	/*
	 * __refcnt wants to be on a different cache line from
+5 −10
Original line number Diff line number Diff line
@@ -23,22 +23,17 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb)
	return NULL;
}

static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb,
						     int family)
static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb)
{
	struct metadata_dst *md_dst = skb_metadata_dst(skb);
	struct rtable *rt;
	struct dst_entry *dst;

	if (md_dst)
		return &md_dst->u.tun_info;

	switch (family) {
	case AF_INET:
		rt = (struct rtable *)skb_dst(skb);
		if (rt && rt->rt_lwtstate)
			return lwt_tun_info(rt->rt_lwtstate);
		break;
	}
	dst = skb_dst(skb);
	if (dst && dst->lwtstate)
		return lwt_tun_info(dst->lwtstate);

	return NULL;
}
+1 −0
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ struct flowi6 {
#define flowi6_proto		__fl_common.flowic_proto
#define flowi6_flags		__fl_common.flowic_flags
#define flowi6_secid		__fl_common.flowic_secid
#define flowi6_tun_key		__fl_common.flowic_tun_key
	struct in6_addr		daddr;
	struct in6_addr		saddr;
	__be32			flowlabel;
Loading