Commit 435fe1c0 authored by Eyal Birger's avatar Eyal Birger Committed by Paolo Abeni
Browse files

net: geneve: support IPv4/IPv6 as inner protocol



This patch adds support for encapsulating IPv4/IPv6 within GENEVE.

In order to use this, a new IFLA_GENEVE_INNER_PROTO_INHERIT flag needs
to be provided at device creation. This property cannot be changed for
the time being.

In case IP traffic is received on a non-tun device the drop count is
increased.

Signed-off-by: default avatarEyal Birger <eyal.birger@gmail.com>
Link: https://lore.kernel.org/r/20220316061557.431872-1-eyal.birger@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 82192c49
Loading
Loading
Loading
Loading
+63 −19
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ struct geneve_config {
	bool			use_udp6_rx_checksums;
	bool			ttl_inherit;
	enum ifla_geneve_df	df;
	bool			inner_proto_inherit;
};

/* Pseudo network device */
@@ -251,18 +252,25 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
		}
	}

	if (tun_dst)
		skb_dst_set(skb, &tun_dst->dst);

	if (gnvh->proto_type == htons(ETH_P_TEB)) {
		skb_reset_mac_header(skb);
		skb->protocol = eth_type_trans(skb, geneve->dev);
		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);

	if (tun_dst)
		skb_dst_set(skb, &tun_dst->dst);

		/* Ignore packet loops (and multicast echo) */
	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) {
		if (ether_addr_equal(eth_hdr(skb)->h_source,
				     geneve->dev->dev_addr)) {
			geneve->dev->stats.rx_errors++;
			goto drop;
		}
	} else {
		skb_reset_mac_header(skb);
		skb->dev = geneve->dev;
		skb->pkt_type = PACKET_HOST;
	}

	oiph = skb_network_header(skb);
	skb_reset_network_header(skb);
@@ -345,6 +353,7 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
	struct genevehdr *geneveh;
	struct geneve_dev *geneve;
	struct geneve_sock *gs;
	__be16 inner_proto;
	int opts_len;

	/* Need UDP and Geneve header to be present */
@@ -356,7 +365,11 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
	if (unlikely(geneveh->ver != GENEVE_VER))
		goto drop;

	if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
	inner_proto = geneveh->proto_type;

	if (unlikely((inner_proto != htons(ETH_P_TEB) &&
		      inner_proto != htons(ETH_P_IP) &&
		      inner_proto != htons(ETH_P_IPV6))))
		goto drop;

	gs = rcu_dereference_sk_user_data(sk);
@@ -367,9 +380,14 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
	if (!geneve)
		goto drop;

	if (unlikely((!geneve->cfg.inner_proto_inherit &&
		      inner_proto != htons(ETH_P_TEB)))) {
		geneve->dev->stats.rx_dropped++;
		goto drop;
	}

	opts_len = geneveh->opt_len * 4;
	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
				 htons(ETH_P_TEB),
	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
				 !net_eq(geneve->net, dev_net(geneve->dev)))) {
		geneve->dev->stats.rx_dropped++;
		goto drop;
@@ -717,7 +735,8 @@ static int geneve_stop(struct net_device *dev)
}

static void geneve_build_header(struct genevehdr *geneveh,
				const struct ip_tunnel_info *info)
				const struct ip_tunnel_info *info,
				__be16 inner_proto)
{
	geneveh->ver = GENEVE_VER;
	geneveh->opt_len = info->options_len / 4;
@@ -725,7 +744,7 @@ static void geneve_build_header(struct genevehdr *geneveh,
	geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
	geneveh->rsvd1 = 0;
	tunnel_id_to_vni(info->key.tun_id, geneveh->vni);
	geneveh->proto_type = htons(ETH_P_TEB);
	geneveh->proto_type = inner_proto;
	geneveh->rsvd2 = 0;

	if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
@@ -734,10 +753,12 @@ static void geneve_build_header(struct genevehdr *geneveh,

static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
			    const struct ip_tunnel_info *info,
			    bool xnet, int ip_hdr_len)
			    bool xnet, int ip_hdr_len,
			    bool inner_proto_inherit)
{
	bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
	struct genevehdr *gnvh;
	__be16 inner_proto;
	int min_headroom;
	int err;

@@ -755,8 +776,9 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
		goto free_dst;

	gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
	geneve_build_header(gnvh, info);
	skb_set_inner_protocol(skb, htons(ETH_P_TEB));
	inner_proto = inner_proto_inherit ? skb->protocol : htons(ETH_P_TEB);
	geneve_build_header(gnvh, info, inner_proto);
	skb_set_inner_protocol(skb, inner_proto);
	return 0;

free_dst:
@@ -959,7 +981,8 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
		}
	}

	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr));
	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr),
			       geneve->cfg.inner_proto_inherit);
	if (unlikely(err))
		return err;

@@ -1038,7 +1061,8 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
			ttl = key->ttl;
		ttl = ttl ? : ip6_dst_hoplimit(dst);
	}
	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr));
	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr),
			       geneve->cfg.inner_proto_inherit);
	if (unlikely(err))
		return err;

@@ -1388,6 +1412,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
	dst_cache_reset(&geneve->cfg.info.dst_cache);
	memcpy(&geneve->cfg, cfg, sizeof(*cfg));

	if (geneve->cfg.inner_proto_inherit) {
		dev->header_ops = NULL;
		dev->type = ARPHRD_NONE;
		dev->hard_header_len = 0;
		dev->addr_len = 0;
		dev->flags = IFF_NOARP;
	}

	err = register_netdevice(dev);
	if (err)
		return err;
@@ -1561,10 +1593,18 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
#endif
	}

	if (data[IFLA_GENEVE_INNER_PROTO_INHERIT]) {
		if (changelink) {
			attrtype = IFLA_GENEVE_INNER_PROTO_INHERIT;
			goto change_notsup;
		}
		cfg->inner_proto_inherit = true;
	}

	return 0;
change_notsup:
	NL_SET_ERR_MSG_ATTR(extack, data[attrtype],
			    "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported");
			    "Changing VNI, Port, endpoint IP address family, external, inner_proto_inherit, and UDP checksum attributes are not supported");
	return -EOPNOTSUPP;
}

@@ -1799,6 +1839,10 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
	if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
		goto nla_put_failure;

	if (geneve->cfg.inner_proto_inherit &&
	    nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT))
		goto nla_put_failure;

	return 0;

nla_put_failure:
+1 −0
Original line number Diff line number Diff line
@@ -842,6 +842,7 @@ enum {
	IFLA_GENEVE_LABEL,
	IFLA_GENEVE_TTL_INHERIT,
	IFLA_GENEVE_DF,
	IFLA_GENEVE_INNER_PROTO_INHERIT,
	__IFLA_GENEVE_MAX
};
#define IFLA_GENEVE_MAX	(__IFLA_GENEVE_MAX - 1)