Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Eyal Birger <eyal.birger@gmail.com>
Link: https://lore.kernel.org/r/20220316061557.431872-1-eyal.birger@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Eyal Birger and committed by
Paolo Abeni
435fe1c0 82192c49

+64 -19
+63 -19
drivers/net/geneve.c
··· 56 56 bool use_udp6_rx_checksums; 57 57 bool ttl_inherit; 58 58 enum ifla_geneve_df df; 59 + bool inner_proto_inherit; 59 60 }; 60 61 61 62 /* Pseudo network device */ ··· 252 251 } 253 252 } 254 253 255 - skb_reset_mac_header(skb); 256 - skb->protocol = eth_type_trans(skb, geneve->dev); 257 - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 258 - 259 254 if (tun_dst) 260 255 skb_dst_set(skb, &tun_dst->dst); 261 256 262 - /* Ignore packet loops (and multicast echo) */ 263 - if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) { 264 - geneve->dev->stats.rx_errors++; 265 - goto drop; 257 + if (gnvh->proto_type == htons(ETH_P_TEB)) { 258 + skb_reset_mac_header(skb); 259 + skb->protocol = eth_type_trans(skb, geneve->dev); 260 + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 261 + 262 + /* Ignore packet loops (and multicast echo) */ 263 + if (ether_addr_equal(eth_hdr(skb)->h_source, 264 + geneve->dev->dev_addr)) { 265 + geneve->dev->stats.rx_errors++; 266 + goto drop; 267 + } 268 + } else { 269 + skb_reset_mac_header(skb); 270 + skb->dev = geneve->dev; 271 + skb->pkt_type = PACKET_HOST; 266 272 } 267 273 268 274 oiph = skb_network_header(skb); ··· 353 345 struct genevehdr *geneveh; 354 346 struct geneve_dev *geneve; 355 347 struct geneve_sock *gs; 348 + __be16 inner_proto; 356 349 int opts_len; 357 350 358 351 /* Need UDP and Geneve header to be present */ ··· 365 356 if (unlikely(geneveh->ver != GENEVE_VER)) 366 357 goto drop; 367 358 368 - if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) 359 + inner_proto = geneveh->proto_type; 360 + 361 + if (unlikely((inner_proto != htons(ETH_P_TEB) && 362 + inner_proto != htons(ETH_P_IP) && 363 + inner_proto != htons(ETH_P_IPV6)))) 369 364 goto drop; 370 365 371 366 gs = rcu_dereference_sk_user_data(sk); ··· 380 367 if (!geneve) 381 368 goto drop; 382 369 370 + if (unlikely((!geneve->cfg.inner_proto_inherit && 371 + inner_proto != htons(ETH_P_TEB)))) { 372 + geneve->dev->stats.rx_dropped++; 373 + goto drop; 374 + } 375 + 383 376 opts_len = geneveh->opt_len * 4; 384 - if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, 385 - htons(ETH_P_TEB), 377 + if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto, 386 378 !net_eq(geneve->net, dev_net(geneve->dev)))) { 387 379 geneve->dev->stats.rx_dropped++; 388 380 goto drop; ··· 735 717 } 736 718 737 719 static void geneve_build_header(struct genevehdr *geneveh, 738 - const struct ip_tunnel_info *info) 720 + const struct ip_tunnel_info *info, 721 + __be16 inner_proto) 739 722 { 740 723 geneveh->ver = GENEVE_VER; 741 724 geneveh->opt_len = info->options_len / 4; ··· 744 725 geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT); 745 726 geneveh->rsvd1 = 0; 746 727 tunnel_id_to_vni(info->key.tun_id, geneveh->vni); 747 - geneveh->proto_type = htons(ETH_P_TEB); 728 + geneveh->proto_type = inner_proto; 748 729 geneveh->rsvd2 = 0; 749 730 750 731 if (info->key.tun_flags & TUNNEL_GENEVE_OPT) ··· 753 734 754 735 static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb, 755 736 const struct ip_tunnel_info *info, 756 - bool xnet, int ip_hdr_len) 737 + bool xnet, int ip_hdr_len, 738 + bool inner_proto_inherit) 757 739 { 758 740 bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM); 759 741 struct genevehdr *gnvh; 742 + __be16 inner_proto; 760 743 int min_headroom; 761 744 int err; 762 745 ··· 776 755 goto free_dst; 777 756 778 757 gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len); 779 - geneve_build_header(gnvh, info); 780 - skb_set_inner_protocol(skb, htons(ETH_P_TEB)); 758 + inner_proto = inner_proto_inherit ? skb->protocol : htons(ETH_P_TEB); 759 + geneve_build_header(gnvh, info, inner_proto); 760 + skb_set_inner_protocol(skb, inner_proto); 781 761 return 0; 782 762 783 763 free_dst: ··· 981 959 } 982 960 } 983 961 984 - err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr)); 962 + err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr), 963 + geneve->cfg.inner_proto_inherit); 985 964 if (unlikely(err)) 986 965 return err; 987 966 ··· 1061 1038 ttl = key->ttl; 1062 1039 ttl = ttl ? : ip6_dst_hoplimit(dst); 1063 1040 } 1064 - err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr)); 1041 + err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr), 1042 + geneve->cfg.inner_proto_inherit); 1065 1043 if (unlikely(err)) 1066 1044 return err; 1067 1045 ··· 1412 1388 dst_cache_reset(&geneve->cfg.info.dst_cache); 1413 1389 memcpy(&geneve->cfg, cfg, sizeof(*cfg)); 1414 1390 1391 + if (geneve->cfg.inner_proto_inherit) { 1392 + dev->header_ops = NULL; 1393 + dev->type = ARPHRD_NONE; 1394 + dev->hard_header_len = 0; 1395 + dev->addr_len = 0; 1396 + dev->flags = IFF_NOARP; 1397 + } 1398 + 1415 1399 err = register_netdevice(dev); 1416 1400 if (err) 1417 1401 return err; ··· 1593 1561 #endif 1594 1562 } 1595 1563 1564 + if (data[IFLA_GENEVE_INNER_PROTO_INHERIT]) { 1565 + if (changelink) { 1566 + attrtype = IFLA_GENEVE_INNER_PROTO_INHERIT; 1567 + goto change_notsup; 1568 + } 1569 + cfg->inner_proto_inherit = true; 1570 + } 1571 + 1596 1572 return 0; 1597 1573 change_notsup: 1598 1574 NL_SET_ERR_MSG_ATTR(extack, data[attrtype], 1599 - "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported"); 1575 + "Changing VNI, Port, endpoint IP address family, external, inner_proto_inherit, and UDP checksum attributes are not supported"); 1600 1576 return -EOPNOTSUPP; 1601 1577 } 1602 1578 ··· 1837 1797 #endif 1838 1798 1839 1799 if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit)) 1800 + goto nla_put_failure; 1801 + 1802 + if (geneve->cfg.inner_proto_inherit && 1803 + nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT)) 1840 1804 goto nla_put_failure; 1841 1805 1842 1806 return 0;
+1
include/uapi/linux/if_link.h
··· 842 842 IFLA_GENEVE_LABEL, 843 843 IFLA_GENEVE_TTL_INHERIT, 844 844 IFLA_GENEVE_DF, 845 + IFLA_GENEVE_INNER_PROTO_INHERIT, 845 846 __IFLA_GENEVE_MAX 846 847 }; 847 848 #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)