18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * GENEVE: Generic Network Virtualization Encapsulation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Red Hat, Inc.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/hash.h>
148c2ecf20Sopenharmony_ci#include <net/ipv6_stubs.h>
158c2ecf20Sopenharmony_ci#include <net/dst_metadata.h>
168c2ecf20Sopenharmony_ci#include <net/gro_cells.h>
178c2ecf20Sopenharmony_ci#include <net/rtnetlink.h>
188c2ecf20Sopenharmony_ci#include <net/geneve.h>
198c2ecf20Sopenharmony_ci#include <net/protocol.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define GENEVE_NETDEV_VER	"0.6"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define GENEVE_N_VID		(1u << 24)
248c2ecf20Sopenharmony_ci#define GENEVE_VID_MASK		(GENEVE_N_VID - 1)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define VNI_HASH_BITS		10
278c2ecf20Sopenharmony_ci#define VNI_HASH_SIZE		(1<<VNI_HASH_BITS)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic bool log_ecn_error = true;
308c2ecf20Sopenharmony_cimodule_param(log_ecn_error, bool, 0644);
318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define GENEVE_VER 0
348c2ecf20Sopenharmony_ci#define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr))
358c2ecf20Sopenharmony_ci#define GENEVE_IPV4_HLEN (ETH_HLEN + sizeof(struct iphdr) + GENEVE_BASE_HLEN)
368c2ecf20Sopenharmony_ci#define GENEVE_IPV6_HLEN (ETH_HLEN + sizeof(struct ipv6hdr) + GENEVE_BASE_HLEN)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* per-network namespace private data for this module */
398c2ecf20Sopenharmony_cistruct geneve_net {
408c2ecf20Sopenharmony_ci	struct list_head	geneve_list;
418c2ecf20Sopenharmony_ci	struct list_head	sock_list;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic unsigned int geneve_net_id;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistruct geneve_dev_node {
478c2ecf20Sopenharmony_ci	struct hlist_node hlist;
488c2ecf20Sopenharmony_ci	struct geneve_dev *geneve;
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct geneve_config {
528c2ecf20Sopenharmony_ci	struct ip_tunnel_info	info;
538c2ecf20Sopenharmony_ci	bool			collect_md;
548c2ecf20Sopenharmony_ci	bool			use_udp6_rx_checksums;
558c2ecf20Sopenharmony_ci	bool			ttl_inherit;
568c2ecf20Sopenharmony_ci	enum ifla_geneve_df	df;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/* Pseudo network device */
608c2ecf20Sopenharmony_cistruct geneve_dev {
618c2ecf20Sopenharmony_ci	struct geneve_dev_node hlist4;	/* vni hash table for IPv4 socket */
628c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
638c2ecf20Sopenharmony_ci	struct geneve_dev_node hlist6;	/* vni hash table for IPv6 socket */
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci	struct net	   *net;	/* netns for packet i/o */
668c2ecf20Sopenharmony_ci	struct net_device  *dev;	/* netdev for geneve tunnel */
678c2ecf20Sopenharmony_ci	struct geneve_sock __rcu *sock4;	/* IPv4 socket used for geneve tunnel */
688c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
698c2ecf20Sopenharmony_ci	struct geneve_sock __rcu *sock6;	/* IPv6 socket used for geneve tunnel */
708c2ecf20Sopenharmony_ci#endif
718c2ecf20Sopenharmony_ci	struct list_head   next;	/* geneve's per namespace list */
728c2ecf20Sopenharmony_ci	struct gro_cells   gro_cells;
738c2ecf20Sopenharmony_ci	struct geneve_config cfg;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistruct geneve_sock {
778c2ecf20Sopenharmony_ci	bool			collect_md;
788c2ecf20Sopenharmony_ci	struct list_head	list;
798c2ecf20Sopenharmony_ci	struct socket		*sock;
808c2ecf20Sopenharmony_ci	struct rcu_head		rcu;
818c2ecf20Sopenharmony_ci	int			refcnt;
828c2ecf20Sopenharmony_ci	struct hlist_head	vni_list[VNI_HASH_SIZE];
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline __u32 geneve_net_vni_hash(u8 vni[3])
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	__u32 vnid;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
908c2ecf20Sopenharmony_ci	return hash_32(vnid, VNI_HASH_BITS);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic __be64 vni_to_tunnel_id(const __u8 *vni)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
968c2ecf20Sopenharmony_ci	return (vni[0] << 16) | (vni[1] << 8) | vni[2];
978c2ecf20Sopenharmony_ci#else
988c2ecf20Sopenharmony_ci	return (__force __be64)(((__force u64)vni[0] << 40) |
998c2ecf20Sopenharmony_ci				((__force u64)vni[1] << 48) |
1008c2ecf20Sopenharmony_ci				((__force u64)vni[2] << 56));
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* Convert 64 bit tunnel ID to 24 bit VNI. */
1058c2ecf20Sopenharmony_cistatic void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
1088c2ecf20Sopenharmony_ci	vni[0] = (__force __u8)(tun_id >> 16);
1098c2ecf20Sopenharmony_ci	vni[1] = (__force __u8)(tun_id >> 8);
1108c2ecf20Sopenharmony_ci	vni[2] = (__force __u8)tun_id;
1118c2ecf20Sopenharmony_ci#else
1128c2ecf20Sopenharmony_ci	vni[0] = (__force __u8)((__force u64)tun_id >> 40);
1138c2ecf20Sopenharmony_ci	vni[1] = (__force __u8)((__force u64)tun_id >> 48);
1148c2ecf20Sopenharmony_ci	vni[2] = (__force __u8)((__force u64)tun_id >> 56);
1158c2ecf20Sopenharmony_ci#endif
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic bool eq_tun_id_and_vni(u8 *tun_id, u8 *vni)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	return !memcmp(vni, &tun_id[5], 3);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return gs->sock->sk->sk_family;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
1298c2ecf20Sopenharmony_ci					__be32 addr, u8 vni[])
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct hlist_head *vni_list_head;
1328c2ecf20Sopenharmony_ci	struct geneve_dev_node *node;
1338c2ecf20Sopenharmony_ci	__u32 hash;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Find the device for this VNI */
1368c2ecf20Sopenharmony_ci	hash = geneve_net_vni_hash(vni);
1378c2ecf20Sopenharmony_ci	vni_list_head = &gs->vni_list[hash];
1388c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1398c2ecf20Sopenharmony_ci		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1408c2ecf20Sopenharmony_ci		    addr == node->geneve->cfg.info.key.u.ipv4.dst)
1418c2ecf20Sopenharmony_ci			return node->geneve;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	return NULL;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1478c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
1488c2ecf20Sopenharmony_ci					 struct in6_addr addr6, u8 vni[])
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct hlist_head *vni_list_head;
1518c2ecf20Sopenharmony_ci	struct geneve_dev_node *node;
1528c2ecf20Sopenharmony_ci	__u32 hash;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Find the device for this VNI */
1558c2ecf20Sopenharmony_ci	hash = geneve_net_vni_hash(vni);
1568c2ecf20Sopenharmony_ci	vni_list_head = &gs->vni_list[hash];
1578c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1588c2ecf20Sopenharmony_ci		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1598c2ecf20Sopenharmony_ci		    ipv6_addr_equal(&addr6, &node->geneve->cfg.info.key.u.ipv6.dst))
1608c2ecf20Sopenharmony_ci			return node->geneve;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci	return NULL;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci#endif
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return (struct genevehdr *)(udp_hdr(skb) + 1);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
1728c2ecf20Sopenharmony_ci					    struct sk_buff *skb)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	static u8 zero_vni[3];
1758c2ecf20Sopenharmony_ci	u8 *vni;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (geneve_get_sk_family(gs) == AF_INET) {
1788c2ecf20Sopenharmony_ci		struct iphdr *iph;
1798c2ecf20Sopenharmony_ci		__be32 addr;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		iph = ip_hdr(skb); /* outer IP header... */
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		if (gs->collect_md) {
1848c2ecf20Sopenharmony_ci			vni = zero_vni;
1858c2ecf20Sopenharmony_ci			addr = 0;
1868c2ecf20Sopenharmony_ci		} else {
1878c2ecf20Sopenharmony_ci			vni = geneve_hdr(skb)->vni;
1888c2ecf20Sopenharmony_ci			addr = iph->saddr;
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		return geneve_lookup(gs, addr, vni);
1928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1938c2ecf20Sopenharmony_ci	} else if (geneve_get_sk_family(gs) == AF_INET6) {
1948c2ecf20Sopenharmony_ci		static struct in6_addr zero_addr6;
1958c2ecf20Sopenharmony_ci		struct ipv6hdr *ip6h;
1968c2ecf20Sopenharmony_ci		struct in6_addr addr6;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		if (gs->collect_md) {
2018c2ecf20Sopenharmony_ci			vni = zero_vni;
2028c2ecf20Sopenharmony_ci			addr6 = zero_addr6;
2038c2ecf20Sopenharmony_ci		} else {
2048c2ecf20Sopenharmony_ci			vni = geneve_hdr(skb)->vni;
2058c2ecf20Sopenharmony_ci			addr6 = ip6h->saddr;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		return geneve6_lookup(gs, addr6, vni);
2098c2ecf20Sopenharmony_ci#endif
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	return NULL;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/* geneve receive/decap routine */
2158c2ecf20Sopenharmony_cistatic void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
2168c2ecf20Sopenharmony_ci		      struct sk_buff *skb)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct genevehdr *gnvh = geneve_hdr(skb);
2198c2ecf20Sopenharmony_ci	struct metadata_dst *tun_dst = NULL;
2208c2ecf20Sopenharmony_ci	unsigned int len;
2218c2ecf20Sopenharmony_ci	int err = 0;
2228c2ecf20Sopenharmony_ci	void *oiph;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (ip_tunnel_collect_metadata() || gs->collect_md) {
2258c2ecf20Sopenharmony_ci		__be16 flags;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		flags = TUNNEL_KEY | (gnvh->oam ? TUNNEL_OAM : 0) |
2288c2ecf20Sopenharmony_ci			(gnvh->critical ? TUNNEL_CRIT_OPT : 0);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
2318c2ecf20Sopenharmony_ci					 vni_to_tunnel_id(gnvh->vni),
2328c2ecf20Sopenharmony_ci					 gnvh->opt_len * 4);
2338c2ecf20Sopenharmony_ci		if (!tun_dst) {
2348c2ecf20Sopenharmony_ci			geneve->dev->stats.rx_dropped++;
2358c2ecf20Sopenharmony_ci			goto drop;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci		/* Update tunnel dst according to Geneve options. */
2388c2ecf20Sopenharmony_ci		ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
2398c2ecf20Sopenharmony_ci					gnvh->options, gnvh->opt_len * 4,
2408c2ecf20Sopenharmony_ci					TUNNEL_GENEVE_OPT);
2418c2ecf20Sopenharmony_ci	} else {
2428c2ecf20Sopenharmony_ci		/* Drop packets w/ critical options,
2438c2ecf20Sopenharmony_ci		 * since we don't support any...
2448c2ecf20Sopenharmony_ci		 */
2458c2ecf20Sopenharmony_ci		if (gnvh->critical) {
2468c2ecf20Sopenharmony_ci			geneve->dev->stats.rx_frame_errors++;
2478c2ecf20Sopenharmony_ci			geneve->dev->stats.rx_errors++;
2488c2ecf20Sopenharmony_ci			goto drop;
2498c2ecf20Sopenharmony_ci		}
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
2538c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, geneve->dev);
2548c2ecf20Sopenharmony_ci	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (tun_dst)
2578c2ecf20Sopenharmony_ci		skb_dst_set(skb, &tun_dst->dst);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* Ignore packet loops (and multicast echo) */
2608c2ecf20Sopenharmony_ci	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) {
2618c2ecf20Sopenharmony_ci		geneve->dev->stats.rx_errors++;
2628c2ecf20Sopenharmony_ci		goto drop;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	oiph = skb_network_header(skb);
2668c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (geneve_get_sk_family(gs) == AF_INET)
2698c2ecf20Sopenharmony_ci		err = IP_ECN_decapsulate(oiph, skb);
2708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2718c2ecf20Sopenharmony_ci	else
2728c2ecf20Sopenharmony_ci		err = IP6_ECN_decapsulate(oiph, skb);
2738c2ecf20Sopenharmony_ci#endif
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (unlikely(err)) {
2768c2ecf20Sopenharmony_ci		if (log_ecn_error) {
2778c2ecf20Sopenharmony_ci			if (geneve_get_sk_family(gs) == AF_INET)
2788c2ecf20Sopenharmony_ci				net_info_ratelimited("non-ECT from %pI4 "
2798c2ecf20Sopenharmony_ci						     "with TOS=%#x\n",
2808c2ecf20Sopenharmony_ci						     &((struct iphdr *)oiph)->saddr,
2818c2ecf20Sopenharmony_ci						     ((struct iphdr *)oiph)->tos);
2828c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2838c2ecf20Sopenharmony_ci			else
2848c2ecf20Sopenharmony_ci				net_info_ratelimited("non-ECT from %pI6\n",
2858c2ecf20Sopenharmony_ci						     &((struct ipv6hdr *)oiph)->saddr);
2868c2ecf20Sopenharmony_ci#endif
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci		if (err > 1) {
2898c2ecf20Sopenharmony_ci			++geneve->dev->stats.rx_frame_errors;
2908c2ecf20Sopenharmony_ci			++geneve->dev->stats.rx_errors;
2918c2ecf20Sopenharmony_ci			goto drop;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	len = skb->len;
2968c2ecf20Sopenharmony_ci	err = gro_cells_receive(&geneve->gro_cells, skb);
2978c2ecf20Sopenharmony_ci	if (likely(err == NET_RX_SUCCESS))
2988c2ecf20Sopenharmony_ci		dev_sw_netstats_rx_add(geneve->dev, len);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return;
3018c2ecf20Sopenharmony_cidrop:
3028c2ecf20Sopenharmony_ci	/* Consume bad packet */
3038c2ecf20Sopenharmony_ci	kfree_skb(skb);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/* Setup stats when device is created */
3078c2ecf20Sopenharmony_cistatic int geneve_init(struct net_device *dev)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
3108c2ecf20Sopenharmony_ci	int err;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
3138c2ecf20Sopenharmony_ci	if (!dev->tstats)
3148c2ecf20Sopenharmony_ci		return -ENOMEM;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	err = gro_cells_init(&geneve->gro_cells, dev);
3178c2ecf20Sopenharmony_ci	if (err) {
3188c2ecf20Sopenharmony_ci		free_percpu(dev->tstats);
3198c2ecf20Sopenharmony_ci		return err;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	err = dst_cache_init(&geneve->cfg.info.dst_cache, GFP_KERNEL);
3238c2ecf20Sopenharmony_ci	if (err) {
3248c2ecf20Sopenharmony_ci		free_percpu(dev->tstats);
3258c2ecf20Sopenharmony_ci		gro_cells_destroy(&geneve->gro_cells);
3268c2ecf20Sopenharmony_ci		return err;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic void geneve_uninit(struct net_device *dev)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	dst_cache_destroy(&geneve->cfg.info.dst_cache);
3368c2ecf20Sopenharmony_ci	gro_cells_destroy(&geneve->gro_cells);
3378c2ecf20Sopenharmony_ci	free_percpu(dev->tstats);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/* Callback from net/ipv4/udp.c to receive packets */
3418c2ecf20Sopenharmony_cistatic int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct genevehdr *geneveh;
3448c2ecf20Sopenharmony_ci	struct geneve_dev *geneve;
3458c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
3468c2ecf20Sopenharmony_ci	int opts_len;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* Need UDP and Geneve header to be present */
3498c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
3508c2ecf20Sopenharmony_ci		goto drop;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Return packets with reserved bits set */
3538c2ecf20Sopenharmony_ci	geneveh = geneve_hdr(skb);
3548c2ecf20Sopenharmony_ci	if (unlikely(geneveh->ver != GENEVE_VER))
3558c2ecf20Sopenharmony_ci		goto drop;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
3588c2ecf20Sopenharmony_ci		goto drop;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	gs = rcu_dereference_sk_user_data(sk);
3618c2ecf20Sopenharmony_ci	if (!gs)
3628c2ecf20Sopenharmony_ci		goto drop;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	geneve = geneve_lookup_skb(gs, skb);
3658c2ecf20Sopenharmony_ci	if (!geneve)
3668c2ecf20Sopenharmony_ci		goto drop;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	opts_len = geneveh->opt_len * 4;
3698c2ecf20Sopenharmony_ci	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
3708c2ecf20Sopenharmony_ci				 htons(ETH_P_TEB),
3718c2ecf20Sopenharmony_ci				 !net_eq(geneve->net, dev_net(geneve->dev)))) {
3728c2ecf20Sopenharmony_ci		geneve->dev->stats.rx_dropped++;
3738c2ecf20Sopenharmony_ci		goto drop;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	geneve_rx(geneve, gs, skb);
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cidrop:
3808c2ecf20Sopenharmony_ci	/* Consume bad packet */
3818c2ecf20Sopenharmony_ci	kfree_skb(skb);
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci/* Callback from net/ipv{4,6}/udp.c to check that we have a tunnel for errors */
3868c2ecf20Sopenharmony_cistatic int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct genevehdr *geneveh;
3898c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
3908c2ecf20Sopenharmony_ci	u8 zero_vni[3] = { 0 };
3918c2ecf20Sopenharmony_ci	u8 *vni = zero_vni;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
3948c2ecf20Sopenharmony_ci		return -EINVAL;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	geneveh = geneve_hdr(skb);
3978c2ecf20Sopenharmony_ci	if (geneveh->ver != GENEVE_VER)
3988c2ecf20Sopenharmony_ci		return -EINVAL;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (geneveh->proto_type != htons(ETH_P_TEB))
4018c2ecf20Sopenharmony_ci		return -EINVAL;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	gs = rcu_dereference_sk_user_data(sk);
4048c2ecf20Sopenharmony_ci	if (!gs)
4058c2ecf20Sopenharmony_ci		return -ENOENT;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (geneve_get_sk_family(gs) == AF_INET) {
4088c2ecf20Sopenharmony_ci		struct iphdr *iph = ip_hdr(skb);
4098c2ecf20Sopenharmony_ci		__be32 addr4 = 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		if (!gs->collect_md) {
4128c2ecf20Sopenharmony_ci			vni = geneve_hdr(skb)->vni;
4138c2ecf20Sopenharmony_ci			addr4 = iph->daddr;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		return geneve_lookup(gs, addr4, vni) ? 0 : -ENOENT;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
4208c2ecf20Sopenharmony_ci	if (geneve_get_sk_family(gs) == AF_INET6) {
4218c2ecf20Sopenharmony_ci		struct ipv6hdr *ip6h = ipv6_hdr(skb);
4228c2ecf20Sopenharmony_ci		struct in6_addr addr6;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		memset(&addr6, 0, sizeof(struct in6_addr));
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		if (!gs->collect_md) {
4278c2ecf20Sopenharmony_ci			vni = geneve_hdr(skb)->vni;
4288c2ecf20Sopenharmony_ci			addr6 = ip6h->daddr;
4298c2ecf20Sopenharmony_ci		}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		return geneve6_lookup(gs, addr6, vni) ? 0 : -ENOENT;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci#endif
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return -EPFNOSUPPORT;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic struct socket *geneve_create_sock(struct net *net, bool ipv6,
4398c2ecf20Sopenharmony_ci					 __be16 port, bool ipv6_rx_csum)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct socket *sock;
4428c2ecf20Sopenharmony_ci	struct udp_port_cfg udp_conf;
4438c2ecf20Sopenharmony_ci	int err;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	memset(&udp_conf, 0, sizeof(udp_conf));
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (ipv6) {
4488c2ecf20Sopenharmony_ci		udp_conf.family = AF_INET6;
4498c2ecf20Sopenharmony_ci		udp_conf.ipv6_v6only = 1;
4508c2ecf20Sopenharmony_ci		udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
4518c2ecf20Sopenharmony_ci	} else {
4528c2ecf20Sopenharmony_ci		udp_conf.family = AF_INET;
4538c2ecf20Sopenharmony_ci		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	udp_conf.local_udp_port = port;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* Open UDP socket */
4598c2ecf20Sopenharmony_ci	err = udp_sock_create(net, &udp_conf, &sock);
4608c2ecf20Sopenharmony_ci	if (err < 0)
4618c2ecf20Sopenharmony_ci		return ERR_PTR(err);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return sock;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic int geneve_hlen(struct genevehdr *gh)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	return sizeof(*gh) + gh->opt_len * 4;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic struct sk_buff *geneve_gro_receive(struct sock *sk,
4728c2ecf20Sopenharmony_ci					  struct list_head *head,
4738c2ecf20Sopenharmony_ci					  struct sk_buff *skb)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct sk_buff *pp = NULL;
4768c2ecf20Sopenharmony_ci	struct sk_buff *p;
4778c2ecf20Sopenharmony_ci	struct genevehdr *gh, *gh2;
4788c2ecf20Sopenharmony_ci	unsigned int hlen, gh_len, off_gnv;
4798c2ecf20Sopenharmony_ci	const struct packet_offload *ptype;
4808c2ecf20Sopenharmony_ci	__be16 type;
4818c2ecf20Sopenharmony_ci	int flush = 1;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	off_gnv = skb_gro_offset(skb);
4848c2ecf20Sopenharmony_ci	hlen = off_gnv + sizeof(*gh);
4858c2ecf20Sopenharmony_ci	gh = skb_gro_header_fast(skb, off_gnv);
4868c2ecf20Sopenharmony_ci	if (skb_gro_header_hard(skb, hlen)) {
4878c2ecf20Sopenharmony_ci		gh = skb_gro_header_slow(skb, hlen, off_gnv);
4888c2ecf20Sopenharmony_ci		if (unlikely(!gh))
4898c2ecf20Sopenharmony_ci			goto out;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (gh->ver != GENEVE_VER || gh->oam)
4938c2ecf20Sopenharmony_ci		goto out;
4948c2ecf20Sopenharmony_ci	gh_len = geneve_hlen(gh);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	hlen = off_gnv + gh_len;
4978c2ecf20Sopenharmony_ci	if (skb_gro_header_hard(skb, hlen)) {
4988c2ecf20Sopenharmony_ci		gh = skb_gro_header_slow(skb, hlen, off_gnv);
4998c2ecf20Sopenharmony_ci		if (unlikely(!gh))
5008c2ecf20Sopenharmony_ci			goto out;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	list_for_each_entry(p, head, list) {
5048c2ecf20Sopenharmony_ci		if (!NAPI_GRO_CB(p)->same_flow)
5058c2ecf20Sopenharmony_ci			continue;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		gh2 = (struct genevehdr *)(p->data + off_gnv);
5088c2ecf20Sopenharmony_ci		if (gh->opt_len != gh2->opt_len ||
5098c2ecf20Sopenharmony_ci		    memcmp(gh, gh2, gh_len)) {
5108c2ecf20Sopenharmony_ci			NAPI_GRO_CB(p)->same_flow = 0;
5118c2ecf20Sopenharmony_ci			continue;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	type = gh->proto_type;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	rcu_read_lock();
5188c2ecf20Sopenharmony_ci	ptype = gro_find_receive_by_type(type);
5198c2ecf20Sopenharmony_ci	if (!ptype)
5208c2ecf20Sopenharmony_ci		goto out_unlock;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	skb_gro_pull(skb, gh_len);
5238c2ecf20Sopenharmony_ci	skb_gro_postpull_rcsum(skb, gh, gh_len);
5248c2ecf20Sopenharmony_ci	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
5258c2ecf20Sopenharmony_ci	flush = 0;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ciout_unlock:
5288c2ecf20Sopenharmony_ci	rcu_read_unlock();
5298c2ecf20Sopenharmony_ciout:
5308c2ecf20Sopenharmony_ci	skb_gro_flush_final(skb, pp, flush);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	return pp;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
5368c2ecf20Sopenharmony_ci			       int nhoff)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct genevehdr *gh;
5398c2ecf20Sopenharmony_ci	struct packet_offload *ptype;
5408c2ecf20Sopenharmony_ci	__be16 type;
5418c2ecf20Sopenharmony_ci	int gh_len;
5428c2ecf20Sopenharmony_ci	int err = -ENOSYS;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	gh = (struct genevehdr *)(skb->data + nhoff);
5458c2ecf20Sopenharmony_ci	gh_len = geneve_hlen(gh);
5468c2ecf20Sopenharmony_ci	type = gh->proto_type;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	rcu_read_lock();
5498c2ecf20Sopenharmony_ci	ptype = gro_find_complete_by_type(type);
5508c2ecf20Sopenharmony_ci	if (ptype)
5518c2ecf20Sopenharmony_ci		err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	rcu_read_unlock();
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	skb_set_inner_mac_header(skb, nhoff + gh_len);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return err;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci/* Create new listen socket if needed */
5618c2ecf20Sopenharmony_cistatic struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
5628c2ecf20Sopenharmony_ci						bool ipv6, bool ipv6_rx_csum)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
5658c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
5668c2ecf20Sopenharmony_ci	struct socket *sock;
5678c2ecf20Sopenharmony_ci	struct udp_tunnel_sock_cfg tunnel_cfg;
5688c2ecf20Sopenharmony_ci	int h;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	gs = kzalloc(sizeof(*gs), GFP_KERNEL);
5718c2ecf20Sopenharmony_ci	if (!gs)
5728c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	sock = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
5758c2ecf20Sopenharmony_ci	if (IS_ERR(sock)) {
5768c2ecf20Sopenharmony_ci		kfree(gs);
5778c2ecf20Sopenharmony_ci		return ERR_CAST(sock);
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	gs->sock = sock;
5818c2ecf20Sopenharmony_ci	gs->refcnt = 1;
5828c2ecf20Sopenharmony_ci	for (h = 0; h < VNI_HASH_SIZE; ++h)
5838c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&gs->vni_list[h]);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* Initialize the geneve udp offloads structure */
5868c2ecf20Sopenharmony_ci	udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Mark socket as an encapsulation socket */
5898c2ecf20Sopenharmony_ci	memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
5908c2ecf20Sopenharmony_ci	tunnel_cfg.sk_user_data = gs;
5918c2ecf20Sopenharmony_ci	tunnel_cfg.encap_type = 1;
5928c2ecf20Sopenharmony_ci	tunnel_cfg.gro_receive = geneve_gro_receive;
5938c2ecf20Sopenharmony_ci	tunnel_cfg.gro_complete = geneve_gro_complete;
5948c2ecf20Sopenharmony_ci	tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
5958c2ecf20Sopenharmony_ci	tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup;
5968c2ecf20Sopenharmony_ci	tunnel_cfg.encap_destroy = NULL;
5978c2ecf20Sopenharmony_ci	setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
5988c2ecf20Sopenharmony_ci	list_add(&gs->list, &gn->sock_list);
5998c2ecf20Sopenharmony_ci	return gs;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic void __geneve_sock_release(struct geneve_sock *gs)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	if (!gs || --gs->refcnt)
6058c2ecf20Sopenharmony_ci		return;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	list_del(&gs->list);
6088c2ecf20Sopenharmony_ci	udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
6098c2ecf20Sopenharmony_ci	udp_tunnel_sock_release(gs->sock);
6108c2ecf20Sopenharmony_ci	kfree_rcu(gs, rcu);
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic void geneve_sock_release(struct geneve_dev *geneve)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
6168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
6178c2ecf20Sopenharmony_ci	struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock6, NULL);
6208c2ecf20Sopenharmony_ci#endif
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock4, NULL);
6238c2ecf20Sopenharmony_ci	synchronize_net();
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	__geneve_sock_release(gs4);
6268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
6278c2ecf20Sopenharmony_ci	__geneve_sock_release(gs6);
6288c2ecf20Sopenharmony_ci#endif
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
6328c2ecf20Sopenharmony_ci					    sa_family_t family,
6338c2ecf20Sopenharmony_ci					    __be16 dst_port)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	list_for_each_entry(gs, &gn->sock_list, list) {
6388c2ecf20Sopenharmony_ci		if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
6398c2ecf20Sopenharmony_ci		    geneve_get_sk_family(gs) == family) {
6408c2ecf20Sopenharmony_ci			return gs;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci	return NULL;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	struct net *net = geneve->net;
6498c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
6508c2ecf20Sopenharmony_ci	struct geneve_dev_node *node;
6518c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
6528c2ecf20Sopenharmony_ci	__u8 vni[3];
6538c2ecf20Sopenharmony_ci	__u32 hash;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->cfg.info.key.tp_dst);
6568c2ecf20Sopenharmony_ci	if (gs) {
6578c2ecf20Sopenharmony_ci		gs->refcnt++;
6588c2ecf20Sopenharmony_ci		goto out;
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6,
6628c2ecf20Sopenharmony_ci				  geneve->cfg.use_udp6_rx_checksums);
6638c2ecf20Sopenharmony_ci	if (IS_ERR(gs))
6648c2ecf20Sopenharmony_ci		return PTR_ERR(gs);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ciout:
6678c2ecf20Sopenharmony_ci	gs->collect_md = geneve->cfg.collect_md;
6688c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
6698c2ecf20Sopenharmony_ci	if (ipv6) {
6708c2ecf20Sopenharmony_ci		rcu_assign_pointer(geneve->sock6, gs);
6718c2ecf20Sopenharmony_ci		node = &geneve->hlist6;
6728c2ecf20Sopenharmony_ci	} else
6738c2ecf20Sopenharmony_ci#endif
6748c2ecf20Sopenharmony_ci	{
6758c2ecf20Sopenharmony_ci		rcu_assign_pointer(geneve->sock4, gs);
6768c2ecf20Sopenharmony_ci		node = &geneve->hlist4;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci	node->geneve = geneve;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	tunnel_id_to_vni(geneve->cfg.info.key.tun_id, vni);
6818c2ecf20Sopenharmony_ci	hash = geneve_net_vni_hash(vni);
6828c2ecf20Sopenharmony_ci	hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]);
6838c2ecf20Sopenharmony_ci	return 0;
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic int geneve_open(struct net_device *dev)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
6898c2ecf20Sopenharmony_ci	bool metadata = geneve->cfg.collect_md;
6908c2ecf20Sopenharmony_ci	bool ipv4, ipv6;
6918c2ecf20Sopenharmony_ci	int ret = 0;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
6948c2ecf20Sopenharmony_ci	ipv4 = !ipv6 || metadata;
6958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
6968c2ecf20Sopenharmony_ci	if (ipv6) {
6978c2ecf20Sopenharmony_ci		ret = geneve_sock_add(geneve, true);
6988c2ecf20Sopenharmony_ci		if (ret < 0 && ret != -EAFNOSUPPORT)
6998c2ecf20Sopenharmony_ci			ipv4 = false;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci#endif
7028c2ecf20Sopenharmony_ci	if (ipv4)
7038c2ecf20Sopenharmony_ci		ret = geneve_sock_add(geneve, false);
7048c2ecf20Sopenharmony_ci	if (ret < 0)
7058c2ecf20Sopenharmony_ci		geneve_sock_release(geneve);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	return ret;
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_cistatic int geneve_stop(struct net_device *dev)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	hlist_del_init_rcu(&geneve->hlist4.hlist);
7158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
7168c2ecf20Sopenharmony_ci	hlist_del_init_rcu(&geneve->hlist6.hlist);
7178c2ecf20Sopenharmony_ci#endif
7188c2ecf20Sopenharmony_ci	geneve_sock_release(geneve);
7198c2ecf20Sopenharmony_ci	return 0;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic void geneve_build_header(struct genevehdr *geneveh,
7238c2ecf20Sopenharmony_ci				const struct ip_tunnel_info *info)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	geneveh->ver = GENEVE_VER;
7268c2ecf20Sopenharmony_ci	geneveh->opt_len = info->options_len / 4;
7278c2ecf20Sopenharmony_ci	geneveh->oam = !!(info->key.tun_flags & TUNNEL_OAM);
7288c2ecf20Sopenharmony_ci	geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
7298c2ecf20Sopenharmony_ci	geneveh->rsvd1 = 0;
7308c2ecf20Sopenharmony_ci	tunnel_id_to_vni(info->key.tun_id, geneveh->vni);
7318c2ecf20Sopenharmony_ci	geneveh->proto_type = htons(ETH_P_TEB);
7328c2ecf20Sopenharmony_ci	geneveh->rsvd2 = 0;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
7358c2ecf20Sopenharmony_ci		ip_tunnel_info_opts_get(geneveh->options, info);
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
7398c2ecf20Sopenharmony_ci			    const struct ip_tunnel_info *info,
7408c2ecf20Sopenharmony_ci			    bool xnet, int ip_hdr_len)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
7438c2ecf20Sopenharmony_ci	struct genevehdr *gnvh;
7448c2ecf20Sopenharmony_ci	int min_headroom;
7458c2ecf20Sopenharmony_ci	int err;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
7488c2ecf20Sopenharmony_ci	skb_scrub_packet(skb, xnet);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +
7518c2ecf20Sopenharmony_ci		       GENEVE_BASE_HLEN + info->options_len + ip_hdr_len;
7528c2ecf20Sopenharmony_ci	err = skb_cow_head(skb, min_headroom);
7538c2ecf20Sopenharmony_ci	if (unlikely(err))
7548c2ecf20Sopenharmony_ci		goto free_dst;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	err = udp_tunnel_handle_offloads(skb, udp_sum);
7578c2ecf20Sopenharmony_ci	if (err)
7588c2ecf20Sopenharmony_ci		goto free_dst;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
7618c2ecf20Sopenharmony_ci	geneve_build_header(gnvh, info);
7628c2ecf20Sopenharmony_ci	skb_set_inner_protocol(skb, htons(ETH_P_TEB));
7638c2ecf20Sopenharmony_ci	return 0;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cifree_dst:
7668c2ecf20Sopenharmony_ci	dst_release(dst);
7678c2ecf20Sopenharmony_ci	return err;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
7718c2ecf20Sopenharmony_ci				       struct net_device *dev,
7728c2ecf20Sopenharmony_ci				       struct geneve_sock *gs4,
7738c2ecf20Sopenharmony_ci				       struct flowi4 *fl4,
7748c2ecf20Sopenharmony_ci				       const struct ip_tunnel_info *info,
7758c2ecf20Sopenharmony_ci				       __be16 dport, __be16 sport,
7768c2ecf20Sopenharmony_ci				       __u8 *full_tos)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
7798c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
7808c2ecf20Sopenharmony_ci	struct dst_cache *dst_cache;
7818c2ecf20Sopenharmony_ci	struct rtable *rt = NULL;
7828c2ecf20Sopenharmony_ci	__u8 tos;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (!gs4)
7858c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	memset(fl4, 0, sizeof(*fl4));
7888c2ecf20Sopenharmony_ci	fl4->flowi4_mark = skb->mark;
7898c2ecf20Sopenharmony_ci	fl4->flowi4_proto = IPPROTO_UDP;
7908c2ecf20Sopenharmony_ci	fl4->daddr = info->key.u.ipv4.dst;
7918c2ecf20Sopenharmony_ci	fl4->saddr = info->key.u.ipv4.src;
7928c2ecf20Sopenharmony_ci	fl4->fl4_dport = dport;
7938c2ecf20Sopenharmony_ci	fl4->fl4_sport = sport;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	tos = info->key.tos;
7968c2ecf20Sopenharmony_ci	if ((tos == 1) && !geneve->cfg.collect_md) {
7978c2ecf20Sopenharmony_ci		tos = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
7988c2ecf20Sopenharmony_ci		use_cache = false;
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci	fl4->flowi4_tos = RT_TOS(tos);
8018c2ecf20Sopenharmony_ci	if (full_tos)
8028c2ecf20Sopenharmony_ci		*full_tos = tos;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	dst_cache = (struct dst_cache *)&info->dst_cache;
8058c2ecf20Sopenharmony_ci	if (use_cache) {
8068c2ecf20Sopenharmony_ci		rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
8078c2ecf20Sopenharmony_ci		if (rt)
8088c2ecf20Sopenharmony_ci			return rt;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci	rt = ip_route_output_key(geneve->net, fl4);
8118c2ecf20Sopenharmony_ci	if (IS_ERR(rt)) {
8128c2ecf20Sopenharmony_ci		netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr);
8138c2ecf20Sopenharmony_ci		return ERR_PTR(-ENETUNREACH);
8148c2ecf20Sopenharmony_ci	}
8158c2ecf20Sopenharmony_ci	if (rt->dst.dev == dev) { /* is this necessary? */
8168c2ecf20Sopenharmony_ci		netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
8178c2ecf20Sopenharmony_ci		ip_rt_put(rt);
8188c2ecf20Sopenharmony_ci		return ERR_PTR(-ELOOP);
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci	if (use_cache)
8218c2ecf20Sopenharmony_ci		dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
8228c2ecf20Sopenharmony_ci	return rt;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
8268c2ecf20Sopenharmony_cistatic struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
8278c2ecf20Sopenharmony_ci					   struct net_device *dev,
8288c2ecf20Sopenharmony_ci					   struct geneve_sock *gs6,
8298c2ecf20Sopenharmony_ci					   struct flowi6 *fl6,
8308c2ecf20Sopenharmony_ci					   const struct ip_tunnel_info *info,
8318c2ecf20Sopenharmony_ci					   __be16 dport, __be16 sport)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
8348c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
8358c2ecf20Sopenharmony_ci	struct dst_entry *dst = NULL;
8368c2ecf20Sopenharmony_ci	struct dst_cache *dst_cache;
8378c2ecf20Sopenharmony_ci	__u8 prio;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (!gs6)
8408c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	memset(fl6, 0, sizeof(*fl6));
8438c2ecf20Sopenharmony_ci	fl6->flowi6_mark = skb->mark;
8448c2ecf20Sopenharmony_ci	fl6->flowi6_proto = IPPROTO_UDP;
8458c2ecf20Sopenharmony_ci	fl6->daddr = info->key.u.ipv6.dst;
8468c2ecf20Sopenharmony_ci	fl6->saddr = info->key.u.ipv6.src;
8478c2ecf20Sopenharmony_ci	fl6->fl6_dport = dport;
8488c2ecf20Sopenharmony_ci	fl6->fl6_sport = sport;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	prio = info->key.tos;
8518c2ecf20Sopenharmony_ci	if ((prio == 1) && !geneve->cfg.collect_md) {
8528c2ecf20Sopenharmony_ci		prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
8538c2ecf20Sopenharmony_ci		use_cache = false;
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	fl6->flowlabel = ip6_make_flowinfo(prio, info->key.label);
8578c2ecf20Sopenharmony_ci	dst_cache = (struct dst_cache *)&info->dst_cache;
8588c2ecf20Sopenharmony_ci	if (use_cache) {
8598c2ecf20Sopenharmony_ci		dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
8608c2ecf20Sopenharmony_ci		if (dst)
8618c2ecf20Sopenharmony_ci			return dst;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci	dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
8648c2ecf20Sopenharmony_ci					      NULL);
8658c2ecf20Sopenharmony_ci	if (IS_ERR(dst)) {
8668c2ecf20Sopenharmony_ci		netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr);
8678c2ecf20Sopenharmony_ci		return ERR_PTR(-ENETUNREACH);
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci	if (dst->dev == dev) { /* is this necessary? */
8708c2ecf20Sopenharmony_ci		netdev_dbg(dev, "circular route to %pI6\n", &fl6->daddr);
8718c2ecf20Sopenharmony_ci		dst_release(dst);
8728c2ecf20Sopenharmony_ci		return ERR_PTR(-ELOOP);
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (use_cache)
8768c2ecf20Sopenharmony_ci		dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
8778c2ecf20Sopenharmony_ci	return dst;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci#endif
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistatic int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
8828c2ecf20Sopenharmony_ci			   struct geneve_dev *geneve,
8838c2ecf20Sopenharmony_ci			   const struct ip_tunnel_info *info)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
8868c2ecf20Sopenharmony_ci	struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
8878c2ecf20Sopenharmony_ci	const struct ip_tunnel_key *key = &info->key;
8888c2ecf20Sopenharmony_ci	struct rtable *rt;
8898c2ecf20Sopenharmony_ci	struct flowi4 fl4;
8908c2ecf20Sopenharmony_ci	__u8 full_tos;
8918c2ecf20Sopenharmony_ci	__u8 tos, ttl;
8928c2ecf20Sopenharmony_ci	__be16 df = 0;
8938c2ecf20Sopenharmony_ci	__be16 sport;
8948c2ecf20Sopenharmony_ci	int err;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (!pskb_inet_may_pull(skb))
8978c2ecf20Sopenharmony_ci		return -EINVAL;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
9008c2ecf20Sopenharmony_ci	rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
9018c2ecf20Sopenharmony_ci			      geneve->cfg.info.key.tp_dst, sport, &full_tos);
9028c2ecf20Sopenharmony_ci	if (IS_ERR(rt))
9038c2ecf20Sopenharmony_ci		return PTR_ERR(rt);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	err = skb_tunnel_check_pmtu(skb, &rt->dst,
9068c2ecf20Sopenharmony_ci				    GENEVE_IPV4_HLEN + info->options_len,
9078c2ecf20Sopenharmony_ci				    netif_is_any_bridge_port(dev));
9088c2ecf20Sopenharmony_ci	if (err < 0) {
9098c2ecf20Sopenharmony_ci		dst_release(&rt->dst);
9108c2ecf20Sopenharmony_ci		return err;
9118c2ecf20Sopenharmony_ci	} else if (err) {
9128c2ecf20Sopenharmony_ci		struct ip_tunnel_info *info;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		info = skb_tunnel_info(skb);
9158c2ecf20Sopenharmony_ci		if (info) {
9168c2ecf20Sopenharmony_ci			struct ip_tunnel_info *unclone;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci			unclone = skb_tunnel_info_unclone(skb);
9198c2ecf20Sopenharmony_ci			if (unlikely(!unclone)) {
9208c2ecf20Sopenharmony_ci				dst_release(&rt->dst);
9218c2ecf20Sopenharmony_ci				return -ENOMEM;
9228c2ecf20Sopenharmony_ci			}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci			unclone->key.u.ipv4.dst = fl4.saddr;
9258c2ecf20Sopenharmony_ci			unclone->key.u.ipv4.src = fl4.daddr;
9268c2ecf20Sopenharmony_ci		}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		if (!pskb_may_pull(skb, ETH_HLEN)) {
9298c2ecf20Sopenharmony_ci			dst_release(&rt->dst);
9308c2ecf20Sopenharmony_ci			return -EINVAL;
9318c2ecf20Sopenharmony_ci		}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, geneve->dev);
9348c2ecf20Sopenharmony_ci		netif_rx(skb);
9358c2ecf20Sopenharmony_ci		dst_release(&rt->dst);
9368c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (geneve->cfg.collect_md) {
9408c2ecf20Sopenharmony_ci		tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
9418c2ecf20Sopenharmony_ci		ttl = key->ttl;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
9448c2ecf20Sopenharmony_ci	} else {
9458c2ecf20Sopenharmony_ci		tos = ip_tunnel_ecn_encap(full_tos, ip_hdr(skb), skb);
9468c2ecf20Sopenharmony_ci		if (geneve->cfg.ttl_inherit)
9478c2ecf20Sopenharmony_ci			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
9488c2ecf20Sopenharmony_ci		else
9498c2ecf20Sopenharmony_ci			ttl = key->ttl;
9508c2ecf20Sopenharmony_ci		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		if (geneve->cfg.df == GENEVE_DF_SET) {
9538c2ecf20Sopenharmony_ci			df = htons(IP_DF);
9548c2ecf20Sopenharmony_ci		} else if (geneve->cfg.df == GENEVE_DF_INHERIT) {
9558c2ecf20Sopenharmony_ci			struct ethhdr *eth = eth_hdr(skb);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci			if (ntohs(eth->h_proto) == ETH_P_IPV6) {
9588c2ecf20Sopenharmony_ci				df = htons(IP_DF);
9598c2ecf20Sopenharmony_ci			} else if (ntohs(eth->h_proto) == ETH_P_IP) {
9608c2ecf20Sopenharmony_ci				struct iphdr *iph = ip_hdr(skb);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci				if (iph->frag_off & htons(IP_DF))
9638c2ecf20Sopenharmony_ci					df = htons(IP_DF);
9648c2ecf20Sopenharmony_ci			}
9658c2ecf20Sopenharmony_ci		}
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr));
9698c2ecf20Sopenharmony_ci	if (unlikely(err))
9708c2ecf20Sopenharmony_ci		return err;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
9738c2ecf20Sopenharmony_ci			    tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
9748c2ecf20Sopenharmony_ci			    !net_eq(geneve->net, dev_net(geneve->dev)),
9758c2ecf20Sopenharmony_ci			    !(info->key.tun_flags & TUNNEL_CSUM));
9768c2ecf20Sopenharmony_ci	return 0;
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
9808c2ecf20Sopenharmony_cistatic int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
9818c2ecf20Sopenharmony_ci			    struct geneve_dev *geneve,
9828c2ecf20Sopenharmony_ci			    const struct ip_tunnel_info *info)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
9858c2ecf20Sopenharmony_ci	struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
9868c2ecf20Sopenharmony_ci	const struct ip_tunnel_key *key = &info->key;
9878c2ecf20Sopenharmony_ci	struct dst_entry *dst = NULL;
9888c2ecf20Sopenharmony_ci	struct flowi6 fl6;
9898c2ecf20Sopenharmony_ci	__u8 prio, ttl;
9908c2ecf20Sopenharmony_ci	__be16 sport;
9918c2ecf20Sopenharmony_ci	int err;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (!pskb_inet_may_pull(skb))
9948c2ecf20Sopenharmony_ci		return -EINVAL;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
9978c2ecf20Sopenharmony_ci	dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
9988c2ecf20Sopenharmony_ci				geneve->cfg.info.key.tp_dst, sport);
9998c2ecf20Sopenharmony_ci	if (IS_ERR(dst))
10008c2ecf20Sopenharmony_ci		return PTR_ERR(dst);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	err = skb_tunnel_check_pmtu(skb, dst,
10038c2ecf20Sopenharmony_ci				    GENEVE_IPV6_HLEN + info->options_len,
10048c2ecf20Sopenharmony_ci				    netif_is_any_bridge_port(dev));
10058c2ecf20Sopenharmony_ci	if (err < 0) {
10068c2ecf20Sopenharmony_ci		dst_release(dst);
10078c2ecf20Sopenharmony_ci		return err;
10088c2ecf20Sopenharmony_ci	} else if (err) {
10098c2ecf20Sopenharmony_ci		struct ip_tunnel_info *info = skb_tunnel_info(skb);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci		if (info) {
10128c2ecf20Sopenharmony_ci			struct ip_tunnel_info *unclone;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci			unclone = skb_tunnel_info_unclone(skb);
10158c2ecf20Sopenharmony_ci			if (unlikely(!unclone)) {
10168c2ecf20Sopenharmony_ci				dst_release(dst);
10178c2ecf20Sopenharmony_ci				return -ENOMEM;
10188c2ecf20Sopenharmony_ci			}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci			unclone->key.u.ipv6.dst = fl6.saddr;
10218c2ecf20Sopenharmony_ci			unclone->key.u.ipv6.src = fl6.daddr;
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		if (!pskb_may_pull(skb, ETH_HLEN)) {
10258c2ecf20Sopenharmony_ci			dst_release(dst);
10268c2ecf20Sopenharmony_ci			return -EINVAL;
10278c2ecf20Sopenharmony_ci		}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, geneve->dev);
10308c2ecf20Sopenharmony_ci		netif_rx(skb);
10318c2ecf20Sopenharmony_ci		dst_release(dst);
10328c2ecf20Sopenharmony_ci		return -EMSGSIZE;
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (geneve->cfg.collect_md) {
10368c2ecf20Sopenharmony_ci		prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
10378c2ecf20Sopenharmony_ci		ttl = key->ttl;
10388c2ecf20Sopenharmony_ci	} else {
10398c2ecf20Sopenharmony_ci		prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
10408c2ecf20Sopenharmony_ci					   ip_hdr(skb), skb);
10418c2ecf20Sopenharmony_ci		if (geneve->cfg.ttl_inherit)
10428c2ecf20Sopenharmony_ci			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
10438c2ecf20Sopenharmony_ci		else
10448c2ecf20Sopenharmony_ci			ttl = key->ttl;
10458c2ecf20Sopenharmony_ci		ttl = ttl ? : ip6_dst_hoplimit(dst);
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr));
10488c2ecf20Sopenharmony_ci	if (unlikely(err))
10498c2ecf20Sopenharmony_ci		return err;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
10528c2ecf20Sopenharmony_ci			     &fl6.saddr, &fl6.daddr, prio, ttl,
10538c2ecf20Sopenharmony_ci			     info->key.label, sport, geneve->cfg.info.key.tp_dst,
10548c2ecf20Sopenharmony_ci			     !(info->key.tun_flags & TUNNEL_CSUM));
10558c2ecf20Sopenharmony_ci	return 0;
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci#endif
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
10628c2ecf20Sopenharmony_ci	struct ip_tunnel_info *info = NULL;
10638c2ecf20Sopenharmony_ci	int err;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (geneve->cfg.collect_md) {
10668c2ecf20Sopenharmony_ci		info = skb_tunnel_info(skb);
10678c2ecf20Sopenharmony_ci		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
10688c2ecf20Sopenharmony_ci			netdev_dbg(dev, "no tunnel metadata\n");
10698c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
10708c2ecf20Sopenharmony_ci			dev->stats.tx_dropped++;
10718c2ecf20Sopenharmony_ci			return NETDEV_TX_OK;
10728c2ecf20Sopenharmony_ci		}
10738c2ecf20Sopenharmony_ci	} else {
10748c2ecf20Sopenharmony_ci		info = &geneve->cfg.info;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	rcu_read_lock();
10788c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
10798c2ecf20Sopenharmony_ci	if (info->mode & IP_TUNNEL_INFO_IPV6)
10808c2ecf20Sopenharmony_ci		err = geneve6_xmit_skb(skb, dev, geneve, info);
10818c2ecf20Sopenharmony_ci	else
10828c2ecf20Sopenharmony_ci#endif
10838c2ecf20Sopenharmony_ci		err = geneve_xmit_skb(skb, dev, geneve, info);
10848c2ecf20Sopenharmony_ci	rcu_read_unlock();
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (likely(!err))
10878c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
10908c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	if (err == -ELOOP)
10938c2ecf20Sopenharmony_ci		dev->stats.collisions++;
10948c2ecf20Sopenharmony_ci	else if (err == -ENETUNREACH)
10958c2ecf20Sopenharmony_ci		dev->stats.tx_carrier_errors++;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	dev->stats.tx_errors++;
10988c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic int geneve_change_mtu(struct net_device *dev, int new_mtu)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	if (new_mtu > dev->max_mtu)
11048c2ecf20Sopenharmony_ci		new_mtu = dev->max_mtu;
11058c2ecf20Sopenharmony_ci	else if (new_mtu < dev->min_mtu)
11068c2ecf20Sopenharmony_ci		new_mtu = dev->min_mtu;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	dev->mtu = new_mtu;
11098c2ecf20Sopenharmony_ci	return 0;
11108c2ecf20Sopenharmony_ci}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_cistatic int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	struct ip_tunnel_info *info = skb_tunnel_info(skb);
11158c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
11168c2ecf20Sopenharmony_ci	__be16 sport;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (ip_tunnel_info_af(info) == AF_INET) {
11198c2ecf20Sopenharmony_ci		struct rtable *rt;
11208c2ecf20Sopenharmony_ci		struct flowi4 fl4;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
11238c2ecf20Sopenharmony_ci		sport = udp_flow_src_port(geneve->net, skb,
11248c2ecf20Sopenharmony_ci					  1, USHRT_MAX, true);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci		rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
11278c2ecf20Sopenharmony_ci				      geneve->cfg.info.key.tp_dst, sport, NULL);
11288c2ecf20Sopenharmony_ci		if (IS_ERR(rt))
11298c2ecf20Sopenharmony_ci			return PTR_ERR(rt);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci		ip_rt_put(rt);
11328c2ecf20Sopenharmony_ci		info->key.u.ipv4.src = fl4.saddr;
11338c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
11348c2ecf20Sopenharmony_ci	} else if (ip_tunnel_info_af(info) == AF_INET6) {
11358c2ecf20Sopenharmony_ci		struct dst_entry *dst;
11368c2ecf20Sopenharmony_ci		struct flowi6 fl6;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
11398c2ecf20Sopenharmony_ci		sport = udp_flow_src_port(geneve->net, skb,
11408c2ecf20Sopenharmony_ci					  1, USHRT_MAX, true);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
11438c2ecf20Sopenharmony_ci					geneve->cfg.info.key.tp_dst, sport);
11448c2ecf20Sopenharmony_ci		if (IS_ERR(dst))
11458c2ecf20Sopenharmony_ci			return PTR_ERR(dst);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci		dst_release(dst);
11488c2ecf20Sopenharmony_ci		info->key.u.ipv6.src = fl6.saddr;
11498c2ecf20Sopenharmony_ci#endif
11508c2ecf20Sopenharmony_ci	} else {
11518c2ecf20Sopenharmony_ci		return -EINVAL;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	info->key.tp_src = sport;
11558c2ecf20Sopenharmony_ci	info->key.tp_dst = geneve->cfg.info.key.tp_dst;
11568c2ecf20Sopenharmony_ci	return 0;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic const struct net_device_ops geneve_netdev_ops = {
11608c2ecf20Sopenharmony_ci	.ndo_init		= geneve_init,
11618c2ecf20Sopenharmony_ci	.ndo_uninit		= geneve_uninit,
11628c2ecf20Sopenharmony_ci	.ndo_open		= geneve_open,
11638c2ecf20Sopenharmony_ci	.ndo_stop		= geneve_stop,
11648c2ecf20Sopenharmony_ci	.ndo_start_xmit		= geneve_xmit,
11658c2ecf20Sopenharmony_ci	.ndo_get_stats64	= ip_tunnel_get_stats64,
11668c2ecf20Sopenharmony_ci	.ndo_change_mtu		= geneve_change_mtu,
11678c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
11688c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
11698c2ecf20Sopenharmony_ci	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst,
11708c2ecf20Sopenharmony_ci};
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic void geneve_get_drvinfo(struct net_device *dev,
11738c2ecf20Sopenharmony_ci			       struct ethtool_drvinfo *drvinfo)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
11768c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic const struct ethtool_ops geneve_ethtool_ops = {
11808c2ecf20Sopenharmony_ci	.get_drvinfo	= geneve_get_drvinfo,
11818c2ecf20Sopenharmony_ci	.get_link	= ethtool_op_get_link,
11828c2ecf20Sopenharmony_ci};
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci/* Info for udev, that this is a virtual tunnel endpoint */
11858c2ecf20Sopenharmony_cistatic struct device_type geneve_type = {
11868c2ecf20Sopenharmony_ci	.name = "geneve",
11878c2ecf20Sopenharmony_ci};
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci/* Calls the ndo_udp_tunnel_add of the caller in order to
11908c2ecf20Sopenharmony_ci * supply the listening GENEVE udp ports. Callers are expected
11918c2ecf20Sopenharmony_ci * to implement the ndo_udp_tunnel_add.
11928c2ecf20Sopenharmony_ci */
11938c2ecf20Sopenharmony_cistatic void geneve_offload_rx_ports(struct net_device *dev, bool push)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	struct net *net = dev_net(dev);
11968c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
11978c2ecf20Sopenharmony_ci	struct geneve_sock *gs;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	rcu_read_lock();
12008c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(gs, &gn->sock_list, list) {
12018c2ecf20Sopenharmony_ci		if (push) {
12028c2ecf20Sopenharmony_ci			udp_tunnel_push_rx_port(dev, gs->sock,
12038c2ecf20Sopenharmony_ci						UDP_TUNNEL_TYPE_GENEVE);
12048c2ecf20Sopenharmony_ci		} else {
12058c2ecf20Sopenharmony_ci			udp_tunnel_drop_rx_port(dev, gs->sock,
12068c2ecf20Sopenharmony_ci						UDP_TUNNEL_TYPE_GENEVE);
12078c2ecf20Sopenharmony_ci		}
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci	rcu_read_unlock();
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci/* Initialize the device structure. */
12138c2ecf20Sopenharmony_cistatic void geneve_setup(struct net_device *dev)
12148c2ecf20Sopenharmony_ci{
12158c2ecf20Sopenharmony_ci	ether_setup(dev);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	dev->netdev_ops = &geneve_netdev_ops;
12188c2ecf20Sopenharmony_ci	dev->ethtool_ops = &geneve_ethtool_ops;
12198c2ecf20Sopenharmony_ci	dev->needs_free_netdev = true;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	SET_NETDEV_DEVTYPE(dev, &geneve_type);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	dev->features    |= NETIF_F_LLTX;
12248c2ecf20Sopenharmony_ci	dev->features    |= NETIF_F_SG | NETIF_F_HW_CSUM;
12258c2ecf20Sopenharmony_ci	dev->features    |= NETIF_F_RXCSUM;
12268c2ecf20Sopenharmony_ci	dev->features    |= NETIF_F_GSO_SOFTWARE;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
12298c2ecf20Sopenharmony_ci	dev->hw_features |= NETIF_F_GSO_SOFTWARE;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	/* MTU range: 68 - (something less than 65535) */
12328c2ecf20Sopenharmony_ci	dev->min_mtu = ETH_MIN_MTU;
12338c2ecf20Sopenharmony_ci	/* The max_mtu calculation does not take account of GENEVE
12348c2ecf20Sopenharmony_ci	 * options, to avoid excluding potentially valid
12358c2ecf20Sopenharmony_ci	 * configurations. This will be further reduced by IPvX hdr size.
12368c2ecf20Sopenharmony_ci	 */
12378c2ecf20Sopenharmony_ci	dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	netif_keep_dst(dev);
12408c2ecf20Sopenharmony_ci	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
12418c2ecf20Sopenharmony_ci	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
12428c2ecf20Sopenharmony_ci	eth_hw_addr_random(dev);
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
12468c2ecf20Sopenharmony_ci	[IFLA_GENEVE_ID]		= { .type = NLA_U32 },
12478c2ecf20Sopenharmony_ci	[IFLA_GENEVE_REMOTE]		= { .len = sizeof_field(struct iphdr, daddr) },
12488c2ecf20Sopenharmony_ci	[IFLA_GENEVE_REMOTE6]		= { .len = sizeof(struct in6_addr) },
12498c2ecf20Sopenharmony_ci	[IFLA_GENEVE_TTL]		= { .type = NLA_U8 },
12508c2ecf20Sopenharmony_ci	[IFLA_GENEVE_TOS]		= { .type = NLA_U8 },
12518c2ecf20Sopenharmony_ci	[IFLA_GENEVE_LABEL]		= { .type = NLA_U32 },
12528c2ecf20Sopenharmony_ci	[IFLA_GENEVE_PORT]		= { .type = NLA_U16 },
12538c2ecf20Sopenharmony_ci	[IFLA_GENEVE_COLLECT_METADATA]	= { .type = NLA_FLAG },
12548c2ecf20Sopenharmony_ci	[IFLA_GENEVE_UDP_CSUM]		= { .type = NLA_U8 },
12558c2ecf20Sopenharmony_ci	[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]	= { .type = NLA_U8 },
12568c2ecf20Sopenharmony_ci	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
12578c2ecf20Sopenharmony_ci	[IFLA_GENEVE_TTL_INHERIT]	= { .type = NLA_U8 },
12588c2ecf20Sopenharmony_ci	[IFLA_GENEVE_DF]		= { .type = NLA_U8 },
12598c2ecf20Sopenharmony_ci};
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_cistatic int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
12628c2ecf20Sopenharmony_ci			   struct netlink_ext_ack *extack)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	if (tb[IFLA_ADDRESS]) {
12658c2ecf20Sopenharmony_ci		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
12668c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
12678c2ecf20Sopenharmony_ci					    "Provided link layer address is not Ethernet");
12688c2ecf20Sopenharmony_ci			return -EINVAL;
12698c2ecf20Sopenharmony_ci		}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
12728c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
12738c2ecf20Sopenharmony_ci					    "Provided Ethernet address is not unicast");
12748c2ecf20Sopenharmony_ci			return -EADDRNOTAVAIL;
12758c2ecf20Sopenharmony_ci		}
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (!data) {
12798c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
12808c2ecf20Sopenharmony_ci			       "Not enough attributes provided to perform the operation");
12818c2ecf20Sopenharmony_ci		return -EINVAL;
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_ID]) {
12858c2ecf20Sopenharmony_ci		__u32 vni =  nla_get_u32(data[IFLA_GENEVE_ID]);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		if (vni >= GENEVE_N_VID) {
12888c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID],
12898c2ecf20Sopenharmony_ci					    "Geneve ID must be lower than 16777216");
12908c2ecf20Sopenharmony_ci			return -ERANGE;
12918c2ecf20Sopenharmony_ci		}
12928c2ecf20Sopenharmony_ci	}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_DF]) {
12958c2ecf20Sopenharmony_ci		enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci		if (df < 0 || df > GENEVE_DF_MAX) {
12988c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_DF],
12998c2ecf20Sopenharmony_ci					    "Invalid DF attribute");
13008c2ecf20Sopenharmony_ci			return -EINVAL;
13018c2ecf20Sopenharmony_ci		}
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	return 0;
13058c2ecf20Sopenharmony_ci}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
13088c2ecf20Sopenharmony_ci					  const struct ip_tunnel_info *info,
13098c2ecf20Sopenharmony_ci					  bool *tun_on_same_port,
13108c2ecf20Sopenharmony_ci					  bool *tun_collect_md)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	struct geneve_dev *geneve, *t = NULL;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	*tun_on_same_port = false;
13158c2ecf20Sopenharmony_ci	*tun_collect_md = false;
13168c2ecf20Sopenharmony_ci	list_for_each_entry(geneve, &gn->geneve_list, next) {
13178c2ecf20Sopenharmony_ci		if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) {
13188c2ecf20Sopenharmony_ci			*tun_collect_md = geneve->cfg.collect_md;
13198c2ecf20Sopenharmony_ci			*tun_on_same_port = true;
13208c2ecf20Sopenharmony_ci		}
13218c2ecf20Sopenharmony_ci		if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
13228c2ecf20Sopenharmony_ci		    info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
13238c2ecf20Sopenharmony_ci		    !memcmp(&info->key.u, &geneve->cfg.info.key.u, sizeof(info->key.u)))
13248c2ecf20Sopenharmony_ci			t = geneve;
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci	return t;
13278c2ecf20Sopenharmony_ci}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_cistatic bool is_tnl_info_zero(const struct ip_tunnel_info *info)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	return !(info->key.tun_id || info->key.tun_flags || info->key.tos ||
13328c2ecf20Sopenharmony_ci		 info->key.ttl || info->key.label || info->key.tp_src ||
13338c2ecf20Sopenharmony_ci		 memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cistatic bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
13378c2ecf20Sopenharmony_ci				  struct ip_tunnel_info *b)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	if (ip_tunnel_info_af(a) == AF_INET)
13408c2ecf20Sopenharmony_ci		return a->key.u.ipv4.dst == b->key.u.ipv4.dst;
13418c2ecf20Sopenharmony_ci	else
13428c2ecf20Sopenharmony_ci		return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst);
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_cistatic int geneve_configure(struct net *net, struct net_device *dev,
13468c2ecf20Sopenharmony_ci			    struct netlink_ext_ack *extack,
13478c2ecf20Sopenharmony_ci			    const struct geneve_config *cfg)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
13508c2ecf20Sopenharmony_ci	struct geneve_dev *t, *geneve = netdev_priv(dev);
13518c2ecf20Sopenharmony_ci	const struct ip_tunnel_info *info = &cfg->info;
13528c2ecf20Sopenharmony_ci	bool tun_collect_md, tun_on_same_port;
13538c2ecf20Sopenharmony_ci	int err, encap_len;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (cfg->collect_md && !is_tnl_info_zero(info)) {
13568c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
13578c2ecf20Sopenharmony_ci			       "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified");
13588c2ecf20Sopenharmony_ci		return -EINVAL;
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	geneve->net = net;
13628c2ecf20Sopenharmony_ci	geneve->dev = dev;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
13658c2ecf20Sopenharmony_ci	if (t)
13668c2ecf20Sopenharmony_ci		return -EBUSY;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	/* make enough headroom for basic scenario */
13698c2ecf20Sopenharmony_ci	encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
13708c2ecf20Sopenharmony_ci	if (!cfg->collect_md && ip_tunnel_info_af(info) == AF_INET) {
13718c2ecf20Sopenharmony_ci		encap_len += sizeof(struct iphdr);
13728c2ecf20Sopenharmony_ci		dev->max_mtu -= sizeof(struct iphdr);
13738c2ecf20Sopenharmony_ci	} else {
13748c2ecf20Sopenharmony_ci		encap_len += sizeof(struct ipv6hdr);
13758c2ecf20Sopenharmony_ci		dev->max_mtu -= sizeof(struct ipv6hdr);
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci	dev->needed_headroom = encap_len + ETH_HLEN;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (cfg->collect_md) {
13808c2ecf20Sopenharmony_ci		if (tun_on_same_port) {
13818c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack,
13828c2ecf20Sopenharmony_ci				       "There can be only one externally controlled device on a destination port");
13838c2ecf20Sopenharmony_ci			return -EPERM;
13848c2ecf20Sopenharmony_ci		}
13858c2ecf20Sopenharmony_ci	} else {
13868c2ecf20Sopenharmony_ci		if (tun_collect_md) {
13878c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack,
13888c2ecf20Sopenharmony_ci				       "There already exists an externally controlled device on this destination port");
13898c2ecf20Sopenharmony_ci			return -EPERM;
13908c2ecf20Sopenharmony_ci		}
13918c2ecf20Sopenharmony_ci	}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	dst_cache_reset(&geneve->cfg.info.dst_cache);
13948c2ecf20Sopenharmony_ci	memcpy(&geneve->cfg, cfg, sizeof(*cfg));
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	err = register_netdevice(dev);
13978c2ecf20Sopenharmony_ci	if (err)
13988c2ecf20Sopenharmony_ci		return err;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	list_add(&geneve->next, &gn->geneve_list);
14018c2ecf20Sopenharmony_ci	return 0;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
14058c2ecf20Sopenharmony_ci{
14068c2ecf20Sopenharmony_ci	memset(info, 0, sizeof(*info));
14078c2ecf20Sopenharmony_ci	info->key.tp_dst = htons(dst_port);
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistatic int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
14118c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack,
14128c2ecf20Sopenharmony_ci			  struct geneve_config *cfg, bool changelink)
14138c2ecf20Sopenharmony_ci{
14148c2ecf20Sopenharmony_ci	struct ip_tunnel_info *info = &cfg->info;
14158c2ecf20Sopenharmony_ci	int attrtype;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
14188c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
14198c2ecf20Sopenharmony_ci			       "Cannot specify both IPv4 and IPv6 Remote addresses");
14208c2ecf20Sopenharmony_ci		return -EINVAL;
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_REMOTE]) {
14248c2ecf20Sopenharmony_ci		if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
14258c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_REMOTE;
14268c2ecf20Sopenharmony_ci			goto change_notsup;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		info->key.u.ipv4.dst =
14308c2ecf20Sopenharmony_ci			nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci		if (ipv4_is_multicast(info->key.u.ipv4.dst)) {
14338c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE],
14348c2ecf20Sopenharmony_ci					    "Remote IPv4 address cannot be Multicast");
14358c2ecf20Sopenharmony_ci			return -EINVAL;
14368c2ecf20Sopenharmony_ci		}
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_REMOTE6]) {
14408c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
14418c2ecf20Sopenharmony_ci		if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
14428c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_REMOTE6;
14438c2ecf20Sopenharmony_ci			goto change_notsup;
14448c2ecf20Sopenharmony_ci		}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci		info->mode = IP_TUNNEL_INFO_IPV6;
14478c2ecf20Sopenharmony_ci		info->key.u.ipv6.dst =
14488c2ecf20Sopenharmony_ci			nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci		if (ipv6_addr_type(&info->key.u.ipv6.dst) &
14518c2ecf20Sopenharmony_ci		    IPV6_ADDR_LINKLOCAL) {
14528c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
14538c2ecf20Sopenharmony_ci					    "Remote IPv6 address cannot be link-local");
14548c2ecf20Sopenharmony_ci			return -EINVAL;
14558c2ecf20Sopenharmony_ci		}
14568c2ecf20Sopenharmony_ci		if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
14578c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
14588c2ecf20Sopenharmony_ci					    "Remote IPv6 address cannot be Multicast");
14598c2ecf20Sopenharmony_ci			return -EINVAL;
14608c2ecf20Sopenharmony_ci		}
14618c2ecf20Sopenharmony_ci		info->key.tun_flags |= TUNNEL_CSUM;
14628c2ecf20Sopenharmony_ci		cfg->use_udp6_rx_checksums = true;
14638c2ecf20Sopenharmony_ci#else
14648c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
14658c2ecf20Sopenharmony_ci				    "IPv6 support not enabled in the kernel");
14668c2ecf20Sopenharmony_ci		return -EPFNOSUPPORT;
14678c2ecf20Sopenharmony_ci#endif
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_ID]) {
14718c2ecf20Sopenharmony_ci		__u32 vni;
14728c2ecf20Sopenharmony_ci		__u8 tvni[3];
14738c2ecf20Sopenharmony_ci		__be64 tunid;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci		vni = nla_get_u32(data[IFLA_GENEVE_ID]);
14768c2ecf20Sopenharmony_ci		tvni[0] = (vni & 0x00ff0000) >> 16;
14778c2ecf20Sopenharmony_ci		tvni[1] = (vni & 0x0000ff00) >> 8;
14788c2ecf20Sopenharmony_ci		tvni[2] =  vni & 0x000000ff;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		tunid = vni_to_tunnel_id(tvni);
14818c2ecf20Sopenharmony_ci		if (changelink && (tunid != info->key.tun_id)) {
14828c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_ID;
14838c2ecf20Sopenharmony_ci			goto change_notsup;
14848c2ecf20Sopenharmony_ci		}
14858c2ecf20Sopenharmony_ci		info->key.tun_id = tunid;
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_TTL_INHERIT]) {
14898c2ecf20Sopenharmony_ci		if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT]))
14908c2ecf20Sopenharmony_ci			cfg->ttl_inherit = true;
14918c2ecf20Sopenharmony_ci		else
14928c2ecf20Sopenharmony_ci			cfg->ttl_inherit = false;
14938c2ecf20Sopenharmony_ci	} else if (data[IFLA_GENEVE_TTL]) {
14948c2ecf20Sopenharmony_ci		info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
14958c2ecf20Sopenharmony_ci		cfg->ttl_inherit = false;
14968c2ecf20Sopenharmony_ci	}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_TOS])
14998c2ecf20Sopenharmony_ci		info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_DF])
15028c2ecf20Sopenharmony_ci		cfg->df = nla_get_u8(data[IFLA_GENEVE_DF]);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_LABEL]) {
15058c2ecf20Sopenharmony_ci		info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
15068c2ecf20Sopenharmony_ci				  IPV6_FLOWLABEL_MASK;
15078c2ecf20Sopenharmony_ci		if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) {
15088c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL],
15098c2ecf20Sopenharmony_ci					    "Label attribute only applies for IPv6 Geneve devices");
15108c2ecf20Sopenharmony_ci			return -EINVAL;
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_PORT]) {
15158c2ecf20Sopenharmony_ci		if (changelink) {
15168c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_PORT;
15178c2ecf20Sopenharmony_ci			goto change_notsup;
15188c2ecf20Sopenharmony_ci		}
15198c2ecf20Sopenharmony_ci		info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_COLLECT_METADATA]) {
15238c2ecf20Sopenharmony_ci		if (changelink) {
15248c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_COLLECT_METADATA;
15258c2ecf20Sopenharmony_ci			goto change_notsup;
15268c2ecf20Sopenharmony_ci		}
15278c2ecf20Sopenharmony_ci		cfg->collect_md = true;
15288c2ecf20Sopenharmony_ci	}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_UDP_CSUM]) {
15318c2ecf20Sopenharmony_ci		if (changelink) {
15328c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_UDP_CSUM;
15338c2ecf20Sopenharmony_ci			goto change_notsup;
15348c2ecf20Sopenharmony_ci		}
15358c2ecf20Sopenharmony_ci		if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
15368c2ecf20Sopenharmony_ci			info->key.tun_flags |= TUNNEL_CSUM;
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
15408c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
15418c2ecf20Sopenharmony_ci		if (changelink) {
15428c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX;
15438c2ecf20Sopenharmony_ci			goto change_notsup;
15448c2ecf20Sopenharmony_ci		}
15458c2ecf20Sopenharmony_ci		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
15468c2ecf20Sopenharmony_ci			info->key.tun_flags &= ~TUNNEL_CSUM;
15478c2ecf20Sopenharmony_ci#else
15488c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX],
15498c2ecf20Sopenharmony_ci				    "IPv6 support not enabled in the kernel");
15508c2ecf20Sopenharmony_ci		return -EPFNOSUPPORT;
15518c2ecf20Sopenharmony_ci#endif
15528c2ecf20Sopenharmony_ci	}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
15558c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
15568c2ecf20Sopenharmony_ci		if (changelink) {
15578c2ecf20Sopenharmony_ci			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX;
15588c2ecf20Sopenharmony_ci			goto change_notsup;
15598c2ecf20Sopenharmony_ci		}
15608c2ecf20Sopenharmony_ci		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
15618c2ecf20Sopenharmony_ci			cfg->use_udp6_rx_checksums = false;
15628c2ecf20Sopenharmony_ci#else
15638c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX],
15648c2ecf20Sopenharmony_ci				    "IPv6 support not enabled in the kernel");
15658c2ecf20Sopenharmony_ci		return -EPFNOSUPPORT;
15668c2ecf20Sopenharmony_ci#endif
15678c2ecf20Sopenharmony_ci	}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	return 0;
15708c2ecf20Sopenharmony_cichange_notsup:
15718c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_ATTR(extack, data[attrtype],
15728c2ecf20Sopenharmony_ci			    "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported");
15738c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_cistatic void geneve_link_config(struct net_device *dev,
15778c2ecf20Sopenharmony_ci			       struct ip_tunnel_info *info, struct nlattr *tb[])
15788c2ecf20Sopenharmony_ci{
15798c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
15808c2ecf20Sopenharmony_ci	int ldev_mtu = 0;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	if (tb[IFLA_MTU]) {
15838c2ecf20Sopenharmony_ci		geneve_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
15848c2ecf20Sopenharmony_ci		return;
15858c2ecf20Sopenharmony_ci	}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	switch (ip_tunnel_info_af(info)) {
15888c2ecf20Sopenharmony_ci	case AF_INET: {
15898c2ecf20Sopenharmony_ci		struct flowi4 fl4 = { .daddr = info->key.u.ipv4.dst };
15908c2ecf20Sopenharmony_ci		struct rtable *rt = ip_route_output_key(geneve->net, &fl4);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci		if (!IS_ERR(rt) && rt->dst.dev) {
15938c2ecf20Sopenharmony_ci			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV4_HLEN;
15948c2ecf20Sopenharmony_ci			ip_rt_put(rt);
15958c2ecf20Sopenharmony_ci		}
15968c2ecf20Sopenharmony_ci		break;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
15998c2ecf20Sopenharmony_ci	case AF_INET6: {
16008c2ecf20Sopenharmony_ci		struct rt6_info *rt;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci		if (!__in6_dev_get(dev))
16038c2ecf20Sopenharmony_ci			break;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci		rt = rt6_lookup(geneve->net, &info->key.u.ipv6.dst, NULL, 0,
16068c2ecf20Sopenharmony_ci				NULL, 0);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci		if (rt && rt->dst.dev)
16098c2ecf20Sopenharmony_ci			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV6_HLEN;
16108c2ecf20Sopenharmony_ci		ip6_rt_put(rt);
16118c2ecf20Sopenharmony_ci		break;
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci#endif
16148c2ecf20Sopenharmony_ci	}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	if (ldev_mtu <= 0)
16178c2ecf20Sopenharmony_ci		return;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	geneve_change_mtu(dev, ldev_mtu - info->options_len);
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cistatic int geneve_newlink(struct net *net, struct net_device *dev,
16238c2ecf20Sopenharmony_ci			  struct nlattr *tb[], struct nlattr *data[],
16248c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack)
16258c2ecf20Sopenharmony_ci{
16268c2ecf20Sopenharmony_ci	struct geneve_config cfg = {
16278c2ecf20Sopenharmony_ci		.df = GENEVE_DF_UNSET,
16288c2ecf20Sopenharmony_ci		.use_udp6_rx_checksums = false,
16298c2ecf20Sopenharmony_ci		.ttl_inherit = false,
16308c2ecf20Sopenharmony_ci		.collect_md = false,
16318c2ecf20Sopenharmony_ci	};
16328c2ecf20Sopenharmony_ci	int err;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	init_tnl_info(&cfg.info, GENEVE_UDP_PORT);
16358c2ecf20Sopenharmony_ci	err = geneve_nl2info(tb, data, extack, &cfg, false);
16368c2ecf20Sopenharmony_ci	if (err)
16378c2ecf20Sopenharmony_ci		return err;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	err = geneve_configure(net, dev, extack, &cfg);
16408c2ecf20Sopenharmony_ci	if (err)
16418c2ecf20Sopenharmony_ci		return err;
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	geneve_link_config(dev, &cfg.info, tb);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	return 0;
16468c2ecf20Sopenharmony_ci}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci/* Quiesces the geneve device data path for both TX and RX.
16498c2ecf20Sopenharmony_ci *
16508c2ecf20Sopenharmony_ci * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
16518c2ecf20Sopenharmony_ci * So, if we set that socket to NULL under RCU and wait for synchronize_net()
16528c2ecf20Sopenharmony_ci * to complete for the existing set of in-flight packets to be transmitted,
16538c2ecf20Sopenharmony_ci * then we would have quiesced the transmit data path. All the future packets
16548c2ecf20Sopenharmony_ci * will get dropped until we unquiesce the data path.
16558c2ecf20Sopenharmony_ci *
16568c2ecf20Sopenharmony_ci * On receive geneve dereference the geneve_sock stashed in the socket. So,
16578c2ecf20Sopenharmony_ci * if we set that to NULL under RCU and wait for synchronize_net() to
16588c2ecf20Sopenharmony_ci * complete, then we would have quiesced the receive data path.
16598c2ecf20Sopenharmony_ci */
16608c2ecf20Sopenharmony_cistatic void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
16618c2ecf20Sopenharmony_ci			   struct geneve_sock **gs6)
16628c2ecf20Sopenharmony_ci{
16638c2ecf20Sopenharmony_ci	*gs4 = rtnl_dereference(geneve->sock4);
16648c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock4, NULL);
16658c2ecf20Sopenharmony_ci	if (*gs4)
16668c2ecf20Sopenharmony_ci		rcu_assign_sk_user_data((*gs4)->sock->sk, NULL);
16678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
16688c2ecf20Sopenharmony_ci	*gs6 = rtnl_dereference(geneve->sock6);
16698c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock6, NULL);
16708c2ecf20Sopenharmony_ci	if (*gs6)
16718c2ecf20Sopenharmony_ci		rcu_assign_sk_user_data((*gs6)->sock->sk, NULL);
16728c2ecf20Sopenharmony_ci#else
16738c2ecf20Sopenharmony_ci	*gs6 = NULL;
16748c2ecf20Sopenharmony_ci#endif
16758c2ecf20Sopenharmony_ci	synchronize_net();
16768c2ecf20Sopenharmony_ci}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci/* Resumes the geneve device data path for both TX and RX. */
16798c2ecf20Sopenharmony_cistatic void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
16808c2ecf20Sopenharmony_ci			     struct geneve_sock __maybe_unused *gs6)
16818c2ecf20Sopenharmony_ci{
16828c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock4, gs4);
16838c2ecf20Sopenharmony_ci	if (gs4)
16848c2ecf20Sopenharmony_ci		rcu_assign_sk_user_data(gs4->sock->sk, gs4);
16858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
16868c2ecf20Sopenharmony_ci	rcu_assign_pointer(geneve->sock6, gs6);
16878c2ecf20Sopenharmony_ci	if (gs6)
16888c2ecf20Sopenharmony_ci		rcu_assign_sk_user_data(gs6->sock->sk, gs6);
16898c2ecf20Sopenharmony_ci#endif
16908c2ecf20Sopenharmony_ci	synchronize_net();
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistatic int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
16948c2ecf20Sopenharmony_ci			     struct nlattr *data[],
16958c2ecf20Sopenharmony_ci			     struct netlink_ext_ack *extack)
16968c2ecf20Sopenharmony_ci{
16978c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
16988c2ecf20Sopenharmony_ci	struct geneve_sock *gs4, *gs6;
16998c2ecf20Sopenharmony_ci	struct geneve_config cfg;
17008c2ecf20Sopenharmony_ci	int err;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	/* If the geneve device is configured for metadata (or externally
17038c2ecf20Sopenharmony_ci	 * controlled, for example, OVS), then nothing can be changed.
17048c2ecf20Sopenharmony_ci	 */
17058c2ecf20Sopenharmony_ci	if (geneve->cfg.collect_md)
17068c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/* Start with the existing info. */
17098c2ecf20Sopenharmony_ci	memcpy(&cfg, &geneve->cfg, sizeof(cfg));
17108c2ecf20Sopenharmony_ci	err = geneve_nl2info(tb, data, extack, &cfg, true);
17118c2ecf20Sopenharmony_ci	if (err)
17128c2ecf20Sopenharmony_ci		return err;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	if (!geneve_dst_addr_equal(&geneve->cfg.info, &cfg.info)) {
17158c2ecf20Sopenharmony_ci		dst_cache_reset(&cfg.info.dst_cache);
17168c2ecf20Sopenharmony_ci		geneve_link_config(dev, &cfg.info, tb);
17178c2ecf20Sopenharmony_ci	}
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	geneve_quiesce(geneve, &gs4, &gs6);
17208c2ecf20Sopenharmony_ci	memcpy(&geneve->cfg, &cfg, sizeof(cfg));
17218c2ecf20Sopenharmony_ci	geneve_unquiesce(geneve, gs4, gs6);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	return 0;
17248c2ecf20Sopenharmony_ci}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_cistatic void geneve_dellink(struct net_device *dev, struct list_head *head)
17278c2ecf20Sopenharmony_ci{
17288c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	list_del(&geneve->next);
17318c2ecf20Sopenharmony_ci	unregister_netdevice_queue(dev, head);
17328c2ecf20Sopenharmony_ci}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_cistatic size_t geneve_get_size(const struct net_device *dev)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	return nla_total_size(sizeof(__u32)) +	/* IFLA_GENEVE_ID */
17378c2ecf20Sopenharmony_ci		nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
17388c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */
17398c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
17408c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) +	/* IFLA_GENEVE_DF */
17418c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__be32)) +  /* IFLA_GENEVE_LABEL */
17428c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
17438c2ecf20Sopenharmony_ci		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */
17448c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
17458c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
17468c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
17478c2ecf20Sopenharmony_ci		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */
17488c2ecf20Sopenharmony_ci		0;
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
17528c2ecf20Sopenharmony_ci{
17538c2ecf20Sopenharmony_ci	struct geneve_dev *geneve = netdev_priv(dev);
17548c2ecf20Sopenharmony_ci	struct ip_tunnel_info *info = &geneve->cfg.info;
17558c2ecf20Sopenharmony_ci	bool ttl_inherit = geneve->cfg.ttl_inherit;
17568c2ecf20Sopenharmony_ci	bool metadata = geneve->cfg.collect_md;
17578c2ecf20Sopenharmony_ci	__u8 tmp_vni[3];
17588c2ecf20Sopenharmony_ci	__u32 vni;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	tunnel_id_to_vni(info->key.tun_id, tmp_vni);
17618c2ecf20Sopenharmony_ci	vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2];
17628c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
17638c2ecf20Sopenharmony_ci		goto nla_put_failure;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	if (!metadata && ip_tunnel_info_af(info) == AF_INET) {
17668c2ecf20Sopenharmony_ci		if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
17678c2ecf20Sopenharmony_ci				    info->key.u.ipv4.dst))
17688c2ecf20Sopenharmony_ci			goto nla_put_failure;
17698c2ecf20Sopenharmony_ci		if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
17708c2ecf20Sopenharmony_ci			       !!(info->key.tun_flags & TUNNEL_CSUM)))
17718c2ecf20Sopenharmony_ci			goto nla_put_failure;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
17748c2ecf20Sopenharmony_ci	} else if (!metadata) {
17758c2ecf20Sopenharmony_ci		if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
17768c2ecf20Sopenharmony_ci				     &info->key.u.ipv6.dst))
17778c2ecf20Sopenharmony_ci			goto nla_put_failure;
17788c2ecf20Sopenharmony_ci		if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
17798c2ecf20Sopenharmony_ci			       !(info->key.tun_flags & TUNNEL_CSUM)))
17808c2ecf20Sopenharmony_ci			goto nla_put_failure;
17818c2ecf20Sopenharmony_ci#endif
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
17858c2ecf20Sopenharmony_ci	    nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
17868c2ecf20Sopenharmony_ci	    nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
17878c2ecf20Sopenharmony_ci		goto nla_put_failure;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->cfg.df))
17908c2ecf20Sopenharmony_ci		goto nla_put_failure;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
17938c2ecf20Sopenharmony_ci		goto nla_put_failure;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA))
17968c2ecf20Sopenharmony_ci		goto nla_put_failure;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
17998c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
18008c2ecf20Sopenharmony_ci		       !geneve->cfg.use_udp6_rx_checksums))
18018c2ecf20Sopenharmony_ci		goto nla_put_failure;
18028c2ecf20Sopenharmony_ci#endif
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
18058c2ecf20Sopenharmony_ci		goto nla_put_failure;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	return 0;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cinla_put_failure:
18108c2ecf20Sopenharmony_ci	return -EMSGSIZE;
18118c2ecf20Sopenharmony_ci}
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_cistatic struct rtnl_link_ops geneve_link_ops __read_mostly = {
18148c2ecf20Sopenharmony_ci	.kind		= "geneve",
18158c2ecf20Sopenharmony_ci	.maxtype	= IFLA_GENEVE_MAX,
18168c2ecf20Sopenharmony_ci	.policy		= geneve_policy,
18178c2ecf20Sopenharmony_ci	.priv_size	= sizeof(struct geneve_dev),
18188c2ecf20Sopenharmony_ci	.setup		= geneve_setup,
18198c2ecf20Sopenharmony_ci	.validate	= geneve_validate,
18208c2ecf20Sopenharmony_ci	.newlink	= geneve_newlink,
18218c2ecf20Sopenharmony_ci	.changelink	= geneve_changelink,
18228c2ecf20Sopenharmony_ci	.dellink	= geneve_dellink,
18238c2ecf20Sopenharmony_ci	.get_size	= geneve_get_size,
18248c2ecf20Sopenharmony_ci	.fill_info	= geneve_fill_info,
18258c2ecf20Sopenharmony_ci};
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_cistruct net_device *geneve_dev_create_fb(struct net *net, const char *name,
18288c2ecf20Sopenharmony_ci					u8 name_assign_type, u16 dst_port)
18298c2ecf20Sopenharmony_ci{
18308c2ecf20Sopenharmony_ci	struct nlattr *tb[IFLA_MAX + 1];
18318c2ecf20Sopenharmony_ci	struct net_device *dev;
18328c2ecf20Sopenharmony_ci	LIST_HEAD(list_kill);
18338c2ecf20Sopenharmony_ci	int err;
18348c2ecf20Sopenharmony_ci	struct geneve_config cfg = {
18358c2ecf20Sopenharmony_ci		.df = GENEVE_DF_UNSET,
18368c2ecf20Sopenharmony_ci		.use_udp6_rx_checksums = true,
18378c2ecf20Sopenharmony_ci		.ttl_inherit = false,
18388c2ecf20Sopenharmony_ci		.collect_md = true,
18398c2ecf20Sopenharmony_ci	};
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	memset(tb, 0, sizeof(tb));
18428c2ecf20Sopenharmony_ci	dev = rtnl_create_link(net, name, name_assign_type,
18438c2ecf20Sopenharmony_ci			       &geneve_link_ops, tb, NULL);
18448c2ecf20Sopenharmony_ci	if (IS_ERR(dev))
18458c2ecf20Sopenharmony_ci		return dev;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	init_tnl_info(&cfg.info, dst_port);
18488c2ecf20Sopenharmony_ci	err = geneve_configure(net, dev, NULL, &cfg);
18498c2ecf20Sopenharmony_ci	if (err) {
18508c2ecf20Sopenharmony_ci		free_netdev(dev);
18518c2ecf20Sopenharmony_ci		return ERR_PTR(err);
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* openvswitch users expect packet sizes to be unrestricted,
18558c2ecf20Sopenharmony_ci	 * so set the largest MTU we can.
18568c2ecf20Sopenharmony_ci	 */
18578c2ecf20Sopenharmony_ci	err = geneve_change_mtu(dev, IP_MAX_MTU);
18588c2ecf20Sopenharmony_ci	if (err)
18598c2ecf20Sopenharmony_ci		goto err;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	err = rtnl_configure_link(dev, NULL);
18628c2ecf20Sopenharmony_ci	if (err < 0)
18638c2ecf20Sopenharmony_ci		goto err;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	return dev;
18668c2ecf20Sopenharmony_cierr:
18678c2ecf20Sopenharmony_ci	geneve_dellink(dev, &list_kill);
18688c2ecf20Sopenharmony_ci	unregister_netdevice_many(&list_kill);
18698c2ecf20Sopenharmony_ci	return ERR_PTR(err);
18708c2ecf20Sopenharmony_ci}
18718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(geneve_dev_create_fb);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_cistatic int geneve_netdevice_event(struct notifier_block *unused,
18748c2ecf20Sopenharmony_ci				  unsigned long event, void *ptr)
18758c2ecf20Sopenharmony_ci{
18768c2ecf20Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
18798c2ecf20Sopenharmony_ci	    event == NETDEV_UDP_TUNNEL_DROP_INFO) {
18808c2ecf20Sopenharmony_ci		geneve_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
18818c2ecf20Sopenharmony_ci	} else if (event == NETDEV_UNREGISTER) {
18828c2ecf20Sopenharmony_ci		if (!dev->udp_tunnel_nic_info)
18838c2ecf20Sopenharmony_ci			geneve_offload_rx_ports(dev, false);
18848c2ecf20Sopenharmony_ci	} else if (event == NETDEV_REGISTER) {
18858c2ecf20Sopenharmony_ci		if (!dev->udp_tunnel_nic_info)
18868c2ecf20Sopenharmony_ci			geneve_offload_rx_ports(dev, true);
18878c2ecf20Sopenharmony_ci	}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	return NOTIFY_DONE;
18908c2ecf20Sopenharmony_ci}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_cistatic struct notifier_block geneve_notifier_block __read_mostly = {
18938c2ecf20Sopenharmony_ci	.notifier_call = geneve_netdevice_event,
18948c2ecf20Sopenharmony_ci};
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_cistatic __net_init int geneve_init_net(struct net *net)
18978c2ecf20Sopenharmony_ci{
18988c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gn->geneve_list);
19018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gn->sock_list);
19028c2ecf20Sopenharmony_ci	return 0;
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_cistatic void geneve_destroy_tunnels(struct net *net, struct list_head *head)
19068c2ecf20Sopenharmony_ci{
19078c2ecf20Sopenharmony_ci	struct geneve_net *gn = net_generic(net, geneve_net_id);
19088c2ecf20Sopenharmony_ci	struct geneve_dev *geneve, *next;
19098c2ecf20Sopenharmony_ci	struct net_device *dev, *aux;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	/* gather any geneve devices that were moved into this ns */
19128c2ecf20Sopenharmony_ci	for_each_netdev_safe(net, dev, aux)
19138c2ecf20Sopenharmony_ci		if (dev->rtnl_link_ops == &geneve_link_ops)
19148c2ecf20Sopenharmony_ci			unregister_netdevice_queue(dev, head);
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	/* now gather any other geneve devices that were created in this ns */
19178c2ecf20Sopenharmony_ci	list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) {
19188c2ecf20Sopenharmony_ci		/* If geneve->dev is in the same netns, it was already added
19198c2ecf20Sopenharmony_ci		 * to the list by the previous loop.
19208c2ecf20Sopenharmony_ci		 */
19218c2ecf20Sopenharmony_ci		if (!net_eq(dev_net(geneve->dev), net))
19228c2ecf20Sopenharmony_ci			unregister_netdevice_queue(geneve->dev, head);
19238c2ecf20Sopenharmony_ci	}
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic void __net_exit geneve_exit_batch_net(struct list_head *net_list)
19278c2ecf20Sopenharmony_ci{
19288c2ecf20Sopenharmony_ci	struct net *net;
19298c2ecf20Sopenharmony_ci	LIST_HEAD(list);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	rtnl_lock();
19328c2ecf20Sopenharmony_ci	list_for_each_entry(net, net_list, exit_list)
19338c2ecf20Sopenharmony_ci		geneve_destroy_tunnels(net, &list);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	/* unregister the devices gathered above */
19368c2ecf20Sopenharmony_ci	unregister_netdevice_many(&list);
19378c2ecf20Sopenharmony_ci	rtnl_unlock();
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	list_for_each_entry(net, net_list, exit_list) {
19408c2ecf20Sopenharmony_ci		const struct geneve_net *gn = net_generic(net, geneve_net_id);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!list_empty(&gn->sock_list));
19438c2ecf20Sopenharmony_ci	}
19448c2ecf20Sopenharmony_ci}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_cistatic struct pernet_operations geneve_net_ops = {
19478c2ecf20Sopenharmony_ci	.init = geneve_init_net,
19488c2ecf20Sopenharmony_ci	.exit_batch = geneve_exit_batch_net,
19498c2ecf20Sopenharmony_ci	.id   = &geneve_net_id,
19508c2ecf20Sopenharmony_ci	.size = sizeof(struct geneve_net),
19518c2ecf20Sopenharmony_ci};
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_cistatic int __init geneve_init_module(void)
19548c2ecf20Sopenharmony_ci{
19558c2ecf20Sopenharmony_ci	int rc;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	rc = register_pernet_subsys(&geneve_net_ops);
19588c2ecf20Sopenharmony_ci	if (rc)
19598c2ecf20Sopenharmony_ci		goto out1;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	rc = register_netdevice_notifier(&geneve_notifier_block);
19628c2ecf20Sopenharmony_ci	if (rc)
19638c2ecf20Sopenharmony_ci		goto out2;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	rc = rtnl_link_register(&geneve_link_ops);
19668c2ecf20Sopenharmony_ci	if (rc)
19678c2ecf20Sopenharmony_ci		goto out3;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	return 0;
19708c2ecf20Sopenharmony_ciout3:
19718c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&geneve_notifier_block);
19728c2ecf20Sopenharmony_ciout2:
19738c2ecf20Sopenharmony_ci	unregister_pernet_subsys(&geneve_net_ops);
19748c2ecf20Sopenharmony_ciout1:
19758c2ecf20Sopenharmony_ci	return rc;
19768c2ecf20Sopenharmony_ci}
19778c2ecf20Sopenharmony_cilate_initcall(geneve_init_module);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_cistatic void __exit geneve_cleanup_module(void)
19808c2ecf20Sopenharmony_ci{
19818c2ecf20Sopenharmony_ci	rtnl_link_unregister(&geneve_link_ops);
19828c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&geneve_notifier_block);
19838c2ecf20Sopenharmony_ci	unregister_pernet_subsys(&geneve_net_ops);
19848c2ecf20Sopenharmony_ci}
19858c2ecf20Sopenharmony_cimodule_exit(geneve_cleanup_module);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
19888c2ecf20Sopenharmony_ciMODULE_VERSION(GENEVE_NETDEV_VER);
19898c2ecf20Sopenharmony_ciMODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
19908c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic");
19918c2ecf20Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("geneve");
1992