xref: /openbmc/linux/drivers/net/geneve.c (revision d37cf9b63113f13d742713881ce691fc615d8b3b)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22d07dc79SJohn W. Linville /*
32d07dc79SJohn W. Linville  * GENEVE: Generic Network Virtualization Encapsulation
42d07dc79SJohn W. Linville  *
52d07dc79SJohn W. Linville  * Copyright (c) 2015 Red Hat, Inc.
62d07dc79SJohn W. Linville  */
72d07dc79SJohn W. Linville 
82d07dc79SJohn W. Linville #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
92d07dc79SJohn W. Linville 
10cc69837fSJakub Kicinski #include <linux/ethtool.h>
112d07dc79SJohn W. Linville #include <linux/kernel.h>
122d07dc79SJohn W. Linville #include <linux/module.h>
132d07dc79SJohn W. Linville #include <linux/etherdevice.h>
142d07dc79SJohn W. Linville #include <linux/hash.h>
153616d08bSDavid Ahern #include <net/ipv6_stubs.h>
16e305ac6cSPravin B Shelar #include <net/dst_metadata.h>
178e816df8SJesse Gross #include <net/gro_cells.h>
182d07dc79SJohn W. Linville #include <net/rtnetlink.h>
192d07dc79SJohn W. Linville #include <net/geneve.h>
204721031cSEric Dumazet #include <net/gro.h>
21371bd106SPravin B Shelar #include <net/protocol.h>
222d07dc79SJohn W. Linville 
232d07dc79SJohn W. Linville #define GENEVE_NETDEV_VER	"0.6"
242d07dc79SJohn W. Linville 
252d07dc79SJohn W. Linville #define GENEVE_N_VID		(1u << 24)
262d07dc79SJohn W. Linville #define GENEVE_VID_MASK		(GENEVE_N_VID - 1)
272d07dc79SJohn W. Linville 
282d07dc79SJohn W. Linville #define VNI_HASH_BITS		10
292d07dc79SJohn W. Linville #define VNI_HASH_SIZE		(1<<VNI_HASH_BITS)
302d07dc79SJohn W. Linville 
312d07dc79SJohn W. Linville static bool log_ecn_error = true;
322d07dc79SJohn W. Linville module_param(log_ecn_error, bool, 0644);
332d07dc79SJohn W. Linville MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
342d07dc79SJohn W. Linville 
35371bd106SPravin B Shelar #define GENEVE_VER 0
36371bd106SPravin B Shelar #define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr))
375edbea69SAlexey Kodanev #define GENEVE_IPV4_HLEN (ETH_HLEN + sizeof(struct iphdr) + GENEVE_BASE_HLEN)
385edbea69SAlexey Kodanev #define GENEVE_IPV6_HLEN (ETH_HLEN + sizeof(struct ipv6hdr) + GENEVE_BASE_HLEN)
39371bd106SPravin B Shelar 
402d07dc79SJohn W. Linville /* per-network namespace private data for this module */
412d07dc79SJohn W. Linville struct geneve_net {
422d07dc79SJohn W. Linville 	struct list_head	geneve_list;
43371bd106SPravin B Shelar 	struct list_head	sock_list;
442d07dc79SJohn W. Linville };
452d07dc79SJohn W. Linville 
46c7d03a00SAlexey Dobriyan static unsigned int geneve_net_id;
47371bd106SPravin B Shelar 
484b4c21faSJiri Benc struct geneve_dev_node {
494b4c21faSJiri Benc 	struct hlist_node hlist;
504b4c21faSJiri Benc 	struct geneve_dev *geneve;
514b4c21faSJiri Benc };
524b4c21faSJiri Benc 
539e06e859SSabrina Dubroca struct geneve_config {
549e06e859SSabrina Dubroca 	struct ip_tunnel_info	info;
559e06e859SSabrina Dubroca 	bool			collect_md;
569e06e859SSabrina Dubroca 	bool			use_udp6_rx_checksums;
579e06e859SSabrina Dubroca 	bool			ttl_inherit;
589e06e859SSabrina Dubroca 	enum ifla_geneve_df	df;
59435fe1c0SEyal Birger 	bool			inner_proto_inherit;
609e06e859SSabrina Dubroca };
619e06e859SSabrina Dubroca 
622d07dc79SJohn W. Linville /* Pseudo network device */
632d07dc79SJohn W. Linville struct geneve_dev {
644b4c21faSJiri Benc 	struct geneve_dev_node hlist4;	/* vni hash table for IPv4 socket */
654b4c21faSJiri Benc #if IS_ENABLED(CONFIG_IPV6)
664b4c21faSJiri Benc 	struct geneve_dev_node hlist6;	/* vni hash table for IPv6 socket */
674b4c21faSJiri Benc #endif
682d07dc79SJohn W. Linville 	struct net	   *net;	/* netns for packet i/o */
692d07dc79SJohn W. Linville 	struct net_device  *dev;	/* netdev for geneve tunnel */
70fceb9c3eSpravin shelar 	struct geneve_sock __rcu *sock4;	/* IPv4 socket used for geneve tunnel */
718ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
72fceb9c3eSpravin shelar 	struct geneve_sock __rcu *sock6;	/* IPv6 socket used for geneve tunnel */
738ed66f0eSJohn W. Linville #endif
742d07dc79SJohn W. Linville 	struct list_head   next;	/* geneve's per namespace list */
758e816df8SJesse Gross 	struct gro_cells   gro_cells;
769e06e859SSabrina Dubroca 	struct geneve_config cfg;
772d07dc79SJohn W. Linville };
782d07dc79SJohn W. Linville 
79371bd106SPravin B Shelar struct geneve_sock {
80371bd106SPravin B Shelar 	bool			collect_md;
81371bd106SPravin B Shelar 	struct list_head	list;
82371bd106SPravin B Shelar 	struct socket		*sock;
83371bd106SPravin B Shelar 	struct rcu_head		rcu;
84371bd106SPravin B Shelar 	int			refcnt;
8566d47003SPravin B Shelar 	struct hlist_head	vni_list[VNI_HASH_SIZE];
86371bd106SPravin B Shelar };
872d07dc79SJohn W. Linville 
geneve_net_vni_hash(u8 vni[3])882d07dc79SJohn W. Linville static inline __u32 geneve_net_vni_hash(u8 vni[3])
892d07dc79SJohn W. Linville {
902d07dc79SJohn W. Linville 	__u32 vnid;
912d07dc79SJohn W. Linville 
922d07dc79SJohn W. Linville 	vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
932d07dc79SJohn W. Linville 	return hash_32(vnid, VNI_HASH_BITS);
942d07dc79SJohn W. Linville }
952d07dc79SJohn W. Linville 
vni_to_tunnel_id(const __u8 * vni)96e305ac6cSPravin B Shelar static __be64 vni_to_tunnel_id(const __u8 *vni)
97e305ac6cSPravin B Shelar {
98e305ac6cSPravin B Shelar #ifdef __BIG_ENDIAN
99e305ac6cSPravin B Shelar 	return (vni[0] << 16) | (vni[1] << 8) | vni[2];
100e305ac6cSPravin B Shelar #else
101e305ac6cSPravin B Shelar 	return (__force __be64)(((__force u64)vni[0] << 40) |
102e305ac6cSPravin B Shelar 				((__force u64)vni[1] << 48) |
103e305ac6cSPravin B Shelar 				((__force u64)vni[2] << 56));
104e305ac6cSPravin B Shelar #endif
105e305ac6cSPravin B Shelar }
106e305ac6cSPravin B Shelar 
1079b4437a5Spravin shelar /* Convert 64 bit tunnel ID to 24 bit VNI. */
tunnel_id_to_vni(__be64 tun_id,__u8 * vni)1089b4437a5Spravin shelar static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
1099b4437a5Spravin shelar {
1109b4437a5Spravin shelar #ifdef __BIG_ENDIAN
1119b4437a5Spravin shelar 	vni[0] = (__force __u8)(tun_id >> 16);
1129b4437a5Spravin shelar 	vni[1] = (__force __u8)(tun_id >> 8);
1139b4437a5Spravin shelar 	vni[2] = (__force __u8)tun_id;
1149b4437a5Spravin shelar #else
1159b4437a5Spravin shelar 	vni[0] = (__force __u8)((__force u64)tun_id >> 40);
1169b4437a5Spravin shelar 	vni[1] = (__force __u8)((__force u64)tun_id >> 48);
1179b4437a5Spravin shelar 	vni[2] = (__force __u8)((__force u64)tun_id >> 56);
1189b4437a5Spravin shelar #endif
1199b4437a5Spravin shelar }
1209b4437a5Spravin shelar 
eq_tun_id_and_vni(u8 * tun_id,u8 * vni)1212e0b26e1Spravin shelar static bool eq_tun_id_and_vni(u8 *tun_id, u8 *vni)
1222e0b26e1Spravin shelar {
1232e0b26e1Spravin shelar 	return !memcmp(vni, &tun_id[5], 3);
1242e0b26e1Spravin shelar }
1252e0b26e1Spravin shelar 
geneve_get_sk_family(struct geneve_sock * gs)1261e9f12ecSJiri Benc static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
1271e9f12ecSJiri Benc {
1281e9f12ecSJiri Benc 	return gs->sock->sk->sk_family;
1291e9f12ecSJiri Benc }
1301e9f12ecSJiri Benc 
geneve_lookup(struct geneve_sock * gs,__be32 addr,u8 vni[])13166d47003SPravin B Shelar static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
132371bd106SPravin B Shelar 					__be32 addr, u8 vni[])
1332d07dc79SJohn W. Linville {
1342d07dc79SJohn W. Linville 	struct hlist_head *vni_list_head;
1354b4c21faSJiri Benc 	struct geneve_dev_node *node;
1362d07dc79SJohn W. Linville 	__u32 hash;
1372d07dc79SJohn W. Linville 
1382d07dc79SJohn W. Linville 	/* Find the device for this VNI */
139371bd106SPravin B Shelar 	hash = geneve_net_vni_hash(vni);
14066d47003SPravin B Shelar 	vni_list_head = &gs->vni_list[hash];
1414b4c21faSJiri Benc 	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1429e06e859SSabrina Dubroca 		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1439e06e859SSabrina Dubroca 		    addr == node->geneve->cfg.info.key.u.ipv4.dst)
1444b4c21faSJiri Benc 			return node->geneve;
1452d07dc79SJohn W. Linville 	}
146e305ac6cSPravin B Shelar 	return NULL;
147e305ac6cSPravin B Shelar }
148e305ac6cSPravin B Shelar 
1498ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve6_lookup(struct geneve_sock * gs,struct in6_addr addr6,u8 vni[])1508ed66f0eSJohn W. Linville static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
1518ed66f0eSJohn W. Linville 					 struct in6_addr addr6, u8 vni[])
1528ed66f0eSJohn W. Linville {
1538ed66f0eSJohn W. Linville 	struct hlist_head *vni_list_head;
1544b4c21faSJiri Benc 	struct geneve_dev_node *node;
1558ed66f0eSJohn W. Linville 	__u32 hash;
1568ed66f0eSJohn W. Linville 
1578ed66f0eSJohn W. Linville 	/* Find the device for this VNI */
1588ed66f0eSJohn W. Linville 	hash = geneve_net_vni_hash(vni);
1598ed66f0eSJohn W. Linville 	vni_list_head = &gs->vni_list[hash];
1604b4c21faSJiri Benc 	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1619e06e859SSabrina Dubroca 		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1629e06e859SSabrina Dubroca 		    ipv6_addr_equal(&addr6, &node->geneve->cfg.info.key.u.ipv6.dst))
1634b4c21faSJiri Benc 			return node->geneve;
1648ed66f0eSJohn W. Linville 	}
1658ed66f0eSJohn W. Linville 	return NULL;
1668ed66f0eSJohn W. Linville }
1678ed66f0eSJohn W. Linville #endif
1688ed66f0eSJohn W. Linville 
geneve_hdr(const struct sk_buff * skb)169371bd106SPravin B Shelar static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
170371bd106SPravin B Shelar {
171371bd106SPravin B Shelar 	return (struct genevehdr *)(udp_hdr(skb) + 1);
172371bd106SPravin B Shelar }
173371bd106SPravin B Shelar 
geneve_lookup_skb(struct geneve_sock * gs,struct sk_buff * skb)1749fc47545SJiri Benc static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
1759fc47545SJiri Benc 					    struct sk_buff *skb)
176e305ac6cSPravin B Shelar {
1778ed66f0eSJohn W. Linville 	static u8 zero_vni[3];
1789b4437a5Spravin shelar 	u8 *vni;
179e305ac6cSPravin B Shelar 
1801e9f12ecSJiri Benc 	if (geneve_get_sk_family(gs) == AF_INET) {
1819fc47545SJiri Benc 		struct iphdr *iph;
1829b4437a5Spravin shelar 		__be32 addr;
1839fc47545SJiri Benc 
18408399efcSJohn W. Linville 		iph = ip_hdr(skb); /* outer IP header... */
18508399efcSJohn W. Linville 
186371bd106SPravin B Shelar 		if (gs->collect_md) {
187371bd106SPravin B Shelar 			vni = zero_vni;
188371bd106SPravin B Shelar 			addr = 0;
189371bd106SPravin B Shelar 		} else {
1909fc47545SJiri Benc 			vni = geneve_hdr(skb)->vni;
191371bd106SPravin B Shelar 			addr = iph->saddr;
192371bd106SPravin B Shelar 		}
193371bd106SPravin B Shelar 
1949fc47545SJiri Benc 		return geneve_lookup(gs, addr, vni);
1958ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1961e9f12ecSJiri Benc 	} else if (geneve_get_sk_family(gs) == AF_INET6) {
1979b4437a5Spravin shelar 		static struct in6_addr zero_addr6;
1989fc47545SJiri Benc 		struct ipv6hdr *ip6h;
1999fc47545SJiri Benc 		struct in6_addr addr6;
2009fc47545SJiri Benc 
2018ed66f0eSJohn W. Linville 		ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
2028ed66f0eSJohn W. Linville 
2038ed66f0eSJohn W. Linville 		if (gs->collect_md) {
2048ed66f0eSJohn W. Linville 			vni = zero_vni;
2058ed66f0eSJohn W. Linville 			addr6 = zero_addr6;
2068ed66f0eSJohn W. Linville 		} else {
2079fc47545SJiri Benc 			vni = geneve_hdr(skb)->vni;
2088ed66f0eSJohn W. Linville 			addr6 = ip6h->saddr;
2098ed66f0eSJohn W. Linville 		}
2108ed66f0eSJohn W. Linville 
2119fc47545SJiri Benc 		return geneve6_lookup(gs, addr6, vni);
2128ed66f0eSJohn W. Linville #endif
2138ed66f0eSJohn W. Linville 	}
2149fc47545SJiri Benc 	return NULL;
2159fc47545SJiri Benc }
2169fc47545SJiri Benc 
2179fc47545SJiri Benc /* geneve receive/decap routine */
geneve_rx(struct geneve_dev * geneve,struct geneve_sock * gs,struct sk_buff * skb)2189fc47545SJiri Benc static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
2199fc47545SJiri Benc 		      struct sk_buff *skb)
2209fc47545SJiri Benc {
2219fc47545SJiri Benc 	struct genevehdr *gnvh = geneve_hdr(skb);
2229fc47545SJiri Benc 	struct metadata_dst *tun_dst = NULL;
223fe741e23SGirish Moodalbail 	unsigned int len;
2240ece581dSEric Dumazet 	int nh, err = 0;
2259fc47545SJiri Benc 	void *oiph;
2262d07dc79SJohn W. Linville 
227371bd106SPravin B Shelar 	if (ip_tunnel_collect_metadata() || gs->collect_md) {
228e305ac6cSPravin B Shelar 		__be16 flags;
229e305ac6cSPravin B Shelar 
2309c2e14b4SYi-Hung Wei 		flags = TUNNEL_KEY | (gnvh->oam ? TUNNEL_OAM : 0) |
231e305ac6cSPravin B Shelar 			(gnvh->critical ? TUNNEL_CRIT_OPT : 0);
232e305ac6cSPravin B Shelar 
2331e9f12ecSJiri Benc 		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
234e305ac6cSPravin B Shelar 					 vni_to_tunnel_id(gnvh->vni),
235e305ac6cSPravin B Shelar 					 gnvh->opt_len * 4);
236fe741e23SGirish Moodalbail 		if (!tun_dst) {
237fe741e23SGirish Moodalbail 			geneve->dev->stats.rx_dropped++;
238e305ac6cSPravin B Shelar 			goto drop;
239fe741e23SGirish Moodalbail 		}
240e305ac6cSPravin B Shelar 		/* Update tunnel dst according to Geneve options. */
2414c222798SPravin B Shelar 		ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
242256c87c1SPieter Jansen van Vuuren 					gnvh->options, gnvh->opt_len * 4,
243256c87c1SPieter Jansen van Vuuren 					TUNNEL_GENEVE_OPT);
244e305ac6cSPravin B Shelar 	} else {
2452d07dc79SJohn W. Linville 		/* Drop packets w/ critical options,
2462d07dc79SJohn W. Linville 		 * since we don't support any...
2472d07dc79SJohn W. Linville 		 */
248fe741e23SGirish Moodalbail 		if (gnvh->critical) {
249fe741e23SGirish Moodalbail 			geneve->dev->stats.rx_frame_errors++;
250fe741e23SGirish Moodalbail 			geneve->dev->stats.rx_errors++;
2512d07dc79SJohn W. Linville 			goto drop;
252e305ac6cSPravin B Shelar 		}
253fe741e23SGirish Moodalbail 	}
2542d07dc79SJohn W. Linville 
255435fe1c0SEyal Birger 	if (tun_dst)
256435fe1c0SEyal Birger 		skb_dst_set(skb, &tun_dst->dst);
257435fe1c0SEyal Birger 
258435fe1c0SEyal Birger 	if (gnvh->proto_type == htons(ETH_P_TEB)) {
2592d07dc79SJohn W. Linville 		skb_reset_mac_header(skb);
2602d07dc79SJohn W. Linville 		skb->protocol = eth_type_trans(skb, geneve->dev);
2612d07dc79SJohn W. Linville 		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
2622d07dc79SJohn W. Linville 
2632d07dc79SJohn W. Linville 		/* Ignore packet loops (and multicast echo) */
264435fe1c0SEyal Birger 		if (ether_addr_equal(eth_hdr(skb)->h_source,
265435fe1c0SEyal Birger 				     geneve->dev->dev_addr)) {
266c02bd115SJakub Kicinski 			geneve->dev->stats.rx_errors++;
267c02bd115SJakub Kicinski 			goto drop;
2684179b00cSEric Dumazet 		}
269435fe1c0SEyal Birger 	} else {
270435fe1c0SEyal Birger 		skb_reset_mac_header(skb);
271435fe1c0SEyal Birger 		skb->dev = geneve->dev;
272435fe1c0SEyal Birger 		skb->pkt_type = PACKET_HOST;
273435fe1c0SEyal Birger 	}
274c02bd115SJakub Kicinski 
2750ece581dSEric Dumazet 	/* Save offset of outer header relative to skb->head,
2760ece581dSEric Dumazet 	 * because we are going to reset the network header to the inner header
2770ece581dSEric Dumazet 	 * and might change skb->head.
2780ece581dSEric Dumazet 	 */
2790ece581dSEric Dumazet 	nh = skb_network_header(skb) - skb->head;
2800ece581dSEric Dumazet 
2812d07dc79SJohn W. Linville 	skb_reset_network_header(skb);
2822d07dc79SJohn W. Linville 
2830ece581dSEric Dumazet 	if (!pskb_inet_may_pull(skb)) {
2840ece581dSEric Dumazet 		DEV_STATS_INC(geneve->dev, rx_length_errors);
2850ece581dSEric Dumazet 		DEV_STATS_INC(geneve->dev, rx_errors);
2860ece581dSEric Dumazet 		goto drop;
2870ece581dSEric Dumazet 	}
2880ece581dSEric Dumazet 
2890ece581dSEric Dumazet 	/* Get the outer header. */
2900ece581dSEric Dumazet 	oiph = skb->head + nh;
2910ece581dSEric Dumazet 
2929fc47545SJiri Benc 	if (geneve_get_sk_family(gs) == AF_INET)
2939fc47545SJiri Benc 		err = IP_ECN_decapsulate(oiph, skb);
2948ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
2959fc47545SJiri Benc 	else
2969fc47545SJiri Benc 		err = IP6_ECN_decapsulate(oiph, skb);
2978ed66f0eSJohn W. Linville #endif
2982d07dc79SJohn W. Linville 
2992d07dc79SJohn W. Linville 	if (unlikely(err)) {
3008ed66f0eSJohn W. Linville 		if (log_ecn_error) {
3019fc47545SJiri Benc 			if (geneve_get_sk_family(gs) == AF_INET)
3028ed66f0eSJohn W. Linville 				net_info_ratelimited("non-ECT from %pI4 "
3038ed66f0eSJohn W. Linville 						     "with TOS=%#x\n",
3049fc47545SJiri Benc 						     &((struct iphdr *)oiph)->saddr,
3059fc47545SJiri Benc 						     ((struct iphdr *)oiph)->tos);
3068ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
3079fc47545SJiri Benc 			else
3088ed66f0eSJohn W. Linville 				net_info_ratelimited("non-ECT from %pI6\n",
3099fc47545SJiri Benc 						     &((struct ipv6hdr *)oiph)->saddr);
3108ed66f0eSJohn W. Linville #endif
3118ed66f0eSJohn W. Linville 		}
3122d07dc79SJohn W. Linville 		if (err > 1) {
3132d07dc79SJohn W. Linville 			++geneve->dev->stats.rx_frame_errors;
3142d07dc79SJohn W. Linville 			++geneve->dev->stats.rx_errors;
3152d07dc79SJohn W. Linville 			goto drop;
3162d07dc79SJohn W. Linville 		}
3172d07dc79SJohn W. Linville 	}
3182d07dc79SJohn W. Linville 
319fe741e23SGirish Moodalbail 	len = skb->len;
320fe741e23SGirish Moodalbail 	err = gro_cells_receive(&geneve->gro_cells, skb);
3211e84527bSFabian Frederick 	if (likely(err == NET_RX_SUCCESS))
3221e84527bSFabian Frederick 		dev_sw_netstats_rx_add(geneve->dev, len);
3231e84527bSFabian Frederick 
3242d07dc79SJohn W. Linville 	return;
3252d07dc79SJohn W. Linville drop:
3262d07dc79SJohn W. Linville 	/* Consume bad packet */
3272d07dc79SJohn W. Linville 	kfree_skb(skb);
3282d07dc79SJohn W. Linville }
3292d07dc79SJohn W. Linville 
3302d07dc79SJohn W. Linville /* Setup stats when device is created */
geneve_init(struct net_device * dev)3312d07dc79SJohn W. Linville static int geneve_init(struct net_device *dev)
3322d07dc79SJohn W. Linville {
3338e816df8SJesse Gross 	struct geneve_dev *geneve = netdev_priv(dev);
3348e816df8SJesse Gross 	int err;
3358e816df8SJesse Gross 
3362d07dc79SJohn W. Linville 	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
3372d07dc79SJohn W. Linville 	if (!dev->tstats)
3382d07dc79SJohn W. Linville 		return -ENOMEM;
3398e816df8SJesse Gross 
3408e816df8SJesse Gross 	err = gro_cells_init(&geneve->gro_cells, dev);
3418e816df8SJesse Gross 	if (err) {
3428e816df8SJesse Gross 		free_percpu(dev->tstats);
3438e816df8SJesse Gross 		return err;
3448e816df8SJesse Gross 	}
3458e816df8SJesse Gross 
3469e06e859SSabrina Dubroca 	err = dst_cache_init(&geneve->cfg.info.dst_cache, GFP_KERNEL);
347468dfffcSPaolo Abeni 	if (err) {
348468dfffcSPaolo Abeni 		free_percpu(dev->tstats);
349468dfffcSPaolo Abeni 		gro_cells_destroy(&geneve->gro_cells);
350468dfffcSPaolo Abeni 		return err;
351468dfffcSPaolo Abeni 	}
352a7b862abSEric Dumazet 	netdev_lockdep_set_classes(dev);
3532d07dc79SJohn W. Linville 	return 0;
3542d07dc79SJohn W. Linville }
3552d07dc79SJohn W. Linville 
geneve_uninit(struct net_device * dev)3562d07dc79SJohn W. Linville static void geneve_uninit(struct net_device *dev)
3572d07dc79SJohn W. Linville {
3588e816df8SJesse Gross 	struct geneve_dev *geneve = netdev_priv(dev);
3598e816df8SJesse Gross 
3609e06e859SSabrina Dubroca 	dst_cache_destroy(&geneve->cfg.info.dst_cache);
3618e816df8SJesse Gross 	gro_cells_destroy(&geneve->gro_cells);
3622d07dc79SJohn W. Linville 	free_percpu(dev->tstats);
3632d07dc79SJohn W. Linville }
3642d07dc79SJohn W. Linville 
365371bd106SPravin B Shelar /* Callback from net/ipv4/udp.c to receive packets */
geneve_udp_encap_recv(struct sock * sk,struct sk_buff * skb)366371bd106SPravin B Shelar static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
367371bd106SPravin B Shelar {
368371bd106SPravin B Shelar 	struct genevehdr *geneveh;
3699fc47545SJiri Benc 	struct geneve_dev *geneve;
370371bd106SPravin B Shelar 	struct geneve_sock *gs;
371435fe1c0SEyal Birger 	__be16 inner_proto;
372371bd106SPravin B Shelar 	int opts_len;
373371bd106SPravin B Shelar 
374fe741e23SGirish Moodalbail 	/* Need UDP and Geneve header to be present */
375371bd106SPravin B Shelar 	if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
376e5aed006SHannes Frederic Sowa 		goto drop;
377371bd106SPravin B Shelar 
378371bd106SPravin B Shelar 	/* Return packets with reserved bits set */
379371bd106SPravin B Shelar 	geneveh = geneve_hdr(skb);
380371bd106SPravin B Shelar 	if (unlikely(geneveh->ver != GENEVE_VER))
381e5aed006SHannes Frederic Sowa 		goto drop;
382371bd106SPravin B Shelar 
3839fc47545SJiri Benc 	gs = rcu_dereference_sk_user_data(sk);
3849fc47545SJiri Benc 	if (!gs)
3859fc47545SJiri Benc 		goto drop;
3869fc47545SJiri Benc 
3879fc47545SJiri Benc 	geneve = geneve_lookup_skb(gs, skb);
3889fc47545SJiri Benc 	if (!geneve)
3899fc47545SJiri Benc 		goto drop;
3909fc47545SJiri Benc 
391251d5a28SJosef Miegl 	inner_proto = geneveh->proto_type;
392251d5a28SJosef Miegl 
393435fe1c0SEyal Birger 	if (unlikely((!geneve->cfg.inner_proto_inherit &&
394435fe1c0SEyal Birger 		      inner_proto != htons(ETH_P_TEB)))) {
395435fe1c0SEyal Birger 		geneve->dev->stats.rx_dropped++;
396435fe1c0SEyal Birger 		goto drop;
397435fe1c0SEyal Birger 	}
398435fe1c0SEyal Birger 
399371bd106SPravin B Shelar 	opts_len = geneveh->opt_len * 4;
400435fe1c0SEyal Birger 	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
401fe741e23SGirish Moodalbail 				 !net_eq(geneve->net, dev_net(geneve->dev)))) {
402fe741e23SGirish Moodalbail 		geneve->dev->stats.rx_dropped++;
403371bd106SPravin B Shelar 		goto drop;
404fe741e23SGirish Moodalbail 	}
405371bd106SPravin B Shelar 
4069fc47545SJiri Benc 	geneve_rx(geneve, gs, skb);
407371bd106SPravin B Shelar 	return 0;
408371bd106SPravin B Shelar 
409371bd106SPravin B Shelar drop:
410371bd106SPravin B Shelar 	/* Consume bad packet */
411371bd106SPravin B Shelar 	kfree_skb(skb);
412371bd106SPravin B Shelar 	return 0;
413371bd106SPravin B Shelar }
414371bd106SPravin B Shelar 
415a0796644SStefano Brivio /* Callback from net/ipv{4,6}/udp.c to check that we have a tunnel for errors */
geneve_udp_encap_err_lookup(struct sock * sk,struct sk_buff * skb)416a0796644SStefano Brivio static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
417a0796644SStefano Brivio {
418a0796644SStefano Brivio 	struct genevehdr *geneveh;
419a0796644SStefano Brivio 	struct geneve_sock *gs;
420a0796644SStefano Brivio 	u8 zero_vni[3] = { 0 };
421a0796644SStefano Brivio 	u8 *vni = zero_vni;
422a0796644SStefano Brivio 
423eccc73a6SStefano Brivio 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
424a0796644SStefano Brivio 		return -EINVAL;
425a0796644SStefano Brivio 
426a0796644SStefano Brivio 	geneveh = geneve_hdr(skb);
427a0796644SStefano Brivio 	if (geneveh->ver != GENEVE_VER)
428a0796644SStefano Brivio 		return -EINVAL;
429a0796644SStefano Brivio 
430a0796644SStefano Brivio 	if (geneveh->proto_type != htons(ETH_P_TEB))
431a0796644SStefano Brivio 		return -EINVAL;
432a0796644SStefano Brivio 
433a0796644SStefano Brivio 	gs = rcu_dereference_sk_user_data(sk);
434a0796644SStefano Brivio 	if (!gs)
435a0796644SStefano Brivio 		return -ENOENT;
436a0796644SStefano Brivio 
437a0796644SStefano Brivio 	if (geneve_get_sk_family(gs) == AF_INET) {
438a0796644SStefano Brivio 		struct iphdr *iph = ip_hdr(skb);
439a0796644SStefano Brivio 		__be32 addr4 = 0;
440a0796644SStefano Brivio 
441a0796644SStefano Brivio 		if (!gs->collect_md) {
442a0796644SStefano Brivio 			vni = geneve_hdr(skb)->vni;
443a0796644SStefano Brivio 			addr4 = iph->daddr;
444a0796644SStefano Brivio 		}
445a0796644SStefano Brivio 
446a0796644SStefano Brivio 		return geneve_lookup(gs, addr4, vni) ? 0 : -ENOENT;
447a0796644SStefano Brivio 	}
448a0796644SStefano Brivio 
449a0796644SStefano Brivio #if IS_ENABLED(CONFIG_IPV6)
450a0796644SStefano Brivio 	if (geneve_get_sk_family(gs) == AF_INET6) {
451a0796644SStefano Brivio 		struct ipv6hdr *ip6h = ipv6_hdr(skb);
4528a962c4aSNathan Chancellor 		struct in6_addr addr6;
4538a962c4aSNathan Chancellor 
4548a962c4aSNathan Chancellor 		memset(&addr6, 0, sizeof(struct in6_addr));
455a0796644SStefano Brivio 
456a0796644SStefano Brivio 		if (!gs->collect_md) {
457a0796644SStefano Brivio 			vni = geneve_hdr(skb)->vni;
458a0796644SStefano Brivio 			addr6 = ip6h->daddr;
459a0796644SStefano Brivio 		}
460a0796644SStefano Brivio 
461a0796644SStefano Brivio 		return geneve6_lookup(gs, addr6, vni) ? 0 : -ENOENT;
462a0796644SStefano Brivio 	}
463a0796644SStefano Brivio #endif
464a0796644SStefano Brivio 
465a0796644SStefano Brivio 	return -EPFNOSUPPORT;
466a0796644SStefano Brivio }
467a0796644SStefano Brivio 
geneve_create_sock(struct net * net,bool ipv6,__be16 port,bool ipv6_rx_csum)468371bd106SPravin B Shelar static struct socket *geneve_create_sock(struct net *net, bool ipv6,
4699b4437a5Spravin shelar 					 __be16 port, bool ipv6_rx_csum)
470371bd106SPravin B Shelar {
471371bd106SPravin B Shelar 	struct socket *sock;
472371bd106SPravin B Shelar 	struct udp_port_cfg udp_conf;
473371bd106SPravin B Shelar 	int err;
474371bd106SPravin B Shelar 
475371bd106SPravin B Shelar 	memset(&udp_conf, 0, sizeof(udp_conf));
476371bd106SPravin B Shelar 
477371bd106SPravin B Shelar 	if (ipv6) {
478371bd106SPravin B Shelar 		udp_conf.family = AF_INET6;
4798ed66f0eSJohn W. Linville 		udp_conf.ipv6_v6only = 1;
4809b4437a5Spravin shelar 		udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
481371bd106SPravin B Shelar 	} else {
482371bd106SPravin B Shelar 		udp_conf.family = AF_INET;
483371bd106SPravin B Shelar 		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
484371bd106SPravin B Shelar 	}
485371bd106SPravin B Shelar 
486371bd106SPravin B Shelar 	udp_conf.local_udp_port = port;
487371bd106SPravin B Shelar 
488371bd106SPravin B Shelar 	/* Open UDP socket */
489371bd106SPravin B Shelar 	err = udp_sock_create(net, &udp_conf, &sock);
490371bd106SPravin B Shelar 	if (err < 0)
491371bd106SPravin B Shelar 		return ERR_PTR(err);
492371bd106SPravin B Shelar 
49361630c4fSPaolo Abeni 	udp_allow_gso(sock->sk);
494371bd106SPravin B Shelar 	return sock;
495371bd106SPravin B Shelar }
496371bd106SPravin B Shelar 
geneve_hlen(struct genevehdr * gh)497371bd106SPravin B Shelar static int geneve_hlen(struct genevehdr *gh)
498371bd106SPravin B Shelar {
499371bd106SPravin B Shelar 	return sizeof(*gh) + gh->opt_len * 4;
500371bd106SPravin B Shelar }
501371bd106SPravin B Shelar 
geneve_gro_receive(struct sock * sk,struct list_head * head,struct sk_buff * skb)502d4546c25SDavid Miller static struct sk_buff *geneve_gro_receive(struct sock *sk,
503d4546c25SDavid Miller 					  struct list_head *head,
5044a0090a9STom Herbert 					  struct sk_buff *skb)
505371bd106SPravin B Shelar {
506d4546c25SDavid Miller 	struct sk_buff *pp = NULL;
507d4546c25SDavid Miller 	struct sk_buff *p;
508371bd106SPravin B Shelar 	struct genevehdr *gh, *gh2;
509371bd106SPravin B Shelar 	unsigned int hlen, gh_len, off_gnv;
510371bd106SPravin B Shelar 	const struct packet_offload *ptype;
511371bd106SPravin B Shelar 	__be16 type;
512371bd106SPravin B Shelar 	int flush = 1;
513371bd106SPravin B Shelar 
514371bd106SPravin B Shelar 	off_gnv = skb_gro_offset(skb);
515371bd106SPravin B Shelar 	hlen = off_gnv + sizeof(*gh);
51635ffb665SRichard Gobert 	gh = skb_gro_header(skb, hlen, off_gnv);
517371bd106SPravin B Shelar 	if (unlikely(!gh))
518371bd106SPravin B Shelar 		goto out;
519371bd106SPravin B Shelar 
520371bd106SPravin B Shelar 	if (gh->ver != GENEVE_VER || gh->oam)
521371bd106SPravin B Shelar 		goto out;
522371bd106SPravin B Shelar 	gh_len = geneve_hlen(gh);
523371bd106SPravin B Shelar 
524371bd106SPravin B Shelar 	hlen = off_gnv + gh_len;
525371bd106SPravin B Shelar 	if (skb_gro_header_hard(skb, hlen)) {
526371bd106SPravin B Shelar 		gh = skb_gro_header_slow(skb, hlen, off_gnv);
527371bd106SPravin B Shelar 		if (unlikely(!gh))
528371bd106SPravin B Shelar 			goto out;
529371bd106SPravin B Shelar 	}
530371bd106SPravin B Shelar 
531d4546c25SDavid Miller 	list_for_each_entry(p, head, list) {
532371bd106SPravin B Shelar 		if (!NAPI_GRO_CB(p)->same_flow)
533371bd106SPravin B Shelar 			continue;
534371bd106SPravin B Shelar 
535371bd106SPravin B Shelar 		gh2 = (struct genevehdr *)(p->data + off_gnv);
536371bd106SPravin B Shelar 		if (gh->opt_len != gh2->opt_len ||
537371bd106SPravin B Shelar 		    memcmp(gh, gh2, gh_len)) {
538371bd106SPravin B Shelar 			NAPI_GRO_CB(p)->same_flow = 0;
539371bd106SPravin B Shelar 			continue;
540371bd106SPravin B Shelar 		}
541371bd106SPravin B Shelar 	}
542371bd106SPravin B Shelar 
543f623f83aSPaolo Abeni 	skb_gro_pull(skb, gh_len);
544f623f83aSPaolo Abeni 	skb_gro_postpull_rcsum(skb, gh, gh_len);
545371bd106SPravin B Shelar 	type = gh->proto_type;
546f623f83aSPaolo Abeni 	if (likely(type == htons(ETH_P_TEB)))
547f623f83aSPaolo Abeni 		return call_gro_receive(eth_gro_receive, head, skb);
548371bd106SPravin B Shelar 
549371bd106SPravin B Shelar 	ptype = gro_find_receive_by_type(type);
550c194cf93SAlexander Duyck 	if (!ptype)
551fc1ca334SEric Dumazet 		goto out;
552371bd106SPravin B Shelar 
553fcd91dd4SSabrina Dubroca 	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
554c194cf93SAlexander Duyck 	flush = 0;
555371bd106SPravin B Shelar 
556371bd106SPravin B Shelar out:
557603d4cf8SSabrina Dubroca 	skb_gro_flush_final(skb, pp, flush);
558371bd106SPravin B Shelar 
559371bd106SPravin B Shelar 	return pp;
560371bd106SPravin B Shelar }
561371bd106SPravin B Shelar 
geneve_gro_complete(struct sock * sk,struct sk_buff * skb,int nhoff)5624a0090a9STom Herbert static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
5634a0090a9STom Herbert 			       int nhoff)
564371bd106SPravin B Shelar {
565371bd106SPravin B Shelar 	struct genevehdr *gh;
566371bd106SPravin B Shelar 	struct packet_offload *ptype;
567371bd106SPravin B Shelar 	__be16 type;
568371bd106SPravin B Shelar 	int gh_len;
569371bd106SPravin B Shelar 	int err = -ENOSYS;
570371bd106SPravin B Shelar 
571371bd106SPravin B Shelar 	gh = (struct genevehdr *)(skb->data + nhoff);
572371bd106SPravin B Shelar 	gh_len = geneve_hlen(gh);
573371bd106SPravin B Shelar 	type = gh->proto_type;
574371bd106SPravin B Shelar 
575f623f83aSPaolo Abeni 	/* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */
576f623f83aSPaolo Abeni 	if (likely(type == htons(ETH_P_TEB)))
577f623f83aSPaolo Abeni 		return eth_gro_complete(skb, nhoff + gh_len);
578f623f83aSPaolo Abeni 
579371bd106SPravin B Shelar 	ptype = gro_find_complete_by_type(type);
580371bd106SPravin B Shelar 	if (ptype)
581371bd106SPravin B Shelar 		err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
582371bd106SPravin B Shelar 
583229740c6SJarno Rajahalme 	skb_set_inner_mac_header(skb, nhoff + gh_len);
584229740c6SJarno Rajahalme 
585371bd106SPravin B Shelar 	return err;
586371bd106SPravin B Shelar }
587371bd106SPravin B Shelar 
588371bd106SPravin B Shelar /* Create new listen socket if needed */
geneve_socket_create(struct net * net,__be16 port,bool ipv6,bool ipv6_rx_csum)589371bd106SPravin B Shelar static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
5909b4437a5Spravin shelar 						bool ipv6, bool ipv6_rx_csum)
591371bd106SPravin B Shelar {
592371bd106SPravin B Shelar 	struct geneve_net *gn = net_generic(net, geneve_net_id);
593371bd106SPravin B Shelar 	struct geneve_sock *gs;
594371bd106SPravin B Shelar 	struct socket *sock;
595371bd106SPravin B Shelar 	struct udp_tunnel_sock_cfg tunnel_cfg;
59666d47003SPravin B Shelar 	int h;
597371bd106SPravin B Shelar 
598371bd106SPravin B Shelar 	gs = kzalloc(sizeof(*gs), GFP_KERNEL);
599371bd106SPravin B Shelar 	if (!gs)
600371bd106SPravin B Shelar 		return ERR_PTR(-ENOMEM);
601371bd106SPravin B Shelar 
6029b4437a5Spravin shelar 	sock = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
603371bd106SPravin B Shelar 	if (IS_ERR(sock)) {
604371bd106SPravin B Shelar 		kfree(gs);
605371bd106SPravin B Shelar 		return ERR_CAST(sock);
606371bd106SPravin B Shelar 	}
607371bd106SPravin B Shelar 
608371bd106SPravin B Shelar 	gs->sock = sock;
609371bd106SPravin B Shelar 	gs->refcnt = 1;
61066d47003SPravin B Shelar 	for (h = 0; h < VNI_HASH_SIZE; ++h)
61166d47003SPravin B Shelar 		INIT_HLIST_HEAD(&gs->vni_list[h]);
612371bd106SPravin B Shelar 
613371bd106SPravin B Shelar 	/* Initialize the geneve udp offloads structure */
614e7b3db5eSAlexander Duyck 	udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
615371bd106SPravin B Shelar 
616371bd106SPravin B Shelar 	/* Mark socket as an encapsulation socket */
6174a0090a9STom Herbert 	memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
618371bd106SPravin B Shelar 	tunnel_cfg.sk_user_data = gs;
619371bd106SPravin B Shelar 	tunnel_cfg.encap_type = 1;
6204a0090a9STom Herbert 	tunnel_cfg.gro_receive = geneve_gro_receive;
6214a0090a9STom Herbert 	tunnel_cfg.gro_complete = geneve_gro_complete;
622371bd106SPravin B Shelar 	tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
623a0796644SStefano Brivio 	tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup;
624371bd106SPravin B Shelar 	tunnel_cfg.encap_destroy = NULL;
625371bd106SPravin B Shelar 	setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
626371bd106SPravin B Shelar 	list_add(&gs->list, &gn->sock_list);
627371bd106SPravin B Shelar 	return gs;
628371bd106SPravin B Shelar }
629371bd106SPravin B Shelar 
__geneve_sock_release(struct geneve_sock * gs)6308ed66f0eSJohn W. Linville static void __geneve_sock_release(struct geneve_sock *gs)
631371bd106SPravin B Shelar {
6328ed66f0eSJohn W. Linville 	if (!gs || --gs->refcnt)
633371bd106SPravin B Shelar 		return;
634371bd106SPravin B Shelar 
635371bd106SPravin B Shelar 	list_del(&gs->list);
636e7b3db5eSAlexander Duyck 	udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
637371bd106SPravin B Shelar 	udp_tunnel_sock_release(gs->sock);
638371bd106SPravin B Shelar 	kfree_rcu(gs, rcu);
639371bd106SPravin B Shelar }
640371bd106SPravin B Shelar 
geneve_sock_release(struct geneve_dev * geneve)6418ed66f0eSJohn W. Linville static void geneve_sock_release(struct geneve_dev *geneve)
6428ed66f0eSJohn W. Linville {
643fceb9c3eSpravin shelar 	struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
6448ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
645fceb9c3eSpravin shelar 	struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
646fceb9c3eSpravin shelar 
647fceb9c3eSpravin shelar 	rcu_assign_pointer(geneve->sock6, NULL);
648fceb9c3eSpravin shelar #endif
649fceb9c3eSpravin shelar 
650fceb9c3eSpravin shelar 	rcu_assign_pointer(geneve->sock4, NULL);
651fceb9c3eSpravin shelar 	synchronize_net();
652fceb9c3eSpravin shelar 
653fceb9c3eSpravin shelar 	__geneve_sock_release(gs4);
654fceb9c3eSpravin shelar #if IS_ENABLED(CONFIG_IPV6)
655fceb9c3eSpravin shelar 	__geneve_sock_release(gs6);
6568ed66f0eSJohn W. Linville #endif
6578ed66f0eSJohn W. Linville }
6588ed66f0eSJohn W. Linville 
geneve_find_sock(struct geneve_net * gn,sa_family_t family,__be16 dst_port)659371bd106SPravin B Shelar static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
6608ed66f0eSJohn W. Linville 					    sa_family_t family,
661371bd106SPravin B Shelar 					    __be16 dst_port)
662371bd106SPravin B Shelar {
663371bd106SPravin B Shelar 	struct geneve_sock *gs;
664371bd106SPravin B Shelar 
665371bd106SPravin B Shelar 	list_for_each_entry(gs, &gn->sock_list, list) {
666371bd106SPravin B Shelar 		if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
6671e9f12ecSJiri Benc 		    geneve_get_sk_family(gs) == family) {
668371bd106SPravin B Shelar 			return gs;
669371bd106SPravin B Shelar 		}
670371bd106SPravin B Shelar 	}
671371bd106SPravin B Shelar 	return NULL;
672371bd106SPravin B Shelar }
673371bd106SPravin B Shelar 
geneve_sock_add(struct geneve_dev * geneve,bool ipv6)6748ed66f0eSJohn W. Linville static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
6752d07dc79SJohn W. Linville {
6762d07dc79SJohn W. Linville 	struct net *net = geneve->net;
677371bd106SPravin B Shelar 	struct geneve_net *gn = net_generic(net, geneve_net_id);
6784b4c21faSJiri Benc 	struct geneve_dev_node *node;
6792d07dc79SJohn W. Linville 	struct geneve_sock *gs;
6809b4437a5Spravin shelar 	__u8 vni[3];
68166d47003SPravin B Shelar 	__u32 hash;
6822d07dc79SJohn W. Linville 
6839e06e859SSabrina Dubroca 	gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->cfg.info.key.tp_dst);
684371bd106SPravin B Shelar 	if (gs) {
685371bd106SPravin B Shelar 		gs->refcnt++;
686371bd106SPravin B Shelar 		goto out;
687371bd106SPravin B Shelar 	}
688371bd106SPravin B Shelar 
6899e06e859SSabrina Dubroca 	gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6,
6909e06e859SSabrina Dubroca 				  geneve->cfg.use_udp6_rx_checksums);
6912d07dc79SJohn W. Linville 	if (IS_ERR(gs))
6922d07dc79SJohn W. Linville 		return PTR_ERR(gs);
6932d07dc79SJohn W. Linville 
694371bd106SPravin B Shelar out:
6959e06e859SSabrina Dubroca 	gs->collect_md = geneve->cfg.collect_md;
6968ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
6974b4c21faSJiri Benc 	if (ipv6) {
698fceb9c3eSpravin shelar 		rcu_assign_pointer(geneve->sock6, gs);
6994b4c21faSJiri Benc 		node = &geneve->hlist6;
7004b4c21faSJiri Benc 	} else
7018ed66f0eSJohn W. Linville #endif
7024b4c21faSJiri Benc 	{
703fceb9c3eSpravin shelar 		rcu_assign_pointer(geneve->sock4, gs);
7044b4c21faSJiri Benc 		node = &geneve->hlist4;
7054b4c21faSJiri Benc 	}
7064b4c21faSJiri Benc 	node->geneve = geneve;
70766d47003SPravin B Shelar 
7089e06e859SSabrina Dubroca 	tunnel_id_to_vni(geneve->cfg.info.key.tun_id, vni);
7099b4437a5Spravin shelar 	hash = geneve_net_vni_hash(vni);
7104b4c21faSJiri Benc 	hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]);
7112d07dc79SJohn W. Linville 	return 0;
7122d07dc79SJohn W. Linville }
7132d07dc79SJohn W. Linville 
geneve_open(struct net_device * dev)7148ed66f0eSJohn W. Linville static int geneve_open(struct net_device *dev)
7158ed66f0eSJohn W. Linville {
7168ed66f0eSJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
7179e06e859SSabrina Dubroca 	bool metadata = geneve->cfg.collect_md;
718cf1c9ccbSJiri Benc 	bool ipv4, ipv6;
7198ed66f0eSJohn W. Linville 	int ret = 0;
7208ed66f0eSJohn W. Linville 
7219e06e859SSabrina Dubroca 	ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
722cf1c9ccbSJiri Benc 	ipv4 = !ipv6 || metadata;
7238ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
724cf1c9ccbSJiri Benc 	if (ipv6) {
7258ed66f0eSJohn W. Linville 		ret = geneve_sock_add(geneve, true);
726cf1c9ccbSJiri Benc 		if (ret < 0 && ret != -EAFNOSUPPORT)
727cf1c9ccbSJiri Benc 			ipv4 = false;
728cf1c9ccbSJiri Benc 	}
7298ed66f0eSJohn W. Linville #endif
730cf1c9ccbSJiri Benc 	if (ipv4)
7318ed66f0eSJohn W. Linville 		ret = geneve_sock_add(geneve, false);
7328ed66f0eSJohn W. Linville 	if (ret < 0)
7338ed66f0eSJohn W. Linville 		geneve_sock_release(geneve);
7348ed66f0eSJohn W. Linville 
7358ed66f0eSJohn W. Linville 	return ret;
7368ed66f0eSJohn W. Linville }
7378ed66f0eSJohn W. Linville 
geneve_stop(struct net_device * dev)7382d07dc79SJohn W. Linville static int geneve_stop(struct net_device *dev)
7392d07dc79SJohn W. Linville {
7402d07dc79SJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
7412d07dc79SJohn W. Linville 
7424b4c21faSJiri Benc 	hlist_del_init_rcu(&geneve->hlist4.hlist);
7434b4c21faSJiri Benc #if IS_ENABLED(CONFIG_IPV6)
7444b4c21faSJiri Benc 	hlist_del_init_rcu(&geneve->hlist6.hlist);
7454b4c21faSJiri Benc #endif
7468ed66f0eSJohn W. Linville 	geneve_sock_release(geneve);
7472d07dc79SJohn W. Linville 	return 0;
7482d07dc79SJohn W. Linville }
7492d07dc79SJohn W. Linville 
geneve_build_header(struct genevehdr * geneveh,const struct ip_tunnel_info * info,__be16 inner_proto)7508ed66f0eSJohn W. Linville static void geneve_build_header(struct genevehdr *geneveh,
751435fe1c0SEyal Birger 				const struct ip_tunnel_info *info,
752435fe1c0SEyal Birger 				__be16 inner_proto)
7538ed66f0eSJohn W. Linville {
7548ed66f0eSJohn W. Linville 	geneveh->ver = GENEVE_VER;
755c3ef5aa5Spravin shelar 	geneveh->opt_len = info->options_len / 4;
756c3ef5aa5Spravin shelar 	geneveh->oam = !!(info->key.tun_flags & TUNNEL_OAM);
757c3ef5aa5Spravin shelar 	geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
7588ed66f0eSJohn W. Linville 	geneveh->rsvd1 = 0;
759c3ef5aa5Spravin shelar 	tunnel_id_to_vni(info->key.tun_id, geneveh->vni);
760435fe1c0SEyal Birger 	geneveh->proto_type = inner_proto;
7618ed66f0eSJohn W. Linville 	geneveh->rsvd2 = 0;
7628ed66f0eSJohn W. Linville 
763256c87c1SPieter Jansen van Vuuren 	if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
764c3ef5aa5Spravin shelar 		ip_tunnel_info_opts_get(geneveh->options, info);
7658ed66f0eSJohn W. Linville }
7668ed66f0eSJohn W. Linville 
geneve_build_skb(struct dst_entry * dst,struct sk_buff * skb,const struct ip_tunnel_info * info,bool xnet,int ip_hdr_len,bool inner_proto_inherit)767c3ef5aa5Spravin shelar static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
768c3ef5aa5Spravin shelar 			    const struct ip_tunnel_info *info,
769435fe1c0SEyal Birger 			    bool xnet, int ip_hdr_len,
770435fe1c0SEyal Birger 			    bool inner_proto_inherit)
771371bd106SPravin B Shelar {
772c3ef5aa5Spravin shelar 	bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
773371bd106SPravin B Shelar 	struct genevehdr *gnvh;
774435fe1c0SEyal Birger 	__be16 inner_proto;
775371bd106SPravin B Shelar 	int min_headroom;
776371bd106SPravin B Shelar 	int err;
777371bd106SPravin B Shelar 
778c3ef5aa5Spravin shelar 	skb_reset_mac_header(skb);
7798ed66f0eSJohn W. Linville 	skb_scrub_packet(skb, xnet);
7808ed66f0eSJohn W. Linville 
781c3ef5aa5Spravin shelar 	min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +
782c3ef5aa5Spravin shelar 		       GENEVE_BASE_HLEN + info->options_len + ip_hdr_len;
7838ed66f0eSJohn W. Linville 	err = skb_cow_head(skb, min_headroom);
784aed069dfSAlexander Duyck 	if (unlikely(err))
7858ed66f0eSJohn W. Linville 		goto free_dst;
7868ed66f0eSJohn W. Linville 
787aed069dfSAlexander Duyck 	err = udp_tunnel_handle_offloads(skb, udp_sum);
7881ba64facSDan Carpenter 	if (err)
7898ed66f0eSJohn W. Linville 		goto free_dst;
7908ed66f0eSJohn W. Linville 
791d58ff351SJohannes Berg 	gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
792435fe1c0SEyal Birger 	inner_proto = inner_proto_inherit ? skb->protocol : htons(ETH_P_TEB);
793435fe1c0SEyal Birger 	geneve_build_header(gnvh, info, inner_proto);
794435fe1c0SEyal Birger 	skb_set_inner_protocol(skb, inner_proto);
7958ed66f0eSJohn W. Linville 	return 0;
7968ed66f0eSJohn W. Linville 
7978ed66f0eSJohn W. Linville free_dst:
7988ed66f0eSJohn W. Linville 	dst_release(dst);
7998ed66f0eSJohn W. Linville 	return err;
8008ed66f0eSJohn W. Linville }
8018ed66f0eSJohn W. Linville 
geneve_get_v4_rt(struct sk_buff * skb,struct net_device * dev,struct geneve_sock * gs4,struct flowi4 * fl4,const struct ip_tunnel_info * info,__be16 dport,__be16 sport,__u8 * full_tos)8028ed66f0eSJohn W. Linville static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
803e305ac6cSPravin B Shelar 				       struct net_device *dev,
8045b861f6bSGirish Moodalbail 				       struct geneve_sock *gs4,
805e305ac6cSPravin B Shelar 				       struct flowi4 *fl4,
80634beb215SMark Gray 				       const struct ip_tunnel_info *info,
807b4ab94d6SMatthias May 				       __be16 dport, __be16 sport,
808b4ab94d6SMatthias May 				       __u8 *full_tos)
809e305ac6cSPravin B Shelar {
810db3c6139SDaniel Borkmann 	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
811e305ac6cSPravin B Shelar 	struct geneve_dev *geneve = netdev_priv(dev);
812468dfffcSPaolo Abeni 	struct dst_cache *dst_cache;
813e305ac6cSPravin B Shelar 	struct rtable *rt = NULL;
814e305ac6cSPravin B Shelar 	__u8 tos;
815e305ac6cSPravin B Shelar 
8165b861f6bSGirish Moodalbail 	if (!gs4)
817fceb9c3eSpravin shelar 		return ERR_PTR(-EIO);
818fceb9c3eSpravin shelar 
819e305ac6cSPravin B Shelar 	memset(fl4, 0, sizeof(*fl4));
820e305ac6cSPravin B Shelar 	fl4->flowi4_mark = skb->mark;
821e305ac6cSPravin B Shelar 	fl4->flowi4_proto = IPPROTO_UDP;
822e305ac6cSPravin B Shelar 	fl4->daddr = info->key.u.ipv4.dst;
823e305ac6cSPravin B Shelar 	fl4->saddr = info->key.u.ipv4.src;
82434beb215SMark Gray 	fl4->fl4_dport = dport;
82534beb215SMark Gray 	fl4->fl4_sport = sport;
826861396acSPaul Chaignon 	fl4->flowi4_flags = info->key.flow_flags;
827e305ac6cSPravin B Shelar 
8289b4437a5Spravin shelar 	tos = info->key.tos;
8299e06e859SSabrina Dubroca 	if ((tos == 1) && !geneve->cfg.collect_md) {
8309b4437a5Spravin shelar 		tos = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
831468dfffcSPaolo Abeni 		use_cache = false;
832e305ac6cSPravin B Shelar 	}
833e305ac6cSPravin B Shelar 	fl4->flowi4_tos = RT_TOS(tos);
834b4ab94d6SMatthias May 	if (full_tos)
835b4ab94d6SMatthias May 		*full_tos = tos;
836468dfffcSPaolo Abeni 
837c3ef5aa5Spravin shelar 	dst_cache = (struct dst_cache *)&info->dst_cache;
838468dfffcSPaolo Abeni 	if (use_cache) {
839468dfffcSPaolo Abeni 		rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
840468dfffcSPaolo Abeni 		if (rt)
841468dfffcSPaolo Abeni 			return rt;
842e305ac6cSPravin B Shelar 	}
843e305ac6cSPravin B Shelar 	rt = ip_route_output_key(geneve->net, fl4);
844e305ac6cSPravin B Shelar 	if (IS_ERR(rt)) {
845e305ac6cSPravin B Shelar 		netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr);
846fc4099f1SPravin B Shelar 		return ERR_PTR(-ENETUNREACH);
847e305ac6cSPravin B Shelar 	}
848e305ac6cSPravin B Shelar 	if (rt->dst.dev == dev) { /* is this necessary? */
849e305ac6cSPravin B Shelar 		netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
850e305ac6cSPravin B Shelar 		ip_rt_put(rt);
851fc4099f1SPravin B Shelar 		return ERR_PTR(-ELOOP);
852e305ac6cSPravin B Shelar 	}
853468dfffcSPaolo Abeni 	if (use_cache)
854468dfffcSPaolo Abeni 		dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
855e305ac6cSPravin B Shelar 	return rt;
856e305ac6cSPravin B Shelar }
857e305ac6cSPravin B Shelar 
8588ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve_get_v6_dst(struct sk_buff * skb,struct net_device * dev,struct geneve_sock * gs6,struct flowi6 * fl6,const struct ip_tunnel_info * info,__be16 dport,__be16 sport)8598ed66f0eSJohn W. Linville static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
8608ed66f0eSJohn W. Linville 					   struct net_device *dev,
8615b861f6bSGirish Moodalbail 					   struct geneve_sock *gs6,
8628ed66f0eSJohn W. Linville 					   struct flowi6 *fl6,
86334beb215SMark Gray 					   const struct ip_tunnel_info *info,
86434beb215SMark Gray 					   __be16 dport, __be16 sport)
8658ed66f0eSJohn W. Linville {
866db3c6139SDaniel Borkmann 	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
8678ed66f0eSJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
8688ed66f0eSJohn W. Linville 	struct dst_entry *dst = NULL;
869468dfffcSPaolo Abeni 	struct dst_cache *dst_cache;
8703a56f86fSJohn W. Linville 	__u8 prio;
8718ed66f0eSJohn W. Linville 
872fceb9c3eSpravin shelar 	if (!gs6)
873fceb9c3eSpravin shelar 		return ERR_PTR(-EIO);
874fceb9c3eSpravin shelar 
8758ed66f0eSJohn W. Linville 	memset(fl6, 0, sizeof(*fl6));
8768ed66f0eSJohn W. Linville 	fl6->flowi6_mark = skb->mark;
8778ed66f0eSJohn W. Linville 	fl6->flowi6_proto = IPPROTO_UDP;
8788ed66f0eSJohn W. Linville 	fl6->daddr = info->key.u.ipv6.dst;
8798ed66f0eSJohn W. Linville 	fl6->saddr = info->key.u.ipv6.src;
88034beb215SMark Gray 	fl6->fl6_dport = dport;
88134beb215SMark Gray 	fl6->fl6_sport = sport;
88234beb215SMark Gray 
8839b4437a5Spravin shelar 	prio = info->key.tos;
8849e06e859SSabrina Dubroca 	if ((prio == 1) && !geneve->cfg.collect_md) {
8859b4437a5Spravin shelar 		prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
886468dfffcSPaolo Abeni 		use_cache = false;
8873a56f86fSJohn W. Linville 	}
8883a56f86fSJohn W. Linville 
889ca2bb695SMatthias May 	fl6->flowlabel = ip6_make_flowinfo(prio, info->key.label);
890c3ef5aa5Spravin shelar 	dst_cache = (struct dst_cache *)&info->dst_cache;
891468dfffcSPaolo Abeni 	if (use_cache) {
892468dfffcSPaolo Abeni 		dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
893468dfffcSPaolo Abeni 		if (dst)
894468dfffcSPaolo Abeni 			return dst;
8958ed66f0eSJohn W. Linville 	}
8966c8991f4SSabrina Dubroca 	dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
8976c8991f4SSabrina Dubroca 					      NULL);
8986c8991f4SSabrina Dubroca 	if (IS_ERR(dst)) {
8998ed66f0eSJohn W. Linville 		netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr);
9008ed66f0eSJohn W. Linville 		return ERR_PTR(-ENETUNREACH);
9018ed66f0eSJohn W. Linville 	}
9028ed66f0eSJohn W. Linville 	if (dst->dev == dev) { /* is this necessary? */
9038ed66f0eSJohn W. Linville 		netdev_dbg(dev, "circular route to %pI6\n", &fl6->daddr);
9048ed66f0eSJohn W. Linville 		dst_release(dst);
9058ed66f0eSJohn W. Linville 		return ERR_PTR(-ELOOP);
9068ed66f0eSJohn W. Linville 	}
9078ed66f0eSJohn W. Linville 
908468dfffcSPaolo Abeni 	if (use_cache)
909468dfffcSPaolo Abeni 		dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
9108ed66f0eSJohn W. Linville 	return dst;
9118ed66f0eSJohn W. Linville }
9128ed66f0eSJohn W. Linville #endif
9138ed66f0eSJohn W. Linville 
geneve_xmit_skb(struct sk_buff * skb,struct net_device * dev,struct geneve_dev * geneve,const struct ip_tunnel_info * info)9149b4437a5Spravin shelar static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
915c3ef5aa5Spravin shelar 			   struct geneve_dev *geneve,
916c3ef5aa5Spravin shelar 			   const struct ip_tunnel_info *info)
917e305ac6cSPravin B Shelar {
918bb5c1b0fSGal Pressman 	bool inner_proto_inherit = geneve->cfg.inner_proto_inherit;
9199b4437a5Spravin shelar 	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
9209b4437a5Spravin shelar 	struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
9219b4437a5Spravin shelar 	const struct ip_tunnel_key *key = &info->key;
9229b4437a5Spravin shelar 	struct rtable *rt;
9232d07dc79SJohn W. Linville 	struct flowi4 fl4;
924b4ab94d6SMatthias May 	__u8 full_tos;
9258760ce58SJohn W. Linville 	__u8 tos, ttl;
926a025fb5fSStefano Brivio 	__be16 df = 0;
927e305ac6cSPravin B Shelar 	__be16 sport;
928bcceeec3Spravin shelar 	int err;
9292d07dc79SJohn W. Linville 
930bb5c1b0fSGal Pressman 	if (!skb_vlan_inet_prepare(skb, inner_proto_inherit))
9316628ddfeSPhillip Potter 		return -EINVAL;
9326628ddfeSPhillip Potter 
93334beb215SMark Gray 	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
93434beb215SMark Gray 	rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
935b4ab94d6SMatthias May 			      geneve->cfg.info.key.tp_dst, sport, &full_tos);
9369b4437a5Spravin shelar 	if (IS_ERR(rt))
9379b4437a5Spravin shelar 		return PTR_ERR(rt);
938371bd106SPravin B Shelar 
939c1a800e8SStefano Brivio 	err = skb_tunnel_check_pmtu(skb, &rt->dst,
940c1a800e8SStefano Brivio 				    GENEVE_IPV4_HLEN + info->options_len,
941c1a800e8SStefano Brivio 				    netif_is_any_bridge_port(dev));
942c1a800e8SStefano Brivio 	if (err < 0) {
943c1a800e8SStefano Brivio 		dst_release(&rt->dst);
944c1a800e8SStefano Brivio 		return err;
945c1a800e8SStefano Brivio 	} else if (err) {
946c1a800e8SStefano Brivio 		struct ip_tunnel_info *info;
947c1a800e8SStefano Brivio 
948c1a800e8SStefano Brivio 		info = skb_tunnel_info(skb);
949c1a800e8SStefano Brivio 		if (info) {
95068c1a943SAntoine Tenart 			struct ip_tunnel_info *unclone;
95168c1a943SAntoine Tenart 
95268c1a943SAntoine Tenart 			unclone = skb_tunnel_info_unclone(skb);
95368c1a943SAntoine Tenart 			if (unlikely(!unclone)) {
95468c1a943SAntoine Tenart 				dst_release(&rt->dst);
95568c1a943SAntoine Tenart 				return -ENOMEM;
95668c1a943SAntoine Tenart 			}
95768c1a943SAntoine Tenart 
95868c1a943SAntoine Tenart 			unclone->key.u.ipv4.dst = fl4.saddr;
95968c1a943SAntoine Tenart 			unclone->key.u.ipv4.src = fl4.daddr;
960c1a800e8SStefano Brivio 		}
961c1a800e8SStefano Brivio 
962c1a800e8SStefano Brivio 		if (!pskb_may_pull(skb, ETH_HLEN)) {
963c1a800e8SStefano Brivio 			dst_release(&rt->dst);
964c1a800e8SStefano Brivio 			return -EINVAL;
965c1a800e8SStefano Brivio 		}
966c1a800e8SStefano Brivio 
967c1a800e8SStefano Brivio 		skb->protocol = eth_type_trans(skb, geneve->dev);
968baebdf48SSebastian Andrzej Siewior 		__netif_rx(skb);
969c1a800e8SStefano Brivio 		dst_release(&rt->dst);
970c1a800e8SStefano Brivio 		return -EMSGSIZE;
971c1a800e8SStefano Brivio 	}
97252a589d5SXin Long 
9739e06e859SSabrina Dubroca 	if (geneve->cfg.collect_md) {
9749b4437a5Spravin shelar 		tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
9759b4437a5Spravin shelar 		ttl = key->ttl;
976a025fb5fSStefano Brivio 
977a025fb5fSStefano Brivio 		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
9789b4437a5Spravin shelar 	} else {
979b4ab94d6SMatthias May 		tos = ip_tunnel_ecn_encap(full_tos, ip_hdr(skb), skb);
9809e06e859SSabrina Dubroca 		if (geneve->cfg.ttl_inherit)
98152d0d404SHangbin Liu 			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
98252d0d404SHangbin Liu 		else
98352d0d404SHangbin Liu 			ttl = key->ttl;
98452d0d404SHangbin Liu 		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
985a025fb5fSStefano Brivio 
9869e06e859SSabrina Dubroca 		if (geneve->cfg.df == GENEVE_DF_SET) {
987a025fb5fSStefano Brivio 			df = htons(IP_DF);
9889e06e859SSabrina Dubroca 		} else if (geneve->cfg.df == GENEVE_DF_INHERIT) {
98997ce3a4eSEric Dumazet 			struct ethhdr *eth = skb_eth_hdr(skb);
990a025fb5fSStefano Brivio 
991a025fb5fSStefano Brivio 			if (ntohs(eth->h_proto) == ETH_P_IPV6) {
992a025fb5fSStefano Brivio 				df = htons(IP_DF);
993a025fb5fSStefano Brivio 			} else if (ntohs(eth->h_proto) == ETH_P_IP) {
994a025fb5fSStefano Brivio 				struct iphdr *iph = ip_hdr(skb);
995a025fb5fSStefano Brivio 
996a025fb5fSStefano Brivio 				if (iph->frag_off & htons(IP_DF))
997a025fb5fSStefano Brivio 					df = htons(IP_DF);
9989b4437a5Spravin shelar 			}
999a025fb5fSStefano Brivio 		}
1000a025fb5fSStefano Brivio 	}
1001e305ac6cSPravin B Shelar 
1002435fe1c0SEyal Birger 	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr),
1003bb5c1b0fSGal Pressman 			       inner_proto_inherit);
1004371bd106SPravin B Shelar 	if (unlikely(err))
10059b4437a5Spravin shelar 		return err;
1006371bd106SPravin B Shelar 
1007039f5062SPravin B Shelar 	udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
10089e06e859SSabrina Dubroca 			    tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
1009371bd106SPravin B Shelar 			    !net_eq(geneve->net, dev_net(geneve->dev)),
10109b4437a5Spravin shelar 			    !(info->key.tun_flags & TUNNEL_CSUM));
10119b4437a5Spravin shelar 	return 0;
10122d07dc79SJohn W. Linville }
10132d07dc79SJohn W. Linville 
10148ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve6_xmit_skb(struct sk_buff * skb,struct net_device * dev,struct geneve_dev * geneve,const struct ip_tunnel_info * info)10159b4437a5Spravin shelar static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
1016c3ef5aa5Spravin shelar 			    struct geneve_dev *geneve,
1017c3ef5aa5Spravin shelar 			    const struct ip_tunnel_info *info)
10188ed66f0eSJohn W. Linville {
1019bb5c1b0fSGal Pressman 	bool inner_proto_inherit = geneve->cfg.inner_proto_inherit;
10209b4437a5Spravin shelar 	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
10219b4437a5Spravin shelar 	struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
10229b4437a5Spravin shelar 	const struct ip_tunnel_key *key = &info->key;
10238ed66f0eSJohn W. Linville 	struct dst_entry *dst = NULL;
10248ed66f0eSJohn W. Linville 	struct flowi6 fl6;
10253a56f86fSJohn W. Linville 	__u8 prio, ttl;
10268ed66f0eSJohn W. Linville 	__be16 sport;
1027bcceeec3Spravin shelar 	int err;
10289b4437a5Spravin shelar 
1029bb5c1b0fSGal Pressman 	if (!skb_vlan_inet_prepare(skb, inner_proto_inherit))
10306628ddfeSPhillip Potter 		return -EINVAL;
10316628ddfeSPhillip Potter 
103234beb215SMark Gray 	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
103334beb215SMark Gray 	dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
103434beb215SMark Gray 				geneve->cfg.info.key.tp_dst, sport);
10359b4437a5Spravin shelar 	if (IS_ERR(dst))
10369b4437a5Spravin shelar 		return PTR_ERR(dst);
10379b4437a5Spravin shelar 
1038c1a800e8SStefano Brivio 	err = skb_tunnel_check_pmtu(skb, dst,
1039c1a800e8SStefano Brivio 				    GENEVE_IPV6_HLEN + info->options_len,
1040c1a800e8SStefano Brivio 				    netif_is_any_bridge_port(dev));
1041c1a800e8SStefano Brivio 	if (err < 0) {
1042c1a800e8SStefano Brivio 		dst_release(dst);
1043c1a800e8SStefano Brivio 		return err;
1044c1a800e8SStefano Brivio 	} else if (err) {
1045c1a800e8SStefano Brivio 		struct ip_tunnel_info *info = skb_tunnel_info(skb);
1046c1a800e8SStefano Brivio 
1047c1a800e8SStefano Brivio 		if (info) {
104868c1a943SAntoine Tenart 			struct ip_tunnel_info *unclone;
104968c1a943SAntoine Tenart 
105068c1a943SAntoine Tenart 			unclone = skb_tunnel_info_unclone(skb);
105168c1a943SAntoine Tenart 			if (unlikely(!unclone)) {
105268c1a943SAntoine Tenart 				dst_release(dst);
105368c1a943SAntoine Tenart 				return -ENOMEM;
105468c1a943SAntoine Tenart 			}
105568c1a943SAntoine Tenart 
105668c1a943SAntoine Tenart 			unclone->key.u.ipv6.dst = fl6.saddr;
105768c1a943SAntoine Tenart 			unclone->key.u.ipv6.src = fl6.daddr;
1058c1a800e8SStefano Brivio 		}
1059c1a800e8SStefano Brivio 
1060c1a800e8SStefano Brivio 		if (!pskb_may_pull(skb, ETH_HLEN)) {
1061c1a800e8SStefano Brivio 			dst_release(dst);
1062c1a800e8SStefano Brivio 			return -EINVAL;
1063c1a800e8SStefano Brivio 		}
1064c1a800e8SStefano Brivio 
1065c1a800e8SStefano Brivio 		skb->protocol = eth_type_trans(skb, geneve->dev);
1066baebdf48SSebastian Andrzej Siewior 		__netif_rx(skb);
1067c1a800e8SStefano Brivio 		dst_release(dst);
1068c1a800e8SStefano Brivio 		return -EMSGSIZE;
1069c1a800e8SStefano Brivio 	}
107052a589d5SXin Long 
10719e06e859SSabrina Dubroca 	if (geneve->cfg.collect_md) {
10729b4437a5Spravin shelar 		prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
10739b4437a5Spravin shelar 		ttl = key->ttl;
10749b4437a5Spravin shelar 	} else {
10759b4437a5Spravin shelar 		prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
10769b4437a5Spravin shelar 					   ip_hdr(skb), skb);
10779e06e859SSabrina Dubroca 		if (geneve->cfg.ttl_inherit)
107852d0d404SHangbin Liu 			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
107952d0d404SHangbin Liu 		else
108052d0d404SHangbin Liu 			ttl = key->ttl;
108152d0d404SHangbin Liu 		ttl = ttl ? : ip6_dst_hoplimit(dst);
10829b4437a5Spravin shelar 	}
1083435fe1c0SEyal Birger 	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr),
1084bb5c1b0fSGal Pressman 			       inner_proto_inherit);
10858ed66f0eSJohn W. Linville 	if (unlikely(err))
10869b4437a5Spravin shelar 		return err;
10878eb3b995SDaniel Borkmann 
1088039f5062SPravin B Shelar 	udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
10899b4437a5Spravin shelar 			     &fl6.saddr, &fl6.daddr, prio, ttl,
10909e06e859SSabrina Dubroca 			     info->key.label, sport, geneve->cfg.info.key.tp_dst,
10919b4437a5Spravin shelar 			     !(info->key.tun_flags & TUNNEL_CSUM));
10929b4437a5Spravin shelar 	return 0;
10938ed66f0eSJohn W. Linville }
10948ed66f0eSJohn W. Linville #endif
10958ed66f0eSJohn W. Linville 
geneve_xmit(struct sk_buff * skb,struct net_device * dev)10968ed66f0eSJohn W. Linville static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
10978ed66f0eSJohn W. Linville {
10988ed66f0eSJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
10998ed66f0eSJohn W. Linville 	struct ip_tunnel_info *info = NULL;
11009b4437a5Spravin shelar 	int err;
11018ed66f0eSJohn W. Linville 
11029e06e859SSabrina Dubroca 	if (geneve->cfg.collect_md) {
11038ed66f0eSJohn W. Linville 		info = skb_tunnel_info(skb);
11049b4437a5Spravin shelar 		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
11059b4437a5Spravin shelar 			netdev_dbg(dev, "no tunnel metadata\n");
11069d149045SJiri Benc 			dev_kfree_skb(skb);
11079d149045SJiri Benc 			dev->stats.tx_dropped++;
11089d149045SJiri Benc 			return NETDEV_TX_OK;
11099b4437a5Spravin shelar 		}
11109b4437a5Spravin shelar 	} else {
11119e06e859SSabrina Dubroca 		info = &geneve->cfg.info;
11129b4437a5Spravin shelar 	}
11138ed66f0eSJohn W. Linville 
1114a717e3f7SJakub Kicinski 	rcu_read_lock();
11158ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
11169b4437a5Spravin shelar 	if (info->mode & IP_TUNNEL_INFO_IPV6)
11179b4437a5Spravin shelar 		err = geneve6_xmit_skb(skb, dev, geneve, info);
11189b4437a5Spravin shelar 	else
11198ed66f0eSJohn W. Linville #endif
11209b4437a5Spravin shelar 		err = geneve_xmit_skb(skb, dev, geneve, info);
1121a717e3f7SJakub Kicinski 	rcu_read_unlock();
11229b4437a5Spravin shelar 
11239b4437a5Spravin shelar 	if (likely(!err))
11249b4437a5Spravin shelar 		return NETDEV_TX_OK;
11259d149045SJiri Benc 
1126c1a800e8SStefano Brivio 	if (err != -EMSGSIZE)
11279b4437a5Spravin shelar 		dev_kfree_skb(skb);
11289b4437a5Spravin shelar 
11299b4437a5Spravin shelar 	if (err == -ELOOP)
11309b4437a5Spravin shelar 		dev->stats.collisions++;
11319b4437a5Spravin shelar 	else if (err == -ENETUNREACH)
11329b4437a5Spravin shelar 		dev->stats.tx_carrier_errors++;
11339b4437a5Spravin shelar 
11349b4437a5Spravin shelar 	dev->stats.tx_errors++;
11359b4437a5Spravin shelar 	return NETDEV_TX_OK;
11368ed66f0eSJohn W. Linville }
11378ed66f0eSJohn W. Linville 
geneve_change_mtu(struct net_device * dev,int new_mtu)113891572088SJarod Wilson static int geneve_change_mtu(struct net_device *dev, int new_mtu)
113955e5bfb5SDavid Wragg {
114091572088SJarod Wilson 	if (new_mtu > dev->max_mtu)
114191572088SJarod Wilson 		new_mtu = dev->max_mtu;
1142321acc1cSAlexey Kodanev 	else if (new_mtu < dev->min_mtu)
1143321acc1cSAlexey Kodanev 		new_mtu = dev->min_mtu;
1144aeee0e66SDavid Wragg 
114555e5bfb5SDavid Wragg 	dev->mtu = new_mtu;
114655e5bfb5SDavid Wragg 	return 0;
114755e5bfb5SDavid Wragg }
114855e5bfb5SDavid Wragg 
geneve_fill_metadata_dst(struct net_device * dev,struct sk_buff * skb)1149fc4099f1SPravin B Shelar static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
1150fc4099f1SPravin B Shelar {
1151fc4099f1SPravin B Shelar 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
1152fc4099f1SPravin B Shelar 	struct geneve_dev *geneve = netdev_priv(dev);
115334beb215SMark Gray 	__be16 sport;
1154fc4099f1SPravin B Shelar 
1155b8812fa8SJohn W. Linville 	if (ip_tunnel_info_af(info) == AF_INET) {
11569b4437a5Spravin shelar 		struct rtable *rt;
11579b4437a5Spravin shelar 		struct flowi4 fl4;
11589b4437a5Spravin shelar 
115934beb215SMark Gray 		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
116034beb215SMark Gray 		sport = udp_flow_src_port(geneve->net, skb,
116134beb215SMark Gray 					  1, USHRT_MAX, true);
116234beb215SMark Gray 
116334beb215SMark Gray 		rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
1164b4ab94d6SMatthias May 				      geneve->cfg.info.key.tp_dst, sport, NULL);
1165fc4099f1SPravin B Shelar 		if (IS_ERR(rt))
1166fc4099f1SPravin B Shelar 			return PTR_ERR(rt);
1167fc4099f1SPravin B Shelar 
1168fc4099f1SPravin B Shelar 		ip_rt_put(rt);
1169fc4099f1SPravin B Shelar 		info->key.u.ipv4.src = fl4.saddr;
1170b8812fa8SJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1171b8812fa8SJohn W. Linville 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
11729b4437a5Spravin shelar 		struct dst_entry *dst;
11739b4437a5Spravin shelar 		struct flowi6 fl6;
11749b4437a5Spravin shelar 
117534beb215SMark Gray 		struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
117634beb215SMark Gray 		sport = udp_flow_src_port(geneve->net, skb,
117734beb215SMark Gray 					  1, USHRT_MAX, true);
117834beb215SMark Gray 
117934beb215SMark Gray 		dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
118034beb215SMark Gray 					geneve->cfg.info.key.tp_dst, sport);
1181b8812fa8SJohn W. Linville 		if (IS_ERR(dst))
1182b8812fa8SJohn W. Linville 			return PTR_ERR(dst);
1183b8812fa8SJohn W. Linville 
1184b8812fa8SJohn W. Linville 		dst_release(dst);
1185b8812fa8SJohn W. Linville 		info->key.u.ipv6.src = fl6.saddr;
1186b8812fa8SJohn W. Linville #endif
1187b8812fa8SJohn W. Linville 	} else {
1188b8812fa8SJohn W. Linville 		return -EINVAL;
1189b8812fa8SJohn W. Linville 	}
1190b8812fa8SJohn W. Linville 
119134beb215SMark Gray 	info->key.tp_src = sport;
11929e06e859SSabrina Dubroca 	info->key.tp_dst = geneve->cfg.info.key.tp_dst;
1193fc4099f1SPravin B Shelar 	return 0;
1194fc4099f1SPravin B Shelar }
1195fc4099f1SPravin B Shelar 
11962d07dc79SJohn W. Linville static const struct net_device_ops geneve_netdev_ops = {
11972d07dc79SJohn W. Linville 	.ndo_init		= geneve_init,
11982d07dc79SJohn W. Linville 	.ndo_uninit		= geneve_uninit,
11992d07dc79SJohn W. Linville 	.ndo_open		= geneve_open,
12002d07dc79SJohn W. Linville 	.ndo_stop		= geneve_stop,
12012d07dc79SJohn W. Linville 	.ndo_start_xmit		= geneve_xmit,
1202b220a4a7SHeiner Kallweit 	.ndo_get_stats64	= dev_get_tstats64,
120355e5bfb5SDavid Wragg 	.ndo_change_mtu		= geneve_change_mtu,
12042d07dc79SJohn W. Linville 	.ndo_validate_addr	= eth_validate_addr,
12052d07dc79SJohn W. Linville 	.ndo_set_mac_address	= eth_mac_addr,
1206fc4099f1SPravin B Shelar 	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst,
12072d07dc79SJohn W. Linville };
12082d07dc79SJohn W. Linville 
geneve_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * drvinfo)12092d07dc79SJohn W. Linville static void geneve_get_drvinfo(struct net_device *dev,
12102d07dc79SJohn W. Linville 			       struct ethtool_drvinfo *drvinfo)
12112d07dc79SJohn W. Linville {
1212fb3ceec1SWolfram Sang 	strscpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
1213fb3ceec1SWolfram Sang 	strscpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
12142d07dc79SJohn W. Linville }
12152d07dc79SJohn W. Linville 
12162d07dc79SJohn W. Linville static const struct ethtool_ops geneve_ethtool_ops = {
12172d07dc79SJohn W. Linville 	.get_drvinfo	= geneve_get_drvinfo,
12182d07dc79SJohn W. Linville 	.get_link	= ethtool_op_get_link,
12192d07dc79SJohn W. Linville };
12202d07dc79SJohn W. Linville 
12212d07dc79SJohn W. Linville /* Info for udev, that this is a virtual tunnel endpoint */
12222d07dc79SJohn W. Linville static struct device_type geneve_type = {
12232d07dc79SJohn W. Linville 	.name = "geneve",
12242d07dc79SJohn W. Linville };
12252d07dc79SJohn W. Linville 
1226e5de25dcSSabrina Dubroca /* Calls the ndo_udp_tunnel_add of the caller in order to
122705ca4029SSinghai, Anjali  * supply the listening GENEVE udp ports. Callers are expected
1228e5de25dcSSabrina Dubroca  * to implement the ndo_udp_tunnel_add.
122905ca4029SSinghai, Anjali  */
geneve_offload_rx_ports(struct net_device * dev,bool push)12302d2b13fcSSabrina Dubroca static void geneve_offload_rx_ports(struct net_device *dev, bool push)
123105ca4029SSinghai, Anjali {
123205ca4029SSinghai, Anjali 	struct net *net = dev_net(dev);
123305ca4029SSinghai, Anjali 	struct geneve_net *gn = net_generic(net, geneve_net_id);
123405ca4029SSinghai, Anjali 	struct geneve_sock *gs;
1235681e683fSHannes Frederic Sowa 
123605ca4029SSinghai, Anjali 	rcu_read_lock();
12372d2b13fcSSabrina Dubroca 	list_for_each_entry_rcu(gs, &gn->sock_list, list) {
12382d2b13fcSSabrina Dubroca 		if (push) {
1239e7b3db5eSAlexander Duyck 			udp_tunnel_push_rx_port(dev, gs->sock,
1240e7b3db5eSAlexander Duyck 						UDP_TUNNEL_TYPE_GENEVE);
12412d2b13fcSSabrina Dubroca 		} else {
12422d2b13fcSSabrina Dubroca 			udp_tunnel_drop_rx_port(dev, gs->sock,
12432d2b13fcSSabrina Dubroca 						UDP_TUNNEL_TYPE_GENEVE);
12442d2b13fcSSabrina Dubroca 		}
12452d2b13fcSSabrina Dubroca 	}
124605ca4029SSinghai, Anjali 	rcu_read_unlock();
124705ca4029SSinghai, Anjali }
124805ca4029SSinghai, Anjali 
12492d07dc79SJohn W. Linville /* Initialize the device structure. */
geneve_setup(struct net_device * dev)12502d07dc79SJohn W. Linville static void geneve_setup(struct net_device *dev)
12512d07dc79SJohn W. Linville {
12522d07dc79SJohn W. Linville 	ether_setup(dev);
12532d07dc79SJohn W. Linville 
12542d07dc79SJohn W. Linville 	dev->netdev_ops = &geneve_netdev_ops;
12552d07dc79SJohn W. Linville 	dev->ethtool_ops = &geneve_ethtool_ops;
1256cf124db5SDavid S. Miller 	dev->needs_free_netdev = true;
12572d07dc79SJohn W. Linville 
12582d07dc79SJohn W. Linville 	SET_NETDEV_DEVTYPE(dev, &geneve_type);
12592d07dc79SJohn W. Linville 
12602d07dc79SJohn W. Linville 	dev->features    |= NETIF_F_LLTX;
126118423e1aSXin Long 	dev->features    |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_FRAGLIST;
12622d07dc79SJohn W. Linville 	dev->features    |= NETIF_F_RXCSUM;
12632d07dc79SJohn W. Linville 	dev->features    |= NETIF_F_GSO_SOFTWARE;
12642d07dc79SJohn W. Linville 
126518423e1aSXin Long 	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_FRAGLIST;
126618423e1aSXin Long 	dev->hw_features |= NETIF_F_RXCSUM;
12672d07dc79SJohn W. Linville 	dev->hw_features |= NETIF_F_GSO_SOFTWARE;
12682d07dc79SJohn W. Linville 
126991572088SJarod Wilson 	/* MTU range: 68 - (something less than 65535) */
127091572088SJarod Wilson 	dev->min_mtu = ETH_MIN_MTU;
127191572088SJarod Wilson 	/* The max_mtu calculation does not take account of GENEVE
127291572088SJarod Wilson 	 * options, to avoid excluding potentially valid
127391572088SJarod Wilson 	 * configurations. This will be further reduced by IPvX hdr size.
127491572088SJarod Wilson 	 */
127591572088SJarod Wilson 	dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
127691572088SJarod Wilson 
12772d07dc79SJohn W. Linville 	netif_keep_dst(dev);
1278fc41cdb3SJiri Benc 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1279ed961ac2SPhil Sutter 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
128087cd3dcaSPravin B Shelar 	eth_hw_addr_random(dev);
12812d07dc79SJohn W. Linville }
12822d07dc79SJohn W. Linville 
12832d07dc79SJohn W. Linville static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
128436c2e31aSEyal Birger 	[IFLA_GENEVE_UNSPEC]		= { .strict_start_type = IFLA_GENEVE_INNER_PROTO_INHERIT },
12852d07dc79SJohn W. Linville 	[IFLA_GENEVE_ID]		= { .type = NLA_U32 },
1286c593642cSPankaj Bharadiya 	[IFLA_GENEVE_REMOTE]		= { .len = sizeof_field(struct iphdr, daddr) },
12878ed66f0eSJohn W. Linville 	[IFLA_GENEVE_REMOTE6]		= { .len = sizeof(struct in6_addr) },
12888760ce58SJohn W. Linville 	[IFLA_GENEVE_TTL]		= { .type = NLA_U8 },
1289d8951125SJohn W. Linville 	[IFLA_GENEVE_TOS]		= { .type = NLA_U8 },
12908eb3b995SDaniel Borkmann 	[IFLA_GENEVE_LABEL]		= { .type = NLA_U32 },
1291cd7918b3SPravin B Shelar 	[IFLA_GENEVE_PORT]		= { .type = NLA_U16 },
1292e305ac6cSPravin B Shelar 	[IFLA_GENEVE_COLLECT_METADATA]	= { .type = NLA_FLAG },
1293abe492b4STom Herbert 	[IFLA_GENEVE_UDP_CSUM]		= { .type = NLA_U8 },
1294abe492b4STom Herbert 	[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]	= { .type = NLA_U8 },
1295abe492b4STom Herbert 	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
129652d0d404SHangbin Liu 	[IFLA_GENEVE_TTL_INHERIT]	= { .type = NLA_U8 },
1297a025fb5fSStefano Brivio 	[IFLA_GENEVE_DF]		= { .type = NLA_U8 },
129836c2e31aSEyal Birger 	[IFLA_GENEVE_INNER_PROTO_INHERIT]	= { .type = NLA_FLAG },
12992d07dc79SJohn W. Linville };
13002d07dc79SJohn W. Linville 
geneve_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1301a8b8a889SMatthias Schiffer static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
1302a8b8a889SMatthias Schiffer 			   struct netlink_ext_ack *extack)
13032d07dc79SJohn W. Linville {
13042d07dc79SJohn W. Linville 	if (tb[IFLA_ADDRESS]) {
1305c5ebc440SGirish Moodalbail 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
1306c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
1307c5ebc440SGirish Moodalbail 					    "Provided link layer address is not Ethernet");
13082d07dc79SJohn W. Linville 			return -EINVAL;
13092d07dc79SJohn W. Linville 		}
13102d07dc79SJohn W. Linville 
1311c5ebc440SGirish Moodalbail 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
1312c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
1313c5ebc440SGirish Moodalbail 					    "Provided Ethernet address is not unicast");
1314c5ebc440SGirish Moodalbail 			return -EADDRNOTAVAIL;
1315c5ebc440SGirish Moodalbail 		}
1316c5ebc440SGirish Moodalbail 	}
1317c5ebc440SGirish Moodalbail 
1318c5ebc440SGirish Moodalbail 	if (!data) {
1319c5ebc440SGirish Moodalbail 		NL_SET_ERR_MSG(extack,
1320c5ebc440SGirish Moodalbail 			       "Not enough attributes provided to perform the operation");
13212d07dc79SJohn W. Linville 		return -EINVAL;
1322c5ebc440SGirish Moodalbail 	}
13232d07dc79SJohn W. Linville 
13242d07dc79SJohn W. Linville 	if (data[IFLA_GENEVE_ID]) {
13252d07dc79SJohn W. Linville 		__u32 vni =  nla_get_u32(data[IFLA_GENEVE_ID]);
13262d07dc79SJohn W. Linville 
1327c5ebc440SGirish Moodalbail 		if (vni >= GENEVE_N_VID) {
1328c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID],
1329c5ebc440SGirish Moodalbail 					    "Geneve ID must be lower than 16777216");
13302d07dc79SJohn W. Linville 			return -ERANGE;
13312d07dc79SJohn W. Linville 		}
1332c5ebc440SGirish Moodalbail 	}
13332d07dc79SJohn W. Linville 
1334a025fb5fSStefano Brivio 	if (data[IFLA_GENEVE_DF]) {
1335a025fb5fSStefano Brivio 		enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
1336a025fb5fSStefano Brivio 
1337a025fb5fSStefano Brivio 		if (df < 0 || df > GENEVE_DF_MAX) {
13389a7b5b50SSabrina Dubroca 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_DF],
1339a025fb5fSStefano Brivio 					    "Invalid DF attribute");
1340a025fb5fSStefano Brivio 			return -EINVAL;
1341a025fb5fSStefano Brivio 		}
1342a025fb5fSStefano Brivio 	}
1343a025fb5fSStefano Brivio 
13442d07dc79SJohn W. Linville 	return 0;
13452d07dc79SJohn W. Linville }
13462d07dc79SJohn W. Linville 
geneve_find_dev(struct geneve_net * gn,const struct ip_tunnel_info * info,bool * tun_on_same_port,bool * tun_collect_md)1347371bd106SPravin B Shelar static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
13489b4437a5Spravin shelar 					  const struct ip_tunnel_info *info,
1349371bd106SPravin B Shelar 					  bool *tun_on_same_port,
1350371bd106SPravin B Shelar 					  bool *tun_collect_md)
1351371bd106SPravin B Shelar {
13529b4437a5Spravin shelar 	struct geneve_dev *geneve, *t = NULL;
1353371bd106SPravin B Shelar 
1354371bd106SPravin B Shelar 	*tun_on_same_port = false;
1355371bd106SPravin B Shelar 	*tun_collect_md = false;
1356371bd106SPravin B Shelar 	list_for_each_entry(geneve, &gn->geneve_list, next) {
13579e06e859SSabrina Dubroca 		if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) {
13589e06e859SSabrina Dubroca 			*tun_collect_md = geneve->cfg.collect_md;
1359371bd106SPravin B Shelar 			*tun_on_same_port = true;
1360371bd106SPravin B Shelar 		}
13619e06e859SSabrina Dubroca 		if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
13629e06e859SSabrina Dubroca 		    info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
13639e06e859SSabrina Dubroca 		    !memcmp(&info->key.u, &geneve->cfg.info.key.u, sizeof(info->key.u)))
1364371bd106SPravin B Shelar 			t = geneve;
1365371bd106SPravin B Shelar 	}
1366371bd106SPravin B Shelar 	return t;
1367371bd106SPravin B Shelar }
1368371bd106SPravin B Shelar 
is_tnl_info_zero(const struct ip_tunnel_info * info)13699b4437a5Spravin shelar static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
13709b4437a5Spravin shelar {
13713fa5f11dSStefano Brivio 	return !(info->key.tun_id || info->key.tun_flags || info->key.tos ||
13729b4437a5Spravin shelar 		 info->key.ttl || info->key.label || info->key.tp_src ||
13733fa5f11dSStefano Brivio 		 memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
13749b4437a5Spravin shelar }
13759b4437a5Spravin shelar 
geneve_dst_addr_equal(struct ip_tunnel_info * a,struct ip_tunnel_info * b)13765b861f6bSGirish Moodalbail static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
13775b861f6bSGirish Moodalbail 				  struct ip_tunnel_info *b)
13785b861f6bSGirish Moodalbail {
13795b861f6bSGirish Moodalbail 	if (ip_tunnel_info_af(a) == AF_INET)
13805b861f6bSGirish Moodalbail 		return a->key.u.ipv4.dst == b->key.u.ipv4.dst;
13815b861f6bSGirish Moodalbail 	else
13825b861f6bSGirish Moodalbail 		return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst);
13835b861f6bSGirish Moodalbail }
13845b861f6bSGirish Moodalbail 
geneve_configure(struct net * net,struct net_device * dev,struct netlink_ext_ack * extack,const struct geneve_config * cfg)1385e305ac6cSPravin B Shelar static int geneve_configure(struct net *net, struct net_device *dev,
1386c5ebc440SGirish Moodalbail 			    struct netlink_ext_ack *extack,
13879e06e859SSabrina Dubroca 			    const struct geneve_config *cfg)
13882d07dc79SJohn W. Linville {
13892d07dc79SJohn W. Linville 	struct geneve_net *gn = net_generic(net, geneve_net_id);
1390371bd106SPravin B Shelar 	struct geneve_dev *t, *geneve = netdev_priv(dev);
13919e06e859SSabrina Dubroca 	const struct ip_tunnel_info *info = &cfg->info;
1392371bd106SPravin B Shelar 	bool tun_collect_md, tun_on_same_port;
1393184fc8b5SPaolo Abeni 	int err, encap_len;
13942d07dc79SJohn W. Linville 
13959e06e859SSabrina Dubroca 	if (cfg->collect_md && !is_tnl_info_zero(info)) {
1396c5ebc440SGirish Moodalbail 		NL_SET_ERR_MSG(extack,
1397c5ebc440SGirish Moodalbail 			       "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified");
13988ed66f0eSJohn W. Linville 		return -EINVAL;
1399c5ebc440SGirish Moodalbail 	}
14002d07dc79SJohn W. Linville 
14012d07dc79SJohn W. Linville 	geneve->net = net;
14022d07dc79SJohn W. Linville 	geneve->dev = dev;
14032d07dc79SJohn W. Linville 
14049b4437a5Spravin shelar 	t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
1405371bd106SPravin B Shelar 	if (t)
1406371bd106SPravin B Shelar 		return -EBUSY;
1407371bd106SPravin B Shelar 
1408184fc8b5SPaolo Abeni 	/* make enough headroom for basic scenario */
1409184fc8b5SPaolo Abeni 	encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
14109e06e859SSabrina Dubroca 	if (!cfg->collect_md && ip_tunnel_info_af(info) == AF_INET) {
1411184fc8b5SPaolo Abeni 		encap_len += sizeof(struct iphdr);
141291572088SJarod Wilson 		dev->max_mtu -= sizeof(struct iphdr);
141391572088SJarod Wilson 	} else {
1414184fc8b5SPaolo Abeni 		encap_len += sizeof(struct ipv6hdr);
141591572088SJarod Wilson 		dev->max_mtu -= sizeof(struct ipv6hdr);
141691572088SJarod Wilson 	}
1417184fc8b5SPaolo Abeni 	dev->needed_headroom = encap_len + ETH_HLEN;
1418184fc8b5SPaolo Abeni 
14199e06e859SSabrina Dubroca 	if (cfg->collect_md) {
1420c5ebc440SGirish Moodalbail 		if (tun_on_same_port) {
1421c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG(extack,
1422c5ebc440SGirish Moodalbail 				       "There can be only one externally controlled device on a destination port");
1423371bd106SPravin B Shelar 			return -EPERM;
1424c5ebc440SGirish Moodalbail 		}
1425371bd106SPravin B Shelar 	} else {
1426c5ebc440SGirish Moodalbail 		if (tun_collect_md) {
1427c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG(extack,
1428c5ebc440SGirish Moodalbail 				       "There already exists an externally controlled device on this destination port");
1429371bd106SPravin B Shelar 			return -EPERM;
1430371bd106SPravin B Shelar 		}
1431c5ebc440SGirish Moodalbail 	}
1432371bd106SPravin B Shelar 
14339e06e859SSabrina Dubroca 	dst_cache_reset(&geneve->cfg.info.dst_cache);
14349e06e859SSabrina Dubroca 	memcpy(&geneve->cfg, cfg, sizeof(*cfg));
1435468dfffcSPaolo Abeni 
1436435fe1c0SEyal Birger 	if (geneve->cfg.inner_proto_inherit) {
1437435fe1c0SEyal Birger 		dev->header_ops = NULL;
1438435fe1c0SEyal Birger 		dev->type = ARPHRD_NONE;
1439435fe1c0SEyal Birger 		dev->hard_header_len = 0;
1440435fe1c0SEyal Birger 		dev->addr_len = 0;
144145ef71d1SJosef Miegl 		dev->flags = IFF_POINTOPOINT | IFF_NOARP;
1442435fe1c0SEyal Birger 	}
1443435fe1c0SEyal Birger 
14442d07dc79SJohn W. Linville 	err = register_netdevice(dev);
14452d07dc79SJohn W. Linville 	if (err)
14462d07dc79SJohn W. Linville 		return err;
14472d07dc79SJohn W. Linville 
14482d07dc79SJohn W. Linville 	list_add(&geneve->next, &gn->geneve_list);
14492d07dc79SJohn W. Linville 	return 0;
14502d07dc79SJohn W. Linville }
14512d07dc79SJohn W. Linville 
init_tnl_info(struct ip_tunnel_info * info,__u16 dst_port)14529b4437a5Spravin shelar static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
14539b4437a5Spravin shelar {
14549b4437a5Spravin shelar 	memset(info, 0, sizeof(*info));
14559b4437a5Spravin shelar 	info->key.tp_dst = htons(dst_port);
14569b4437a5Spravin shelar }
14579b4437a5Spravin shelar 
geneve_nl2info(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack,struct geneve_config * cfg,bool changelink)1458c5ebc440SGirish Moodalbail static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
1459c5ebc440SGirish Moodalbail 			  struct netlink_ext_ack *extack,
14609e06e859SSabrina Dubroca 			  struct geneve_config *cfg, bool changelink)
1461e305ac6cSPravin B Shelar {
14629e06e859SSabrina Dubroca 	struct ip_tunnel_info *info = &cfg->info;
1463c5ebc440SGirish Moodalbail 	int attrtype;
1464c5ebc440SGirish Moodalbail 
1465c5ebc440SGirish Moodalbail 	if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
1466c5ebc440SGirish Moodalbail 		NL_SET_ERR_MSG(extack,
1467c5ebc440SGirish Moodalbail 			       "Cannot specify both IPv4 and IPv6 Remote addresses");
14688ed66f0eSJohn W. Linville 		return -EINVAL;
1469c5ebc440SGirish Moodalbail 	}
14708ed66f0eSJohn W. Linville 
14718ed66f0eSJohn W. Linville 	if (data[IFLA_GENEVE_REMOTE]) {
1472c5ebc440SGirish Moodalbail 		if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
1473c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_REMOTE;
1474c5ebc440SGirish Moodalbail 			goto change_notsup;
1475c5ebc440SGirish Moodalbail 		}
14765b861f6bSGirish Moodalbail 
14775b861f6bSGirish Moodalbail 		info->key.u.ipv4.dst =
14788ed66f0eSJohn W. Linville 			nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
14798ed66f0eSJohn W. Linville 
1480842841ecSDave Taht 		if (ipv4_is_multicast(info->key.u.ipv4.dst)) {
1481c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE],
1482c5ebc440SGirish Moodalbail 					    "Remote IPv4 address cannot be Multicast");
14838ed66f0eSJohn W. Linville 			return -EINVAL;
14848ed66f0eSJohn W. Linville 		}
14858ed66f0eSJohn W. Linville 	}
14868ed66f0eSJohn W. Linville 
14879b4437a5Spravin shelar 	if (data[IFLA_GENEVE_REMOTE6]) {
14889b4437a5Spravin shelar #if IS_ENABLED(CONFIG_IPV6)
1489c5ebc440SGirish Moodalbail 		if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
1490c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_REMOTE6;
1491c5ebc440SGirish Moodalbail 			goto change_notsup;
1492c5ebc440SGirish Moodalbail 		}
14935b861f6bSGirish Moodalbail 
14945b861f6bSGirish Moodalbail 		info->mode = IP_TUNNEL_INFO_IPV6;
14955b861f6bSGirish Moodalbail 		info->key.u.ipv6.dst =
14969b4437a5Spravin shelar 			nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
1497e277de5fSJesse Gross 
14985b861f6bSGirish Moodalbail 		if (ipv6_addr_type(&info->key.u.ipv6.dst) &
14999b4437a5Spravin shelar 		    IPV6_ADDR_LINKLOCAL) {
1500c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1501c5ebc440SGirish Moodalbail 					    "Remote IPv6 address cannot be link-local");
15029b4437a5Spravin shelar 			return -EINVAL;
15039b4437a5Spravin shelar 		}
15045b861f6bSGirish Moodalbail 		if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
1505c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1506c5ebc440SGirish Moodalbail 					    "Remote IPv6 address cannot be Multicast");
15079b4437a5Spravin shelar 			return -EINVAL;
15089b4437a5Spravin shelar 		}
15095b861f6bSGirish Moodalbail 		info->key.tun_flags |= TUNNEL_CSUM;
15109e06e859SSabrina Dubroca 		cfg->use_udp6_rx_checksums = true;
15119b4437a5Spravin shelar #else
1512c5ebc440SGirish Moodalbail 		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1513c5ebc440SGirish Moodalbail 				    "IPv6 support not enabled in the kernel");
15149b4437a5Spravin shelar 		return -EPFNOSUPPORT;
15159b4437a5Spravin shelar #endif
15169b4437a5Spravin shelar 	}
15179b4437a5Spravin shelar 
15189b4437a5Spravin shelar 	if (data[IFLA_GENEVE_ID]) {
15199b4437a5Spravin shelar 		__u32 vni;
15209b4437a5Spravin shelar 		__u8 tvni[3];
15215b861f6bSGirish Moodalbail 		__be64 tunid;
15229b4437a5Spravin shelar 
15239b4437a5Spravin shelar 		vni = nla_get_u32(data[IFLA_GENEVE_ID]);
15249b4437a5Spravin shelar 		tvni[0] = (vni & 0x00ff0000) >> 16;
15259b4437a5Spravin shelar 		tvni[1] = (vni & 0x0000ff00) >> 8;
15269b4437a5Spravin shelar 		tvni[2] =  vni & 0x000000ff;
15279b4437a5Spravin shelar 
15285b861f6bSGirish Moodalbail 		tunid = vni_to_tunnel_id(tvni);
1529c5ebc440SGirish Moodalbail 		if (changelink && (tunid != info->key.tun_id)) {
1530c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_ID;
1531c5ebc440SGirish Moodalbail 			goto change_notsup;
1532c5ebc440SGirish Moodalbail 		}
15335b861f6bSGirish Moodalbail 		info->key.tun_id = tunid;
15349b4437a5Spravin shelar 	}
15355b861f6bSGirish Moodalbail 
1536a97d97baSHangbin Liu 	if (data[IFLA_GENEVE_TTL_INHERIT]) {
1537a97d97baSHangbin Liu 		if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT]))
15389e06e859SSabrina Dubroca 			cfg->ttl_inherit = true;
1539a97d97baSHangbin Liu 		else
15409e06e859SSabrina Dubroca 			cfg->ttl_inherit = false;
1541a97d97baSHangbin Liu 	} else if (data[IFLA_GENEVE_TTL]) {
1542a97d97baSHangbin Liu 		info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
15439e06e859SSabrina Dubroca 		cfg->ttl_inherit = false;
1544a97d97baSHangbin Liu 	}
154552d0d404SHangbin Liu 
1546e305ac6cSPravin B Shelar 	if (data[IFLA_GENEVE_TOS])
15475b861f6bSGirish Moodalbail 		info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
1548e305ac6cSPravin B Shelar 
1549a025fb5fSStefano Brivio 	if (data[IFLA_GENEVE_DF])
15509e06e859SSabrina Dubroca 		cfg->df = nla_get_u8(data[IFLA_GENEVE_DF]);
1551a025fb5fSStefano Brivio 
15529b4437a5Spravin shelar 	if (data[IFLA_GENEVE_LABEL]) {
15535b861f6bSGirish Moodalbail 		info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
15548eb3b995SDaniel Borkmann 				  IPV6_FLOWLABEL_MASK;
1555c5ebc440SGirish Moodalbail 		if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) {
1556c5ebc440SGirish Moodalbail 			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL],
1557c5ebc440SGirish Moodalbail 					    "Label attribute only applies for IPv6 Geneve devices");
15589b4437a5Spravin shelar 			return -EINVAL;
15599b4437a5Spravin shelar 		}
1560c5ebc440SGirish Moodalbail 	}
15618eb3b995SDaniel Borkmann 
15625b861f6bSGirish Moodalbail 	if (data[IFLA_GENEVE_PORT]) {
1563c5ebc440SGirish Moodalbail 		if (changelink) {
1564c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_PORT;
1565c5ebc440SGirish Moodalbail 			goto change_notsup;
1566c5ebc440SGirish Moodalbail 		}
15675b861f6bSGirish Moodalbail 		info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
15685b861f6bSGirish Moodalbail 	}
1569e305ac6cSPravin B Shelar 
15705b861f6bSGirish Moodalbail 	if (data[IFLA_GENEVE_COLLECT_METADATA]) {
1571c5ebc440SGirish Moodalbail 		if (changelink) {
1572c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_COLLECT_METADATA;
1573c5ebc440SGirish Moodalbail 			goto change_notsup;
1574c5ebc440SGirish Moodalbail 		}
15759e06e859SSabrina Dubroca 		cfg->collect_md = true;
15765b861f6bSGirish Moodalbail 	}
1577e305ac6cSPravin B Shelar 
15785b861f6bSGirish Moodalbail 	if (data[IFLA_GENEVE_UDP_CSUM]) {
1579c5ebc440SGirish Moodalbail 		if (changelink) {
1580c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_UDP_CSUM;
1581c5ebc440SGirish Moodalbail 			goto change_notsup;
1582c5ebc440SGirish Moodalbail 		}
15835b861f6bSGirish Moodalbail 		if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
15845b861f6bSGirish Moodalbail 			info->key.tun_flags |= TUNNEL_CSUM;
15855b861f6bSGirish Moodalbail 	}
1586abe492b4STom Herbert 
15875b861f6bSGirish Moodalbail 	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
1588f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1589c5ebc440SGirish Moodalbail 		if (changelink) {
1590c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX;
1591c5ebc440SGirish Moodalbail 			goto change_notsup;
1592c5ebc440SGirish Moodalbail 		}
15935b861f6bSGirish Moodalbail 		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
15945b861f6bSGirish Moodalbail 			info->key.tun_flags &= ~TUNNEL_CSUM;
1595f9094b76SHangbin Liu #else
1596f9094b76SHangbin Liu 		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX],
1597f9094b76SHangbin Liu 				    "IPv6 support not enabled in the kernel");
1598f9094b76SHangbin Liu 		return -EPFNOSUPPORT;
1599f9094b76SHangbin Liu #endif
16005b861f6bSGirish Moodalbail 	}
1601abe492b4STom Herbert 
16025b861f6bSGirish Moodalbail 	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
1603f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1604c5ebc440SGirish Moodalbail 		if (changelink) {
1605c5ebc440SGirish Moodalbail 			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX;
1606c5ebc440SGirish Moodalbail 			goto change_notsup;
1607c5ebc440SGirish Moodalbail 		}
16085b861f6bSGirish Moodalbail 		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
16099e06e859SSabrina Dubroca 			cfg->use_udp6_rx_checksums = false;
1610f9094b76SHangbin Liu #else
1611f9094b76SHangbin Liu 		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX],
1612f9094b76SHangbin Liu 				    "IPv6 support not enabled in the kernel");
1613f9094b76SHangbin Liu 		return -EPFNOSUPPORT;
1614f9094b76SHangbin Liu #endif
16155b861f6bSGirish Moodalbail 	}
16165b861f6bSGirish Moodalbail 
1617435fe1c0SEyal Birger 	if (data[IFLA_GENEVE_INNER_PROTO_INHERIT]) {
1618435fe1c0SEyal Birger 		if (changelink) {
1619435fe1c0SEyal Birger 			attrtype = IFLA_GENEVE_INNER_PROTO_INHERIT;
1620435fe1c0SEyal Birger 			goto change_notsup;
1621435fe1c0SEyal Birger 		}
1622435fe1c0SEyal Birger 		cfg->inner_proto_inherit = true;
1623435fe1c0SEyal Birger 	}
1624435fe1c0SEyal Birger 
16255b861f6bSGirish Moodalbail 	return 0;
1626c5ebc440SGirish Moodalbail change_notsup:
1627c5ebc440SGirish Moodalbail 	NL_SET_ERR_MSG_ATTR(extack, data[attrtype],
1628435fe1c0SEyal Birger 			    "Changing VNI, Port, endpoint IP address family, external, inner_proto_inherit, and UDP checksum attributes are not supported");
1629c5ebc440SGirish Moodalbail 	return -EOPNOTSUPP;
16305b861f6bSGirish Moodalbail }
16315b861f6bSGirish Moodalbail 
geneve_link_config(struct net_device * dev,struct ip_tunnel_info * info,struct nlattr * tb[])1632c40e89fdSAlexey Kodanev static void geneve_link_config(struct net_device *dev,
1633c40e89fdSAlexey Kodanev 			       struct ip_tunnel_info *info, struct nlattr *tb[])
1634c40e89fdSAlexey Kodanev {
1635c40e89fdSAlexey Kodanev 	struct geneve_dev *geneve = netdev_priv(dev);
1636c40e89fdSAlexey Kodanev 	int ldev_mtu = 0;
1637c40e89fdSAlexey Kodanev 
1638c40e89fdSAlexey Kodanev 	if (tb[IFLA_MTU]) {
1639c40e89fdSAlexey Kodanev 		geneve_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
1640c40e89fdSAlexey Kodanev 		return;
1641c40e89fdSAlexey Kodanev 	}
1642c40e89fdSAlexey Kodanev 
1643c40e89fdSAlexey Kodanev 	switch (ip_tunnel_info_af(info)) {
1644c40e89fdSAlexey Kodanev 	case AF_INET: {
1645c40e89fdSAlexey Kodanev 		struct flowi4 fl4 = { .daddr = info->key.u.ipv4.dst };
1646c40e89fdSAlexey Kodanev 		struct rtable *rt = ip_route_output_key(geneve->net, &fl4);
1647c40e89fdSAlexey Kodanev 
1648c40e89fdSAlexey Kodanev 		if (!IS_ERR(rt) && rt->dst.dev) {
1649c40e89fdSAlexey Kodanev 			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV4_HLEN;
1650c40e89fdSAlexey Kodanev 			ip_rt_put(rt);
1651c40e89fdSAlexey Kodanev 		}
1652c40e89fdSAlexey Kodanev 		break;
1653c40e89fdSAlexey Kodanev 	}
1654c40e89fdSAlexey Kodanev #if IS_ENABLED(CONFIG_IPV6)
1655c40e89fdSAlexey Kodanev 	case AF_INET6: {
1656c0a47e44SHangbin Liu 		struct rt6_info *rt;
1657c0a47e44SHangbin Liu 
1658c0a47e44SHangbin Liu 		if (!__in6_dev_get(dev))
1659c0a47e44SHangbin Liu 			break;
1660c0a47e44SHangbin Liu 
1661c0a47e44SHangbin Liu 		rt = rt6_lookup(geneve->net, &info->key.u.ipv6.dst, NULL, 0,
1662c40e89fdSAlexey Kodanev 				NULL, 0);
1663c40e89fdSAlexey Kodanev 
1664c40e89fdSAlexey Kodanev 		if (rt && rt->dst.dev)
1665c40e89fdSAlexey Kodanev 			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV6_HLEN;
1666c40e89fdSAlexey Kodanev 		ip6_rt_put(rt);
1667c40e89fdSAlexey Kodanev 		break;
1668c40e89fdSAlexey Kodanev 	}
1669c40e89fdSAlexey Kodanev #endif
1670c40e89fdSAlexey Kodanev 	}
1671c40e89fdSAlexey Kodanev 
1672c40e89fdSAlexey Kodanev 	if (ldev_mtu <= 0)
1673c40e89fdSAlexey Kodanev 		return;
1674c40e89fdSAlexey Kodanev 
1675c40e89fdSAlexey Kodanev 	geneve_change_mtu(dev, ldev_mtu - info->options_len);
1676c40e89fdSAlexey Kodanev }
1677c40e89fdSAlexey Kodanev 
geneve_newlink(struct net * net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)16785b861f6bSGirish Moodalbail static int geneve_newlink(struct net *net, struct net_device *dev,
16795b861f6bSGirish Moodalbail 			  struct nlattr *tb[], struct nlattr *data[],
16805b861f6bSGirish Moodalbail 			  struct netlink_ext_ack *extack)
16815b861f6bSGirish Moodalbail {
16829e06e859SSabrina Dubroca 	struct geneve_config cfg = {
16839e06e859SSabrina Dubroca 		.df = GENEVE_DF_UNSET,
16849e06e859SSabrina Dubroca 		.use_udp6_rx_checksums = false,
16859e06e859SSabrina Dubroca 		.ttl_inherit = false,
16869e06e859SSabrina Dubroca 		.collect_md = false,
16879e06e859SSabrina Dubroca 	};
16885b861f6bSGirish Moodalbail 	int err;
16895b861f6bSGirish Moodalbail 
16909e06e859SSabrina Dubroca 	init_tnl_info(&cfg.info, GENEVE_UDP_PORT);
16919e06e859SSabrina Dubroca 	err = geneve_nl2info(tb, data, extack, &cfg, false);
16925b861f6bSGirish Moodalbail 	if (err)
16935b861f6bSGirish Moodalbail 		return err;
1694abe492b4STom Herbert 
16959e06e859SSabrina Dubroca 	err = geneve_configure(net, dev, extack, &cfg);
1696c40e89fdSAlexey Kodanev 	if (err)
1697c40e89fdSAlexey Kodanev 		return err;
1698c40e89fdSAlexey Kodanev 
16999e06e859SSabrina Dubroca 	geneve_link_config(dev, &cfg.info, tb);
1700c40e89fdSAlexey Kodanev 
1701c40e89fdSAlexey Kodanev 	return 0;
1702e305ac6cSPravin B Shelar }
1703e305ac6cSPravin B Shelar 
17045b861f6bSGirish Moodalbail /* Quiesces the geneve device data path for both TX and RX.
17055b861f6bSGirish Moodalbail  *
17065b861f6bSGirish Moodalbail  * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
17075b861f6bSGirish Moodalbail  * So, if we set that socket to NULL under RCU and wait for synchronize_net()
17085b861f6bSGirish Moodalbail  * to complete for the existing set of in-flight packets to be transmitted,
17095b861f6bSGirish Moodalbail  * then we would have quiesced the transmit data path. All the future packets
17105b861f6bSGirish Moodalbail  * will get dropped until we unquiesce the data path.
17115b861f6bSGirish Moodalbail  *
17125b861f6bSGirish Moodalbail  * On receive geneve dereference the geneve_sock stashed in the socket. So,
17135b861f6bSGirish Moodalbail  * if we set that to NULL under RCU and wait for synchronize_net() to
17145b861f6bSGirish Moodalbail  * complete, then we would have quiesced the receive data path.
17155b861f6bSGirish Moodalbail  */
geneve_quiesce(struct geneve_dev * geneve,struct geneve_sock ** gs4,struct geneve_sock ** gs6)17165b861f6bSGirish Moodalbail static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
17175b861f6bSGirish Moodalbail 			   struct geneve_sock **gs6)
17185b861f6bSGirish Moodalbail {
17195b861f6bSGirish Moodalbail 	*gs4 = rtnl_dereference(geneve->sock4);
17205b861f6bSGirish Moodalbail 	rcu_assign_pointer(geneve->sock4, NULL);
17215b861f6bSGirish Moodalbail 	if (*gs4)
17225b861f6bSGirish Moodalbail 		rcu_assign_sk_user_data((*gs4)->sock->sk, NULL);
17235b861f6bSGirish Moodalbail #if IS_ENABLED(CONFIG_IPV6)
17245b861f6bSGirish Moodalbail 	*gs6 = rtnl_dereference(geneve->sock6);
17255b861f6bSGirish Moodalbail 	rcu_assign_pointer(geneve->sock6, NULL);
17265b861f6bSGirish Moodalbail 	if (*gs6)
17275b861f6bSGirish Moodalbail 		rcu_assign_sk_user_data((*gs6)->sock->sk, NULL);
17285b861f6bSGirish Moodalbail #else
17295b861f6bSGirish Moodalbail 	*gs6 = NULL;
17305b861f6bSGirish Moodalbail #endif
17315b861f6bSGirish Moodalbail 	synchronize_net();
17325b861f6bSGirish Moodalbail }
17335b861f6bSGirish Moodalbail 
17345b861f6bSGirish Moodalbail /* Resumes the geneve device data path for both TX and RX. */
geneve_unquiesce(struct geneve_dev * geneve,struct geneve_sock * gs4,struct geneve_sock __maybe_unused * gs6)17355b861f6bSGirish Moodalbail static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
17365b861f6bSGirish Moodalbail 			     struct geneve_sock __maybe_unused *gs6)
17375b861f6bSGirish Moodalbail {
17385b861f6bSGirish Moodalbail 	rcu_assign_pointer(geneve->sock4, gs4);
17395b861f6bSGirish Moodalbail 	if (gs4)
17405b861f6bSGirish Moodalbail 		rcu_assign_sk_user_data(gs4->sock->sk, gs4);
17415b861f6bSGirish Moodalbail #if IS_ENABLED(CONFIG_IPV6)
17425b861f6bSGirish Moodalbail 	rcu_assign_pointer(geneve->sock6, gs6);
17435b861f6bSGirish Moodalbail 	if (gs6)
17445b861f6bSGirish Moodalbail 		rcu_assign_sk_user_data(gs6->sock->sk, gs6);
17455b861f6bSGirish Moodalbail #endif
17465b861f6bSGirish Moodalbail 	synchronize_net();
17475b861f6bSGirish Moodalbail }
17485b861f6bSGirish Moodalbail 
geneve_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)17495b861f6bSGirish Moodalbail static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
17505b861f6bSGirish Moodalbail 			     struct nlattr *data[],
17515b861f6bSGirish Moodalbail 			     struct netlink_ext_ack *extack)
17525b861f6bSGirish Moodalbail {
17535b861f6bSGirish Moodalbail 	struct geneve_dev *geneve = netdev_priv(dev);
17545b861f6bSGirish Moodalbail 	struct geneve_sock *gs4, *gs6;
17559e06e859SSabrina Dubroca 	struct geneve_config cfg;
17565b861f6bSGirish Moodalbail 	int err;
17575b861f6bSGirish Moodalbail 
17585b861f6bSGirish Moodalbail 	/* If the geneve device is configured for metadata (or externally
17595b861f6bSGirish Moodalbail 	 * controlled, for example, OVS), then nothing can be changed.
17605b861f6bSGirish Moodalbail 	 */
17619e06e859SSabrina Dubroca 	if (geneve->cfg.collect_md)
17625b861f6bSGirish Moodalbail 		return -EOPNOTSUPP;
17635b861f6bSGirish Moodalbail 
17645b861f6bSGirish Moodalbail 	/* Start with the existing info. */
17659e06e859SSabrina Dubroca 	memcpy(&cfg, &geneve->cfg, sizeof(cfg));
17669e06e859SSabrina Dubroca 	err = geneve_nl2info(tb, data, extack, &cfg, true);
17675b861f6bSGirish Moodalbail 	if (err)
17685b861f6bSGirish Moodalbail 		return err;
17695b861f6bSGirish Moodalbail 
17709e06e859SSabrina Dubroca 	if (!geneve_dst_addr_equal(&geneve->cfg.info, &cfg.info)) {
17719e06e859SSabrina Dubroca 		dst_cache_reset(&cfg.info.dst_cache);
17729e06e859SSabrina Dubroca 		geneve_link_config(dev, &cfg.info, tb);
1773c40e89fdSAlexey Kodanev 	}
17745b861f6bSGirish Moodalbail 
17755b861f6bSGirish Moodalbail 	geneve_quiesce(geneve, &gs4, &gs6);
17769e06e859SSabrina Dubroca 	memcpy(&geneve->cfg, &cfg, sizeof(cfg));
17775b861f6bSGirish Moodalbail 	geneve_unquiesce(geneve, gs4, gs6);
17785b861f6bSGirish Moodalbail 
17795b861f6bSGirish Moodalbail 	return 0;
17805b861f6bSGirish Moodalbail }
17815b861f6bSGirish Moodalbail 
geneve_dellink(struct net_device * dev,struct list_head * head)17822d07dc79SJohn W. Linville static void geneve_dellink(struct net_device *dev, struct list_head *head)
17832d07dc79SJohn W. Linville {
17842d07dc79SJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
17852d07dc79SJohn W. Linville 
17862d07dc79SJohn W. Linville 	list_del(&geneve->next);
17872d07dc79SJohn W. Linville 	unregister_netdevice_queue(dev, head);
17882d07dc79SJohn W. Linville }
17892d07dc79SJohn W. Linville 
geneve_get_size(const struct net_device * dev)17902d07dc79SJohn W. Linville static size_t geneve_get_size(const struct net_device *dev)
17912d07dc79SJohn W. Linville {
17922d07dc79SJohn W. Linville 	return nla_total_size(sizeof(__u32)) +	/* IFLA_GENEVE_ID */
17938ed66f0eSJohn W. Linville 		nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
17948760ce58SJohn W. Linville 		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */
1795d8951125SJohn W. Linville 		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
1796a025fb5fSStefano Brivio 		nla_total_size(sizeof(__u8)) +	/* IFLA_GENEVE_DF */
17978eb3b995SDaniel Borkmann 		nla_total_size(sizeof(__be32)) +  /* IFLA_GENEVE_LABEL */
17987bbe33ffSJohn W. Linville 		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
1799e305ac6cSPravin B Shelar 		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */
1800abe492b4STom Herbert 		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
1801abe492b4STom Herbert 		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
1802abe492b4STom Herbert 		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
180352d0d404SHangbin Liu 		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */
180436c2e31aSEyal Birger 		nla_total_size(0) +	 /* IFLA_GENEVE_INNER_PROTO_INHERIT */
18052d07dc79SJohn W. Linville 		0;
18062d07dc79SJohn W. Linville }
18072d07dc79SJohn W. Linville 
geneve_fill_info(struct sk_buff * skb,const struct net_device * dev)18082d07dc79SJohn W. Linville static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
18092d07dc79SJohn W. Linville {
18102d07dc79SJohn W. Linville 	struct geneve_dev *geneve = netdev_priv(dev);
18119e06e859SSabrina Dubroca 	struct ip_tunnel_info *info = &geneve->cfg.info;
18129e06e859SSabrina Dubroca 	bool ttl_inherit = geneve->cfg.ttl_inherit;
18139e06e859SSabrina Dubroca 	bool metadata = geneve->cfg.collect_md;
18149b4437a5Spravin shelar 	__u8 tmp_vni[3];
18152d07dc79SJohn W. Linville 	__u32 vni;
18162d07dc79SJohn W. Linville 
18179b4437a5Spravin shelar 	tunnel_id_to_vni(info->key.tun_id, tmp_vni);
18189b4437a5Spravin shelar 	vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2];
18192d07dc79SJohn W. Linville 	if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
18202d07dc79SJohn W. Linville 		goto nla_put_failure;
18212d07dc79SJohn W. Linville 
1822fd7eafd0SHangbin Liu 	if (!metadata && ip_tunnel_info_af(info) == AF_INET) {
18232d07dc79SJohn W. Linville 		if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
18249b4437a5Spravin shelar 				    info->key.u.ipv4.dst))
18252d07dc79SJohn W. Linville 			goto nla_put_failure;
18269b4437a5Spravin shelar 		if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
18279b4437a5Spravin shelar 			       !!(info->key.tun_flags & TUNNEL_CSUM)))
18289b4437a5Spravin shelar 			goto nla_put_failure;
18299b4437a5Spravin shelar 
18308ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1831fd7eafd0SHangbin Liu 	} else if (!metadata) {
18328ed66f0eSJohn W. Linville 		if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
18339b4437a5Spravin shelar 				     &info->key.u.ipv6.dst))
18349b4437a5Spravin shelar 			goto nla_put_failure;
18359b4437a5Spravin shelar 		if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
18369b4437a5Spravin shelar 			       !(info->key.tun_flags & TUNNEL_CSUM)))
18379b4437a5Spravin shelar 			goto nla_put_failure;
183811387fe4SEric Garver #endif
1839fd7eafd0SHangbin Liu 	}
18402d07dc79SJohn W. Linville 
18419b4437a5Spravin shelar 	if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
18429b4437a5Spravin shelar 	    nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
18439b4437a5Spravin shelar 	    nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
18448760ce58SJohn W. Linville 		goto nla_put_failure;
18458760ce58SJohn W. Linville 
18469e06e859SSabrina Dubroca 	if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->cfg.df))
1847a025fb5fSStefano Brivio 		goto nla_put_failure;
1848a025fb5fSStefano Brivio 
18499b4437a5Spravin shelar 	if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
1850cd7918b3SPravin B Shelar 		goto nla_put_failure;
1851cd7918b3SPravin B Shelar 
1852fd7eafd0SHangbin Liu 	if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA))
1853e305ac6cSPravin B Shelar 		goto nla_put_failure;
1854fd7eafd0SHangbin Liu 
1855f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1856fd7eafd0SHangbin Liu 	if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
18579e06e859SSabrina Dubroca 		       !geneve->cfg.use_udp6_rx_checksums))
1858fd7eafd0SHangbin Liu 		goto nla_put_failure;
1859f9094b76SHangbin Liu #endif
1860fd7eafd0SHangbin Liu 
186152d0d404SHangbin Liu 	if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
186252d0d404SHangbin Liu 		goto nla_put_failure;
186352d0d404SHangbin Liu 
1864435fe1c0SEyal Birger 	if (geneve->cfg.inner_proto_inherit &&
1865435fe1c0SEyal Birger 	    nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT))
1866435fe1c0SEyal Birger 		goto nla_put_failure;
1867435fe1c0SEyal Birger 
18682d07dc79SJohn W. Linville 	return 0;
18692d07dc79SJohn W. Linville 
18702d07dc79SJohn W. Linville nla_put_failure:
18712d07dc79SJohn W. Linville 	return -EMSGSIZE;
18722d07dc79SJohn W. Linville }
18732d07dc79SJohn W. Linville 
18742d07dc79SJohn W. Linville static struct rtnl_link_ops geneve_link_ops __read_mostly = {
18752d07dc79SJohn W. Linville 	.kind		= "geneve",
18762d07dc79SJohn W. Linville 	.maxtype	= IFLA_GENEVE_MAX,
18772d07dc79SJohn W. Linville 	.policy		= geneve_policy,
18782d07dc79SJohn W. Linville 	.priv_size	= sizeof(struct geneve_dev),
18792d07dc79SJohn W. Linville 	.setup		= geneve_setup,
18802d07dc79SJohn W. Linville 	.validate	= geneve_validate,
18812d07dc79SJohn W. Linville 	.newlink	= geneve_newlink,
18825b861f6bSGirish Moodalbail 	.changelink	= geneve_changelink,
18832d07dc79SJohn W. Linville 	.dellink	= geneve_dellink,
18842d07dc79SJohn W. Linville 	.get_size	= geneve_get_size,
18852d07dc79SJohn W. Linville 	.fill_info	= geneve_fill_info,
18862d07dc79SJohn W. Linville };
18872d07dc79SJohn W. Linville 
geneve_dev_create_fb(struct net * net,const char * name,u8 name_assign_type,u16 dst_port)1888e305ac6cSPravin B Shelar struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
1889e305ac6cSPravin B Shelar 					u8 name_assign_type, u16 dst_port)
1890e305ac6cSPravin B Shelar {
1891e305ac6cSPravin B Shelar 	struct nlattr *tb[IFLA_MAX + 1];
1892e305ac6cSPravin B Shelar 	struct net_device *dev;
1893106da663SNicolas Dichtel 	LIST_HEAD(list_kill);
1894e305ac6cSPravin B Shelar 	int err;
18959e06e859SSabrina Dubroca 	struct geneve_config cfg = {
18969e06e859SSabrina Dubroca 		.df = GENEVE_DF_UNSET,
18979e06e859SSabrina Dubroca 		.use_udp6_rx_checksums = true,
18989e06e859SSabrina Dubroca 		.ttl_inherit = false,
18999e06e859SSabrina Dubroca 		.collect_md = true,
19009e06e859SSabrina Dubroca 	};
1901e305ac6cSPravin B Shelar 
1902e305ac6cSPravin B Shelar 	memset(tb, 0, sizeof(tb));
1903e305ac6cSPravin B Shelar 	dev = rtnl_create_link(net, name, name_assign_type,
1904d0522f1cSDavid Ahern 			       &geneve_link_ops, tb, NULL);
1905e305ac6cSPravin B Shelar 	if (IS_ERR(dev))
1906e305ac6cSPravin B Shelar 		return dev;
1907e305ac6cSPravin B Shelar 
19089e06e859SSabrina Dubroca 	init_tnl_info(&cfg.info, dst_port);
19099e06e859SSabrina Dubroca 	err = geneve_configure(net, dev, NULL, &cfg);
1910106da663SNicolas Dichtel 	if (err) {
1911106da663SNicolas Dichtel 		free_netdev(dev);
1912106da663SNicolas Dichtel 		return ERR_PTR(err);
1913106da663SNicolas Dichtel 	}
19147e059158SDavid Wragg 
19157e059158SDavid Wragg 	/* openvswitch users expect packet sizes to be unrestricted,
19167e059158SDavid Wragg 	 * so set the largest MTU we can.
19177e059158SDavid Wragg 	 */
191891572088SJarod Wilson 	err = geneve_change_mtu(dev, IP_MAX_MTU);
19197e059158SDavid Wragg 	if (err)
19207e059158SDavid Wragg 		goto err;
19217e059158SDavid Wragg 
19221d997f10SHangbin Liu 	err = rtnl_configure_link(dev, NULL, 0, NULL);
192341009481SNicolas Dichtel 	if (err < 0)
192441009481SNicolas Dichtel 		goto err;
192541009481SNicolas Dichtel 
19267e059158SDavid Wragg 	return dev;
19277e059158SDavid Wragg err:
1928106da663SNicolas Dichtel 	geneve_dellink(dev, &list_kill);
1929106da663SNicolas Dichtel 	unregister_netdevice_many(&list_kill);
1930e305ac6cSPravin B Shelar 	return ERR_PTR(err);
1931e305ac6cSPravin B Shelar }
1932e305ac6cSPravin B Shelar EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
1933e305ac6cSPravin B Shelar 
geneve_netdevice_event(struct notifier_block * unused,unsigned long event,void * ptr)1934681e683fSHannes Frederic Sowa static int geneve_netdevice_event(struct notifier_block *unused,
1935681e683fSHannes Frederic Sowa 				  unsigned long event, void *ptr)
1936681e683fSHannes Frederic Sowa {
1937681e683fSHannes Frederic Sowa 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1938681e683fSHannes Frederic Sowa 
1939dedc33e7SJakub Kicinski 	if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
194004584957SSabrina Dubroca 		geneve_offload_rx_ports(dev, true);
1941dedc33e7SJakub Kicinski 	else if (event == NETDEV_UDP_TUNNEL_DROP_INFO)
1942dedc33e7SJakub Kicinski 		geneve_offload_rx_ports(dev, false);
1943681e683fSHannes Frederic Sowa 
1944681e683fSHannes Frederic Sowa 	return NOTIFY_DONE;
1945681e683fSHannes Frederic Sowa }
1946681e683fSHannes Frederic Sowa 
1947681e683fSHannes Frederic Sowa static struct notifier_block geneve_notifier_block __read_mostly = {
1948681e683fSHannes Frederic Sowa 	.notifier_call = geneve_netdevice_event,
1949681e683fSHannes Frederic Sowa };
1950681e683fSHannes Frederic Sowa 
geneve_init_net(struct net * net)19512d07dc79SJohn W. Linville static __net_init int geneve_init_net(struct net *net)
19522d07dc79SJohn W. Linville {
19532d07dc79SJohn W. Linville 	struct geneve_net *gn = net_generic(net, geneve_net_id);
19542d07dc79SJohn W. Linville 
19552d07dc79SJohn W. Linville 	INIT_LIST_HEAD(&gn->geneve_list);
1956371bd106SPravin B Shelar 	INIT_LIST_HEAD(&gn->sock_list);
19572d07dc79SJohn W. Linville 	return 0;
19582d07dc79SJohn W. Linville }
19592d07dc79SJohn W. Linville 
geneve_destroy_tunnels(struct net * net,struct list_head * head)19602843a253SHaishuang Yan static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
19612d07dc79SJohn W. Linville {
19622d07dc79SJohn W. Linville 	struct geneve_net *gn = net_generic(net, geneve_net_id);
19632d07dc79SJohn W. Linville 	struct geneve_dev *geneve, *next;
19642d07dc79SJohn W. Linville 
1965*3ce92ca9SKuniyuki Iwashima 	list_for_each_entry_safe(geneve, next, &gn->geneve_list, next)
1966*3ce92ca9SKuniyuki Iwashima 		geneve_dellink(geneve->dev, head);
19672843a253SHaishuang Yan }
19682843a253SHaishuang Yan 
geneve_exit_batch_net(struct list_head * net_list)19692843a253SHaishuang Yan static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
19702843a253SHaishuang Yan {
19712843a253SHaishuang Yan 	struct net *net;
19722843a253SHaishuang Yan 	LIST_HEAD(list);
19732843a253SHaishuang Yan 
19742843a253SHaishuang Yan 	rtnl_lock();
19752843a253SHaishuang Yan 	list_for_each_entry(net, net_list, exit_list)
19762843a253SHaishuang Yan 		geneve_destroy_tunnels(net, &list);
19772843a253SHaishuang Yan 
19782d07dc79SJohn W. Linville 	/* unregister the devices gathered above */
19792d07dc79SJohn W. Linville 	unregister_netdevice_many(&list);
19802d07dc79SJohn W. Linville 	rtnl_unlock();
19810fda7600SFlorian Westphal 
19820fda7600SFlorian Westphal 	list_for_each_entry(net, net_list, exit_list) {
19830fda7600SFlorian Westphal 		const struct geneve_net *gn = net_generic(net, geneve_net_id);
19840fda7600SFlorian Westphal 
19850fda7600SFlorian Westphal 		WARN_ON_ONCE(!list_empty(&gn->sock_list));
19860fda7600SFlorian Westphal 	}
19872d07dc79SJohn W. Linville }
19882d07dc79SJohn W. Linville 
19892d07dc79SJohn W. Linville static struct pernet_operations geneve_net_ops = {
19902d07dc79SJohn W. Linville 	.init = geneve_init_net,
19912843a253SHaishuang Yan 	.exit_batch = geneve_exit_batch_net,
19922d07dc79SJohn W. Linville 	.id   = &geneve_net_id,
19932d07dc79SJohn W. Linville 	.size = sizeof(struct geneve_net),
19942d07dc79SJohn W. Linville };
19952d07dc79SJohn W. Linville 
geneve_init_module(void)19962d07dc79SJohn W. Linville static int __init geneve_init_module(void)
19972d07dc79SJohn W. Linville {
19982d07dc79SJohn W. Linville 	int rc;
19992d07dc79SJohn W. Linville 
20002d07dc79SJohn W. Linville 	rc = register_pernet_subsys(&geneve_net_ops);
20012d07dc79SJohn W. Linville 	if (rc)
20022d07dc79SJohn W. Linville 		goto out1;
20032d07dc79SJohn W. Linville 
2004681e683fSHannes Frederic Sowa 	rc = register_netdevice_notifier(&geneve_notifier_block);
20052d07dc79SJohn W. Linville 	if (rc)
20062d07dc79SJohn W. Linville 		goto out2;
20072d07dc79SJohn W. Linville 
2008681e683fSHannes Frederic Sowa 	rc = rtnl_link_register(&geneve_link_ops);
2009681e683fSHannes Frederic Sowa 	if (rc)
2010681e683fSHannes Frederic Sowa 		goto out3;
2011681e683fSHannes Frederic Sowa 
20122d07dc79SJohn W. Linville 	return 0;
2013681e683fSHannes Frederic Sowa out3:
2014681e683fSHannes Frederic Sowa 	unregister_netdevice_notifier(&geneve_notifier_block);
20152d07dc79SJohn W. Linville out2:
20162d07dc79SJohn W. Linville 	unregister_pernet_subsys(&geneve_net_ops);
20172d07dc79SJohn W. Linville out1:
20182d07dc79SJohn W. Linville 	return rc;
20192d07dc79SJohn W. Linville }
20202d07dc79SJohn W. Linville late_initcall(geneve_init_module);
20212d07dc79SJohn W. Linville 
geneve_cleanup_module(void)20222d07dc79SJohn W. Linville static void __exit geneve_cleanup_module(void)
20232d07dc79SJohn W. Linville {
20242d07dc79SJohn W. Linville 	rtnl_link_unregister(&geneve_link_ops);
2025681e683fSHannes Frederic Sowa 	unregister_netdevice_notifier(&geneve_notifier_block);
20262d07dc79SJohn W. Linville 	unregister_pernet_subsys(&geneve_net_ops);
20272d07dc79SJohn W. Linville }
20282d07dc79SJohn W. Linville module_exit(geneve_cleanup_module);
20292d07dc79SJohn W. Linville 
20302d07dc79SJohn W. Linville MODULE_LICENSE("GPL");
20312d07dc79SJohn W. Linville MODULE_VERSION(GENEVE_NETDEV_VER);
20322d07dc79SJohn W. Linville MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
20332d07dc79SJohn W. Linville MODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic");
20342d07dc79SJohn W. Linville MODULE_ALIAS_RTNL_LINK("geneve");
2035