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

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.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 82192c49
...@@ -56,6 +56,7 @@ struct geneve_config { ...@@ -56,6 +56,7 @@ struct geneve_config {
bool use_udp6_rx_checksums; bool use_udp6_rx_checksums;
bool ttl_inherit; bool ttl_inherit;
enum ifla_geneve_df df; enum ifla_geneve_df df;
bool inner_proto_inherit;
}; };
/* Pseudo network device */ /* Pseudo network device */
...@@ -251,17 +252,24 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, ...@@ -251,17 +252,24 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
} }
} }
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) if (tun_dst)
skb_dst_set(skb, &tun_dst->dst); skb_dst_set(skb, &tun_dst->dst);
/* Ignore packet loops (and multicast echo) */ if (gnvh->proto_type == htons(ETH_P_TEB)) {
if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) { skb_reset_mac_header(skb);
geneve->dev->stats.rx_errors++; skb->protocol = eth_type_trans(skb, geneve->dev);
goto drop; skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
/* Ignore packet loops (and multicast echo) */
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); oiph = skb_network_header(skb);
...@@ -345,6 +353,7 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -345,6 +353,7 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct genevehdr *geneveh; struct genevehdr *geneveh;
struct geneve_dev *geneve; struct geneve_dev *geneve;
struct geneve_sock *gs; struct geneve_sock *gs;
__be16 inner_proto;
int opts_len; int opts_len;
/* Need UDP and Geneve header to be present */ /* 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) ...@@ -356,7 +365,11 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely(geneveh->ver != GENEVE_VER)) if (unlikely(geneveh->ver != GENEVE_VER))
goto drop; 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; goto drop;
gs = rcu_dereference_sk_user_data(sk); gs = rcu_dereference_sk_user_data(sk);
...@@ -367,9 +380,14 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -367,9 +380,14 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (!geneve) if (!geneve)
goto drop; 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; opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
htons(ETH_P_TEB),
!net_eq(geneve->net, dev_net(geneve->dev)))) { !net_eq(geneve->net, dev_net(geneve->dev)))) {
geneve->dev->stats.rx_dropped++; geneve->dev->stats.rx_dropped++;
goto drop; goto drop;
...@@ -717,7 +735,8 @@ static int geneve_stop(struct net_device *dev) ...@@ -717,7 +735,8 @@ static int geneve_stop(struct net_device *dev)
} }
static void geneve_build_header(struct genevehdr *geneveh, 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->ver = GENEVE_VER;
geneveh->opt_len = info->options_len / 4; geneveh->opt_len = info->options_len / 4;
...@@ -725,7 +744,7 @@ static void geneve_build_header(struct genevehdr *geneveh, ...@@ -725,7 +744,7 @@ static void geneve_build_header(struct genevehdr *geneveh,
geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT); geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
geneveh->rsvd1 = 0; geneveh->rsvd1 = 0;
tunnel_id_to_vni(info->key.tun_id, geneveh->vni); 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; geneveh->rsvd2 = 0;
if (info->key.tun_flags & TUNNEL_GENEVE_OPT) if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
...@@ -734,10 +753,12 @@ static void geneve_build_header(struct genevehdr *geneveh, ...@@ -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, static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
const struct ip_tunnel_info *info, 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); bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
struct genevehdr *gnvh; struct genevehdr *gnvh;
__be16 inner_proto;
int min_headroom; int min_headroom;
int err; int err;
...@@ -755,8 +776,9 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb, ...@@ -755,8 +776,9 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
goto free_dst; goto free_dst;
gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len); gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
geneve_build_header(gnvh, info); inner_proto = inner_proto_inherit ? skb->protocol : htons(ETH_P_TEB);
skb_set_inner_protocol(skb, htons(ETH_P_TEB)); geneve_build_header(gnvh, info, inner_proto);
skb_set_inner_protocol(skb, inner_proto);
return 0; return 0;
free_dst: free_dst:
...@@ -959,7 +981,8 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -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)) if (unlikely(err))
return err; return err;
...@@ -1038,7 +1061,8 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -1038,7 +1061,8 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
ttl = key->ttl; ttl = key->ttl;
ttl = ttl ? : ip6_dst_hoplimit(dst); 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)) if (unlikely(err))
return err; return err;
...@@ -1388,6 +1412,14 @@ static int geneve_configure(struct net *net, struct net_device *dev, ...@@ -1388,6 +1412,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
dst_cache_reset(&geneve->cfg.info.dst_cache); dst_cache_reset(&geneve->cfg.info.dst_cache);
memcpy(&geneve->cfg, cfg, sizeof(*cfg)); 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); err = register_netdevice(dev);
if (err) if (err)
return err; return err;
...@@ -1561,10 +1593,18 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], ...@@ -1561,10 +1593,18 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
#endif #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; return 0;
change_notsup: change_notsup:
NL_SET_ERR_MSG_ATTR(extack, data[attrtype], 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; return -EOPNOTSUPP;
} }
...@@ -1799,6 +1839,10 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -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)) if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
goto nla_put_failure; 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; return 0;
nla_put_failure: nla_put_failure:
......
...@@ -842,6 +842,7 @@ enum { ...@@ -842,6 +842,7 @@ enum {
IFLA_GENEVE_LABEL, IFLA_GENEVE_LABEL,
IFLA_GENEVE_TTL_INHERIT, IFLA_GENEVE_TTL_INHERIT,
IFLA_GENEVE_DF, IFLA_GENEVE_DF,
IFLA_GENEVE_INNER_PROTO_INHERIT,
__IFLA_GENEVE_MAX __IFLA_GENEVE_MAX
}; };
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment