Blame view

drivers/net/geneve.c 48.8 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
2d07dc79f   John W. Linville   geneve: add initi...
2
3
4
5
  /*
   * GENEVE: Generic Network Virtualization Encapsulation
   *
   * Copyright (c) 2015 Red Hat, Inc.
2d07dc79f   John W. Linville   geneve: add initi...
6
7
8
9
10
11
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/kernel.h>
  #include <linux/module.h>
2d07dc79f   John W. Linville   geneve: add initi...
12
13
  #include <linux/etherdevice.h>
  #include <linux/hash.h>
3616d08bc   David Ahern   ipv6: Move ipv6 s...
14
  #include <net/ipv6_stubs.h>
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
15
  #include <net/dst_metadata.h>
8e816df87   Jesse Gross   geneve: Use GRO c...
16
  #include <net/gro_cells.h>
2d07dc79f   John W. Linville   geneve: add initi...
17
18
  #include <net/rtnetlink.h>
  #include <net/geneve.h>
371bd1061   Pravin B Shelar   geneve: Consolida...
19
  #include <net/protocol.h>
2d07dc79f   John W. Linville   geneve: add initi...
20
21
  
  #define GENEVE_NETDEV_VER	"0.6"
2d07dc79f   John W. Linville   geneve: add initi...
22
23
24
25
26
27
28
29
30
  #define GENEVE_N_VID		(1u << 24)
  #define GENEVE_VID_MASK		(GENEVE_N_VID - 1)
  
  #define VNI_HASH_BITS		10
  #define VNI_HASH_SIZE		(1<<VNI_HASH_BITS)
  
  static bool log_ecn_error = true;
  module_param(log_ecn_error, bool, 0644);
  MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
371bd1061   Pravin B Shelar   geneve: Consolida...
31
32
  #define GENEVE_VER 0
  #define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr))
5edbea698   Alexey Kodanev   geneve: cleanup h...
33
34
  #define GENEVE_IPV4_HLEN (ETH_HLEN + sizeof(struct iphdr) + GENEVE_BASE_HLEN)
  #define GENEVE_IPV6_HLEN (ETH_HLEN + sizeof(struct ipv6hdr) + GENEVE_BASE_HLEN)
371bd1061   Pravin B Shelar   geneve: Consolida...
35

2d07dc79f   John W. Linville   geneve: add initi...
36
37
  /* per-network namespace private data for this module */
  struct geneve_net {
371bd1061   Pravin B Shelar   geneve: Consolida...
38
  	struct list_head	geneve_list;
371bd1061   Pravin B Shelar   geneve: Consolida...
39
  	struct list_head	sock_list;
2d07dc79f   John W. Linville   geneve: add initi...
40
  };
c7d03a00b   Alexey Dobriyan   netns: make struc...
41
  static unsigned int geneve_net_id;
371bd1061   Pravin B Shelar   geneve: Consolida...
42

4b4c21fad   Jiri Benc   geneve: fix hlist...
43
44
45
46
  struct geneve_dev_node {
  	struct hlist_node hlist;
  	struct geneve_dev *geneve;
  };
2d07dc79f   John W. Linville   geneve: add initi...
47
48
  /* Pseudo network device */
  struct geneve_dev {
4b4c21fad   Jiri Benc   geneve: fix hlist...
49
50
51
52
  	struct geneve_dev_node hlist4;	/* vni hash table for IPv4 socket */
  #if IS_ENABLED(CONFIG_IPV6)
  	struct geneve_dev_node hlist6;	/* vni hash table for IPv6 socket */
  #endif
2d07dc79f   John W. Linville   geneve: add initi...
53
54
  	struct net	   *net;	/* netns for packet i/o */
  	struct net_device  *dev;	/* netdev for geneve tunnel */
9b4437a5b   pravin shelar   geneve: Unify LWT...
55
  	struct ip_tunnel_info info;
fceb9c3e3   pravin shelar   geneve: avoid usi...
56
  	struct geneve_sock __rcu *sock4;	/* IPv4 socket used for geneve tunnel */
8ed66f0e8   John W. Linville   geneve: implement...
57
  #if IS_ENABLED(CONFIG_IPV6)
fceb9c3e3   pravin shelar   geneve: avoid usi...
58
  	struct geneve_sock __rcu *sock6;	/* IPv6 socket used for geneve tunnel */
8ed66f0e8   John W. Linville   geneve: implement...
59
  #endif
2d07dc79f   John W. Linville   geneve: add initi...
60
  	struct list_head   next;	/* geneve's per namespace list */
8e816df87   Jesse Gross   geneve: Use GRO c...
61
  	struct gro_cells   gro_cells;
9b4437a5b   pravin shelar   geneve: Unify LWT...
62
63
  	bool		   collect_md;
  	bool		   use_udp6_rx_checksums;
52d0d404d   Hangbin Liu   geneve: add ttl i...
64
  	bool		   ttl_inherit;
a025fb5f4   Stefano Brivio   geneve: Allow con...
65
  	enum ifla_geneve_df df;
2d07dc79f   John W. Linville   geneve: add initi...
66
  };
371bd1061   Pravin B Shelar   geneve: Consolida...
67
68
  struct geneve_sock {
  	bool			collect_md;
371bd1061   Pravin B Shelar   geneve: Consolida...
69
70
71
72
  	struct list_head	list;
  	struct socket		*sock;
  	struct rcu_head		rcu;
  	int			refcnt;
66d47003f   Pravin B Shelar   geneve: Move devi...
73
  	struct hlist_head	vni_list[VNI_HASH_SIZE];
371bd1061   Pravin B Shelar   geneve: Consolida...
74
  };
2d07dc79f   John W. Linville   geneve: add initi...
75
76
77
78
79
80
81
82
  
  static inline __u32 geneve_net_vni_hash(u8 vni[3])
  {
  	__u32 vnid;
  
  	vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
  	return hash_32(vnid, VNI_HASH_BITS);
  }
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
83
84
85
86
87
88
89
90
91
92
  static __be64 vni_to_tunnel_id(const __u8 *vni)
  {
  #ifdef __BIG_ENDIAN
  	return (vni[0] << 16) | (vni[1] << 8) | vni[2];
  #else
  	return (__force __be64)(((__force u64)vni[0] << 40) |
  				((__force u64)vni[1] << 48) |
  				((__force u64)vni[2] << 56));
  #endif
  }
9b4437a5b   pravin shelar   geneve: Unify LWT...
93
94
95
96
97
98
99
100
101
102
103
104
105
  /* Convert 64 bit tunnel ID to 24 bit VNI. */
  static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
  {
  #ifdef __BIG_ENDIAN
  	vni[0] = (__force __u8)(tun_id >> 16);
  	vni[1] = (__force __u8)(tun_id >> 8);
  	vni[2] = (__force __u8)tun_id;
  #else
  	vni[0] = (__force __u8)((__force u64)tun_id >> 40);
  	vni[1] = (__force __u8)((__force u64)tun_id >> 48);
  	vni[2] = (__force __u8)((__force u64)tun_id >> 56);
  #endif
  }
2e0b26e10   pravin shelar   geneve: Optimize ...
106
107
  static bool eq_tun_id_and_vni(u8 *tun_id, u8 *vni)
  {
2e0b26e10   pravin shelar   geneve: Optimize ...
108
  	return !memcmp(vni, &tun_id[5], 3);
2e0b26e10   pravin shelar   geneve: Optimize ...
109
  }
1e9f12ec9   Jiri Benc   geneve: implement...
110
111
112
113
  static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
  {
  	return gs->sock->sk->sk_family;
  }
66d47003f   Pravin B Shelar   geneve: Move devi...
114
  static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
371bd1061   Pravin B Shelar   geneve: Consolida...
115
  					__be32 addr, u8 vni[])
2d07dc79f   John W. Linville   geneve: add initi...
116
  {
2d07dc79f   John W. Linville   geneve: add initi...
117
  	struct hlist_head *vni_list_head;
4b4c21fad   Jiri Benc   geneve: fix hlist...
118
  	struct geneve_dev_node *node;
2d07dc79f   John W. Linville   geneve: add initi...
119
  	__u32 hash;
2d07dc79f   John W. Linville   geneve: add initi...
120
  	/* Find the device for this VNI */
371bd1061   Pravin B Shelar   geneve: Consolida...
121
  	hash = geneve_net_vni_hash(vni);
66d47003f   Pravin B Shelar   geneve: Move devi...
122
  	vni_list_head = &gs->vni_list[hash];
4b4c21fad   Jiri Benc   geneve: fix hlist...
123
124
125
126
  	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
  		if (eq_tun_id_and_vni((u8 *)&node->geneve->info.key.tun_id, vni) &&
  		    addr == node->geneve->info.key.u.ipv4.dst)
  			return node->geneve;
8ed66f0e8   John W. Linville   geneve: implement...
127
128
129
130
131
132
133
134
135
  	}
  	return NULL;
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
  static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
  					 struct in6_addr addr6, u8 vni[])
  {
  	struct hlist_head *vni_list_head;
4b4c21fad   Jiri Benc   geneve: fix hlist...
136
  	struct geneve_dev_node *node;
8ed66f0e8   John W. Linville   geneve: implement...
137
138
139
140
141
  	__u32 hash;
  
  	/* Find the device for this VNI */
  	hash = geneve_net_vni_hash(vni);
  	vni_list_head = &gs->vni_list[hash];
4b4c21fad   Jiri Benc   geneve: fix hlist...
142
143
144
145
  	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
  		if (eq_tun_id_and_vni((u8 *)&node->geneve->info.key.tun_id, vni) &&
  		    ipv6_addr_equal(&addr6, &node->geneve->info.key.u.ipv6.dst))
  			return node->geneve;
2d07dc79f   John W. Linville   geneve: add initi...
146
  	}
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
147
148
  	return NULL;
  }
8ed66f0e8   John W. Linville   geneve: implement...
149
  #endif
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
150

371bd1061   Pravin B Shelar   geneve: Consolida...
151
152
153
154
  static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
  {
  	return (struct genevehdr *)(udp_hdr(skb) + 1);
  }
9fc475458   Jiri Benc   geneve: move gene...
155
156
  static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
  					    struct sk_buff *skb)
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
157
  {
8ed66f0e8   John W. Linville   geneve: implement...
158
  	static u8 zero_vni[3];
9b4437a5b   pravin shelar   geneve: Unify LWT...
159
  	u8 *vni;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
160

1e9f12ec9   Jiri Benc   geneve: implement...
161
  	if (geneve_get_sk_family(gs) == AF_INET) {
9fc475458   Jiri Benc   geneve: move gene...
162
  		struct iphdr *iph;
9b4437a5b   pravin shelar   geneve: Unify LWT...
163
  		__be32 addr;
9fc475458   Jiri Benc   geneve: move gene...
164

8ed66f0e8   John W. Linville   geneve: implement...
165
  		iph = ip_hdr(skb); /* outer IP header... */
371bd1061   Pravin B Shelar   geneve: Consolida...
166

8ed66f0e8   John W. Linville   geneve: implement...
167
168
169
170
  		if (gs->collect_md) {
  			vni = zero_vni;
  			addr = 0;
  		} else {
9fc475458   Jiri Benc   geneve: move gene...
171
  			vni = geneve_hdr(skb)->vni;
8ed66f0e8   John W. Linville   geneve: implement...
172
173
  			addr = iph->saddr;
  		}
9fc475458   Jiri Benc   geneve: move gene...
174
  		return geneve_lookup(gs, addr, vni);
8ed66f0e8   John W. Linville   geneve: implement...
175
  #if IS_ENABLED(CONFIG_IPV6)
1e9f12ec9   Jiri Benc   geneve: implement...
176
  	} else if (geneve_get_sk_family(gs) == AF_INET6) {
9b4437a5b   pravin shelar   geneve: Unify LWT...
177
  		static struct in6_addr zero_addr6;
9fc475458   Jiri Benc   geneve: move gene...
178
179
  		struct ipv6hdr *ip6h;
  		struct in6_addr addr6;
8ed66f0e8   John W. Linville   geneve: implement...
180
  		ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
371bd1061   Pravin B Shelar   geneve: Consolida...
181

8ed66f0e8   John W. Linville   geneve: implement...
182
183
184
185
  		if (gs->collect_md) {
  			vni = zero_vni;
  			addr6 = zero_addr6;
  		} else {
9fc475458   Jiri Benc   geneve: move gene...
186
  			vni = geneve_hdr(skb)->vni;
8ed66f0e8   John W. Linville   geneve: implement...
187
188
  			addr6 = ip6h->saddr;
  		}
9fc475458   Jiri Benc   geneve: move gene...
189
  		return geneve6_lookup(gs, addr6, vni);
8ed66f0e8   John W. Linville   geneve: implement...
190
191
  #endif
  	}
9fc475458   Jiri Benc   geneve: move gene...
192
193
194
195
196
197
198
199
200
201
  	return NULL;
  }
  
  /* geneve receive/decap routine */
  static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
  		      struct sk_buff *skb)
  {
  	struct genevehdr *gnvh = geneve_hdr(skb);
  	struct metadata_dst *tun_dst = NULL;
  	struct pcpu_sw_netstats *stats;
fe741e236   Girish Moodalbail   geneve: add missi...
202
  	unsigned int len;
9fc475458   Jiri Benc   geneve: move gene...
203
204
  	int err = 0;
  	void *oiph;
2d07dc79f   John W. Linville   geneve: add initi...
205

371bd1061   Pravin B Shelar   geneve: Consolida...
206
  	if (ip_tunnel_collect_metadata() || gs->collect_md) {
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
207
  		__be16 flags;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
208
209
210
211
  
  		flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT |
  			(gnvh->oam ? TUNNEL_OAM : 0) |
  			(gnvh->critical ? TUNNEL_CRIT_OPT : 0);
1e9f12ec9   Jiri Benc   geneve: implement...
212
  		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
213
214
  					 vni_to_tunnel_id(gnvh->vni),
  					 gnvh->opt_len * 4);
fe741e236   Girish Moodalbail   geneve: add missi...
215
216
  		if (!tun_dst) {
  			geneve->dev->stats.rx_dropped++;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
217
  			goto drop;
fe741e236   Girish Moodalbail   geneve: add missi...
218
  		}
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
219
  		/* Update tunnel dst according to Geneve options. */
4c2227984   Pravin B Shelar   ip-tunnel: Use AP...
220
  		ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
256c87c17   Pieter Jansen van Vuuren   net: check tunnel...
221
222
  					gnvh->options, gnvh->opt_len * 4,
  					TUNNEL_GENEVE_OPT);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
223
224
225
226
  	} else {
  		/* Drop packets w/ critical options,
  		 * since we don't support any...
  		 */
fe741e236   Girish Moodalbail   geneve: add missi...
227
228
229
  		if (gnvh->critical) {
  			geneve->dev->stats.rx_frame_errors++;
  			geneve->dev->stats.rx_errors++;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
230
  			goto drop;
fe741e236   Girish Moodalbail   geneve: add missi...
231
  		}
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
232
  	}
2d07dc79f   John W. Linville   geneve: add initi...
233
234
  
  	skb_reset_mac_header(skb);
2d07dc79f   John W. Linville   geneve: add initi...
235
236
  	skb->protocol = eth_type_trans(skb, geneve->dev);
  	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
237
238
  	if (tun_dst)
  		skb_dst_set(skb, &tun_dst->dst);
2d07dc79f   John W. Linville   geneve: add initi...
239
  	/* Ignore packet loops (and multicast echo) */
fe741e236   Girish Moodalbail   geneve: add missi...
240
241
  	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) {
  		geneve->dev->stats.rx_errors++;
2d07dc79f   John W. Linville   geneve: add initi...
242
  		goto drop;
fe741e236   Girish Moodalbail   geneve: add missi...
243
  	}
2d07dc79f   John W. Linville   geneve: add initi...
244

9fc475458   Jiri Benc   geneve: move gene...
245
  	oiph = skb_network_header(skb);
2d07dc79f   John W. Linville   geneve: add initi...
246
  	skb_reset_network_header(skb);
9fc475458   Jiri Benc   geneve: move gene...
247
248
  	if (geneve_get_sk_family(gs) == AF_INET)
  		err = IP_ECN_decapsulate(oiph, skb);
8ed66f0e8   John W. Linville   geneve: implement...
249
  #if IS_ENABLED(CONFIG_IPV6)
9fc475458   Jiri Benc   geneve: move gene...
250
251
  	else
  		err = IP6_ECN_decapsulate(oiph, skb);
8ed66f0e8   John W. Linville   geneve: implement...
252
  #endif
2d07dc79f   John W. Linville   geneve: add initi...
253
254
  
  	if (unlikely(err)) {
8ed66f0e8   John W. Linville   geneve: implement...
255
  		if (log_ecn_error) {
9fc475458   Jiri Benc   geneve: move gene...
256
  			if (geneve_get_sk_family(gs) == AF_INET)
8ed66f0e8   John W. Linville   geneve: implement...
257
258
259
  				net_info_ratelimited("non-ECT from %pI4 "
  						     "with TOS=%#x
  ",
9fc475458   Jiri Benc   geneve: move gene...
260
261
  						     &((struct iphdr *)oiph)->saddr,
  						     ((struct iphdr *)oiph)->tos);
8ed66f0e8   John W. Linville   geneve: implement...
262
  #if IS_ENABLED(CONFIG_IPV6)
9fc475458   Jiri Benc   geneve: move gene...
263
  			else
8ed66f0e8   John W. Linville   geneve: implement...
264
265
  				net_info_ratelimited("non-ECT from %pI6
  ",
9fc475458   Jiri Benc   geneve: move gene...
266
  						     &((struct ipv6hdr *)oiph)->saddr);
8ed66f0e8   John W. Linville   geneve: implement...
267
268
  #endif
  		}
2d07dc79f   John W. Linville   geneve: add initi...
269
270
271
272
273
274
  		if (err > 1) {
  			++geneve->dev->stats.rx_frame_errors;
  			++geneve->dev->stats.rx_errors;
  			goto drop;
  		}
  	}
fe741e236   Girish Moodalbail   geneve: add missi...
275
276
277
278
279
280
281
282
283
  	len = skb->len;
  	err = gro_cells_receive(&geneve->gro_cells, skb);
  	if (likely(err == NET_RX_SUCCESS)) {
  		stats = this_cpu_ptr(geneve->dev->tstats);
  		u64_stats_update_begin(&stats->syncp);
  		stats->rx_packets++;
  		stats->rx_bytes += len;
  		u64_stats_update_end(&stats->syncp);
  	}
2d07dc79f   John W. Linville   geneve: add initi...
284
285
286
287
288
289
290
291
292
  	return;
  drop:
  	/* Consume bad packet */
  	kfree_skb(skb);
  }
  
  /* Setup stats when device is created */
  static int geneve_init(struct net_device *dev)
  {
8e816df87   Jesse Gross   geneve: Use GRO c...
293
294
  	struct geneve_dev *geneve = netdev_priv(dev);
  	int err;
2d07dc79f   John W. Linville   geneve: add initi...
295
296
297
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
  	if (!dev->tstats)
  		return -ENOMEM;
8e816df87   Jesse Gross   geneve: Use GRO c...
298
299
300
301
302
303
  
  	err = gro_cells_init(&geneve->gro_cells, dev);
  	if (err) {
  		free_percpu(dev->tstats);
  		return err;
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
304
  	err = dst_cache_init(&geneve->info.dst_cache, GFP_KERNEL);
468dfffcd   Paolo Abeni   geneve: add dst c...
305
306
307
308
309
  	if (err) {
  		free_percpu(dev->tstats);
  		gro_cells_destroy(&geneve->gro_cells);
  		return err;
  	}
2d07dc79f   John W. Linville   geneve: add initi...
310
311
312
313
314
  	return 0;
  }
  
  static void geneve_uninit(struct net_device *dev)
  {
8e816df87   Jesse Gross   geneve: Use GRO c...
315
  	struct geneve_dev *geneve = netdev_priv(dev);
9b4437a5b   pravin shelar   geneve: Unify LWT...
316
  	dst_cache_destroy(&geneve->info.dst_cache);
8e816df87   Jesse Gross   geneve: Use GRO c...
317
  	gro_cells_destroy(&geneve->gro_cells);
2d07dc79f   John W. Linville   geneve: add initi...
318
319
  	free_percpu(dev->tstats);
  }
371bd1061   Pravin B Shelar   geneve: Consolida...
320
321
322
323
  /* Callback from net/ipv4/udp.c to receive packets */
  static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
  {
  	struct genevehdr *geneveh;
9fc475458   Jiri Benc   geneve: move gene...
324
  	struct geneve_dev *geneve;
371bd1061   Pravin B Shelar   geneve: Consolida...
325
326
  	struct geneve_sock *gs;
  	int opts_len;
fe741e236   Girish Moodalbail   geneve: add missi...
327
  	/* Need UDP and Geneve header to be present */
371bd1061   Pravin B Shelar   geneve: Consolida...
328
  	if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
e5aed006b   Hannes Frederic Sowa   udp: prevent skbs...
329
  		goto drop;
371bd1061   Pravin B Shelar   geneve: Consolida...
330
331
332
333
  
  	/* Return packets with reserved bits set */
  	geneveh = geneve_hdr(skb);
  	if (unlikely(geneveh->ver != GENEVE_VER))
e5aed006b   Hannes Frederic Sowa   udp: prevent skbs...
334
  		goto drop;
371bd1061   Pravin B Shelar   geneve: Consolida...
335
336
  
  	if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
e5aed006b   Hannes Frederic Sowa   udp: prevent skbs...
337
  		goto drop;
371bd1061   Pravin B Shelar   geneve: Consolida...
338

9fc475458   Jiri Benc   geneve: move gene...
339
340
341
342
343
344
345
  	gs = rcu_dereference_sk_user_data(sk);
  	if (!gs)
  		goto drop;
  
  	geneve = geneve_lookup_skb(gs, skb);
  	if (!geneve)
  		goto drop;
371bd1061   Pravin B Shelar   geneve: Consolida...
346
347
  	opts_len = geneveh->opt_len * 4;
  	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
7f290c943   Jiri Benc   iptunnel: scrub p...
348
  				 htons(ETH_P_TEB),
fe741e236   Girish Moodalbail   geneve: add missi...
349
350
  				 !net_eq(geneve->net, dev_net(geneve->dev)))) {
  		geneve->dev->stats.rx_dropped++;
371bd1061   Pravin B Shelar   geneve: Consolida...
351
  		goto drop;
fe741e236   Girish Moodalbail   geneve: add missi...
352
  	}
371bd1061   Pravin B Shelar   geneve: Consolida...
353

9fc475458   Jiri Benc   geneve: move gene...
354
  	geneve_rx(geneve, gs, skb);
371bd1061   Pravin B Shelar   geneve: Consolida...
355
356
357
358
359
360
  	return 0;
  
  drop:
  	/* Consume bad packet */
  	kfree_skb(skb);
  	return 0;
371bd1061   Pravin B Shelar   geneve: Consolida...
361
  }
a07966447   Stefano Brivio   geneve: ICMP erro...
362
363
364
365
366
367
368
  /* Callback from net/ipv{4,6}/udp.c to check that we have a tunnel for errors */
  static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
  {
  	struct genevehdr *geneveh;
  	struct geneve_sock *gs;
  	u8 zero_vni[3] = { 0 };
  	u8 *vni = zero_vni;
eccc73a6b   Stefano Brivio   geneve: Don't ass...
369
  	if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
a07966447   Stefano Brivio   geneve: ICMP erro...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  		return -EINVAL;
  
  	geneveh = geneve_hdr(skb);
  	if (geneveh->ver != GENEVE_VER)
  		return -EINVAL;
  
  	if (geneveh->proto_type != htons(ETH_P_TEB))
  		return -EINVAL;
  
  	gs = rcu_dereference_sk_user_data(sk);
  	if (!gs)
  		return -ENOENT;
  
  	if (geneve_get_sk_family(gs) == AF_INET) {
  		struct iphdr *iph = ip_hdr(skb);
  		__be32 addr4 = 0;
  
  		if (!gs->collect_md) {
  			vni = geneve_hdr(skb)->vni;
  			addr4 = iph->daddr;
  		}
  
  		return geneve_lookup(gs, addr4, vni) ? 0 : -ENOENT;
  	}
  
  #if IS_ENABLED(CONFIG_IPV6)
  	if (geneve_get_sk_family(gs) == AF_INET6) {
  		struct ipv6hdr *ip6h = ipv6_hdr(skb);
8a962c4aa   Nathan Chancellor   geneve: Initializ...
398
399
400
  		struct in6_addr addr6;
  
  		memset(&addr6, 0, sizeof(struct in6_addr));
a07966447   Stefano Brivio   geneve: ICMP erro...
401
402
403
404
405
406
407
408
409
410
411
412
  
  		if (!gs->collect_md) {
  			vni = geneve_hdr(skb)->vni;
  			addr6 = ip6h->daddr;
  		}
  
  		return geneve6_lookup(gs, addr6, vni) ? 0 : -ENOENT;
  	}
  #endif
  
  	return -EPFNOSUPPORT;
  }
371bd1061   Pravin B Shelar   geneve: Consolida...
413
  static struct socket *geneve_create_sock(struct net *net, bool ipv6,
9b4437a5b   pravin shelar   geneve: Unify LWT...
414
  					 __be16 port, bool ipv6_rx_csum)
371bd1061   Pravin B Shelar   geneve: Consolida...
415
416
417
418
419
420
421
422
423
  {
  	struct socket *sock;
  	struct udp_port_cfg udp_conf;
  	int err;
  
  	memset(&udp_conf, 0, sizeof(udp_conf));
  
  	if (ipv6) {
  		udp_conf.family = AF_INET6;
8ed66f0e8   John W. Linville   geneve: implement...
424
  		udp_conf.ipv6_v6only = 1;
9b4437a5b   pravin shelar   geneve: Unify LWT...
425
  		udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
371bd1061   Pravin B Shelar   geneve: Consolida...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  	} else {
  		udp_conf.family = AF_INET;
  		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
  	}
  
  	udp_conf.local_udp_port = port;
  
  	/* Open UDP socket */
  	err = udp_sock_create(net, &udp_conf, &sock);
  	if (err < 0)
  		return ERR_PTR(err);
  
  	return sock;
  }
371bd1061   Pravin B Shelar   geneve: Consolida...
440
441
442
443
  static int geneve_hlen(struct genevehdr *gh)
  {
  	return sizeof(*gh) + gh->opt_len * 4;
  }
d4546c250   David Miller   net: Convert GRO ...
444
445
446
  static struct sk_buff *geneve_gro_receive(struct sock *sk,
  					  struct list_head *head,
  					  struct sk_buff *skb)
371bd1061   Pravin B Shelar   geneve: Consolida...
447
  {
d4546c250   David Miller   net: Convert GRO ...
448
449
  	struct sk_buff *pp = NULL;
  	struct sk_buff *p;
371bd1061   Pravin B Shelar   geneve: Consolida...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	struct genevehdr *gh, *gh2;
  	unsigned int hlen, gh_len, off_gnv;
  	const struct packet_offload *ptype;
  	__be16 type;
  	int flush = 1;
  
  	off_gnv = skb_gro_offset(skb);
  	hlen = off_gnv + sizeof(*gh);
  	gh = skb_gro_header_fast(skb, off_gnv);
  	if (skb_gro_header_hard(skb, hlen)) {
  		gh = skb_gro_header_slow(skb, hlen, off_gnv);
  		if (unlikely(!gh))
  			goto out;
  	}
  
  	if (gh->ver != GENEVE_VER || gh->oam)
  		goto out;
  	gh_len = geneve_hlen(gh);
  
  	hlen = off_gnv + gh_len;
  	if (skb_gro_header_hard(skb, hlen)) {
  		gh = skb_gro_header_slow(skb, hlen, off_gnv);
  		if (unlikely(!gh))
  			goto out;
  	}
d4546c250   David Miller   net: Convert GRO ...
475
  	list_for_each_entry(p, head, list) {
371bd1061   Pravin B Shelar   geneve: Consolida...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  		if (!NAPI_GRO_CB(p)->same_flow)
  			continue;
  
  		gh2 = (struct genevehdr *)(p->data + off_gnv);
  		if (gh->opt_len != gh2->opt_len ||
  		    memcmp(gh, gh2, gh_len)) {
  			NAPI_GRO_CB(p)->same_flow = 0;
  			continue;
  		}
  	}
  
  	type = gh->proto_type;
  
  	rcu_read_lock();
  	ptype = gro_find_receive_by_type(type);
c194cf93c   Alexander Duyck   gro: Defer cleari...
491
  	if (!ptype)
371bd1061   Pravin B Shelar   geneve: Consolida...
492
  		goto out_unlock;
371bd1061   Pravin B Shelar   geneve: Consolida...
493
494
495
  
  	skb_gro_pull(skb, gh_len);
  	skb_gro_postpull_rcsum(skb, gh, gh_len);
fcd91dd44   Sabrina Dubroca   net: add recursio...
496
  	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
c194cf93c   Alexander Duyck   gro: Defer cleari...
497
  	flush = 0;
371bd1061   Pravin B Shelar   geneve: Consolida...
498
499
500
501
  
  out_unlock:
  	rcu_read_unlock();
  out:
603d4cf8f   Sabrina Dubroca   net: fix use-afte...
502
  	skb_gro_flush_final(skb, pp, flush);
371bd1061   Pravin B Shelar   geneve: Consolida...
503
504
505
  
  	return pp;
  }
4a0090a98   Tom Herbert   geneve: change to...
506
507
  static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
  			       int nhoff)
371bd1061   Pravin B Shelar   geneve: Consolida...
508
509
510
511
512
513
  {
  	struct genevehdr *gh;
  	struct packet_offload *ptype;
  	__be16 type;
  	int gh_len;
  	int err = -ENOSYS;
371bd1061   Pravin B Shelar   geneve: Consolida...
514
515
516
517
518
519
520
521
522
523
  	gh = (struct genevehdr *)(skb->data + nhoff);
  	gh_len = geneve_hlen(gh);
  	type = gh->proto_type;
  
  	rcu_read_lock();
  	ptype = gro_find_complete_by_type(type);
  	if (ptype)
  		err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
  
  	rcu_read_unlock();
229740c63   Jarno Rajahalme   udp_offload: Set ...
524
525
  
  	skb_set_inner_mac_header(skb, nhoff + gh_len);
371bd1061   Pravin B Shelar   geneve: Consolida...
526
527
528
529
530
  	return err;
  }
  
  /* Create new listen socket if needed */
  static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
9b4437a5b   pravin shelar   geneve: Unify LWT...
531
  						bool ipv6, bool ipv6_rx_csum)
371bd1061   Pravin B Shelar   geneve: Consolida...
532
533
534
535
536
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
  	struct geneve_sock *gs;
  	struct socket *sock;
  	struct udp_tunnel_sock_cfg tunnel_cfg;
66d47003f   Pravin B Shelar   geneve: Move devi...
537
  	int h;
371bd1061   Pravin B Shelar   geneve: Consolida...
538
539
540
541
  
  	gs = kzalloc(sizeof(*gs), GFP_KERNEL);
  	if (!gs)
  		return ERR_PTR(-ENOMEM);
9b4437a5b   pravin shelar   geneve: Unify LWT...
542
  	sock = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
371bd1061   Pravin B Shelar   geneve: Consolida...
543
544
545
546
547
548
549
  	if (IS_ERR(sock)) {
  		kfree(gs);
  		return ERR_CAST(sock);
  	}
  
  	gs->sock = sock;
  	gs->refcnt = 1;
66d47003f   Pravin B Shelar   geneve: Move devi...
550
551
  	for (h = 0; h < VNI_HASH_SIZE; ++h)
  		INIT_HLIST_HEAD(&gs->vni_list[h]);
371bd1061   Pravin B Shelar   geneve: Consolida...
552
553
  
  	/* Initialize the geneve udp offloads structure */
e7b3db5e6   Alexander Duyck   net: Combine GENE...
554
  	udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
371bd1061   Pravin B Shelar   geneve: Consolida...
555
556
  
  	/* Mark socket as an encapsulation socket */
4a0090a98   Tom Herbert   geneve: change to...
557
  	memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
371bd1061   Pravin B Shelar   geneve: Consolida...
558
559
  	tunnel_cfg.sk_user_data = gs;
  	tunnel_cfg.encap_type = 1;
4a0090a98   Tom Herbert   geneve: change to...
560
561
  	tunnel_cfg.gro_receive = geneve_gro_receive;
  	tunnel_cfg.gro_complete = geneve_gro_complete;
371bd1061   Pravin B Shelar   geneve: Consolida...
562
  	tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
a07966447   Stefano Brivio   geneve: ICMP erro...
563
  	tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup;
371bd1061   Pravin B Shelar   geneve: Consolida...
564
565
  	tunnel_cfg.encap_destroy = NULL;
  	setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
371bd1061   Pravin B Shelar   geneve: Consolida...
566
567
568
  	list_add(&gs->list, &gn->sock_list);
  	return gs;
  }
8ed66f0e8   John W. Linville   geneve: implement...
569
  static void __geneve_sock_release(struct geneve_sock *gs)
371bd1061   Pravin B Shelar   geneve: Consolida...
570
  {
8ed66f0e8   John W. Linville   geneve: implement...
571
  	if (!gs || --gs->refcnt)
371bd1061   Pravin B Shelar   geneve: Consolida...
572
573
574
  		return;
  
  	list_del(&gs->list);
e7b3db5e6   Alexander Duyck   net: Combine GENE...
575
  	udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
371bd1061   Pravin B Shelar   geneve: Consolida...
576
577
578
  	udp_tunnel_sock_release(gs->sock);
  	kfree_rcu(gs, rcu);
  }
8ed66f0e8   John W. Linville   geneve: implement...
579
580
  static void geneve_sock_release(struct geneve_dev *geneve)
  {
fceb9c3e3   pravin shelar   geneve: avoid usi...
581
  	struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
8ed66f0e8   John W. Linville   geneve: implement...
582
  #if IS_ENABLED(CONFIG_IPV6)
fceb9c3e3   pravin shelar   geneve: avoid usi...
583
584
585
586
587
588
589
590
591
592
593
  	struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
  
  	rcu_assign_pointer(geneve->sock6, NULL);
  #endif
  
  	rcu_assign_pointer(geneve->sock4, NULL);
  	synchronize_net();
  
  	__geneve_sock_release(gs4);
  #if IS_ENABLED(CONFIG_IPV6)
  	__geneve_sock_release(gs6);
8ed66f0e8   John W. Linville   geneve: implement...
594
595
  #endif
  }
371bd1061   Pravin B Shelar   geneve: Consolida...
596
  static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
8ed66f0e8   John W. Linville   geneve: implement...
597
  					    sa_family_t family,
371bd1061   Pravin B Shelar   geneve: Consolida...
598
599
600
601
602
603
  					    __be16 dst_port)
  {
  	struct geneve_sock *gs;
  
  	list_for_each_entry(gs, &gn->sock_list, list) {
  		if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
1e9f12ec9   Jiri Benc   geneve: implement...
604
  		    geneve_get_sk_family(gs) == family) {
371bd1061   Pravin B Shelar   geneve: Consolida...
605
606
607
608
609
  			return gs;
  		}
  	}
  	return NULL;
  }
8ed66f0e8   John W. Linville   geneve: implement...
610
  static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
2d07dc79f   John W. Linville   geneve: add initi...
611
  {
2d07dc79f   John W. Linville   geneve: add initi...
612
  	struct net *net = geneve->net;
371bd1061   Pravin B Shelar   geneve: Consolida...
613
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
4b4c21fad   Jiri Benc   geneve: fix hlist...
614
  	struct geneve_dev_node *node;
2d07dc79f   John W. Linville   geneve: add initi...
615
  	struct geneve_sock *gs;
9b4437a5b   pravin shelar   geneve: Unify LWT...
616
  	__u8 vni[3];
66d47003f   Pravin B Shelar   geneve: Move devi...
617
  	__u32 hash;
2d07dc79f   John W. Linville   geneve: add initi...
618

9b4437a5b   pravin shelar   geneve: Unify LWT...
619
  	gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->info.key.tp_dst);
371bd1061   Pravin B Shelar   geneve: Consolida...
620
621
622
623
  	if (gs) {
  		gs->refcnt++;
  		goto out;
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
624
625
  	gs = geneve_socket_create(net, geneve->info.key.tp_dst, ipv6,
  				  geneve->use_udp6_rx_checksums);
2d07dc79f   John W. Linville   geneve: add initi...
626
627
  	if (IS_ERR(gs))
  		return PTR_ERR(gs);
371bd1061   Pravin B Shelar   geneve: Consolida...
628
629
  out:
  	gs->collect_md = geneve->collect_md;
8ed66f0e8   John W. Linville   geneve: implement...
630
  #if IS_ENABLED(CONFIG_IPV6)
4b4c21fad   Jiri Benc   geneve: fix hlist...
631
  	if (ipv6) {
fceb9c3e3   pravin shelar   geneve: avoid usi...
632
  		rcu_assign_pointer(geneve->sock6, gs);
4b4c21fad   Jiri Benc   geneve: fix hlist...
633
634
  		node = &geneve->hlist6;
  	} else
8ed66f0e8   John W. Linville   geneve: implement...
635
  #endif
4b4c21fad   Jiri Benc   geneve: fix hlist...
636
  	{
fceb9c3e3   pravin shelar   geneve: avoid usi...
637
  		rcu_assign_pointer(geneve->sock4, gs);
4b4c21fad   Jiri Benc   geneve: fix hlist...
638
639
640
  		node = &geneve->hlist4;
  	}
  	node->geneve = geneve;
66d47003f   Pravin B Shelar   geneve: Move devi...
641

9b4437a5b   pravin shelar   geneve: Unify LWT...
642
643
  	tunnel_id_to_vni(geneve->info.key.tun_id, vni);
  	hash = geneve_net_vni_hash(vni);
4b4c21fad   Jiri Benc   geneve: fix hlist...
644
  	hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]);
2d07dc79f   John W. Linville   geneve: add initi...
645
646
  	return 0;
  }
8ed66f0e8   John W. Linville   geneve: implement...
647
648
649
  static int geneve_open(struct net_device *dev)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
8ed66f0e8   John W. Linville   geneve: implement...
650
  	bool metadata = geneve->collect_md;
cf1c9ccba   Jiri Benc   geneve: correctly...
651
  	bool ipv4, ipv6;
8ed66f0e8   John W. Linville   geneve: implement...
652
  	int ret = 0;
cf1c9ccba   Jiri Benc   geneve: correctly...
653
654
  	ipv6 = geneve->info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
  	ipv4 = !ipv6 || metadata;
8ed66f0e8   John W. Linville   geneve: implement...
655
  #if IS_ENABLED(CONFIG_IPV6)
cf1c9ccba   Jiri Benc   geneve: correctly...
656
  	if (ipv6) {
8ed66f0e8   John W. Linville   geneve: implement...
657
  		ret = geneve_sock_add(geneve, true);
cf1c9ccba   Jiri Benc   geneve: correctly...
658
659
660
  		if (ret < 0 && ret != -EAFNOSUPPORT)
  			ipv4 = false;
  	}
8ed66f0e8   John W. Linville   geneve: implement...
661
  #endif
cf1c9ccba   Jiri Benc   geneve: correctly...
662
  	if (ipv4)
8ed66f0e8   John W. Linville   geneve: implement...
663
664
665
666
667
668
  		ret = geneve_sock_add(geneve, false);
  	if (ret < 0)
  		geneve_sock_release(geneve);
  
  	return ret;
  }
2d07dc79f   John W. Linville   geneve: add initi...
669
670
671
  static int geneve_stop(struct net_device *dev)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
2d07dc79f   John W. Linville   geneve: add initi...
672

4b4c21fad   Jiri Benc   geneve: fix hlist...
673
674
675
676
  	hlist_del_init_rcu(&geneve->hlist4.hlist);
  #if IS_ENABLED(CONFIG_IPV6)
  	hlist_del_init_rcu(&geneve->hlist6.hlist);
  #endif
8ed66f0e8   John W. Linville   geneve: implement...
677
  	geneve_sock_release(geneve);
371bd1061   Pravin B Shelar   geneve: Consolida...
678
679
  	return 0;
  }
8ed66f0e8   John W. Linville   geneve: implement...
680
  static void geneve_build_header(struct genevehdr *geneveh,
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
681
  				const struct ip_tunnel_info *info)
8ed66f0e8   John W. Linville   geneve: implement...
682
683
  {
  	geneveh->ver = GENEVE_VER;
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
684
685
686
  	geneveh->opt_len = info->options_len / 4;
  	geneveh->oam = !!(info->key.tun_flags & TUNNEL_OAM);
  	geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
8ed66f0e8   John W. Linville   geneve: implement...
687
  	geneveh->rsvd1 = 0;
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
688
  	tunnel_id_to_vni(info->key.tun_id, geneveh->vni);
8ed66f0e8   John W. Linville   geneve: implement...
689
690
  	geneveh->proto_type = htons(ETH_P_TEB);
  	geneveh->rsvd2 = 0;
256c87c17   Pieter Jansen van Vuuren   net: check tunnel...
691
692
  	if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
  		ip_tunnel_info_opts_get(geneveh->options, info);
8ed66f0e8   John W. Linville   geneve: implement...
693
  }
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
694
695
696
  static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
  			    const struct ip_tunnel_info *info,
  			    bool xnet, int ip_hdr_len)
371bd1061   Pravin B Shelar   geneve: Consolida...
697
  {
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
698
  	bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
8ed66f0e8   John W. Linville   geneve: implement...
699
700
701
  	struct genevehdr *gnvh;
  	int min_headroom;
  	int err;
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
702
  	skb_reset_mac_header(skb);
8ed66f0e8   John W. Linville   geneve: implement...
703
  	skb_scrub_packet(skb, xnet);
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
704
705
  	min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +
  		       GENEVE_BASE_HLEN + info->options_len + ip_hdr_len;
8ed66f0e8   John W. Linville   geneve: implement...
706
  	err = skb_cow_head(skb, min_headroom);
aed069df0   Alexander Duyck   ip_tunnel_core: i...
707
  	if (unlikely(err))
8ed66f0e8   John W. Linville   geneve: implement...
708
  		goto free_dst;
8ed66f0e8   John W. Linville   geneve: implement...
709

aed069df0   Alexander Duyck   ip_tunnel_core: i...
710
  	err = udp_tunnel_handle_offloads(skb, udp_sum);
1ba64faca   Dan Carpenter   geneve: testing t...
711
  	if (err)
8ed66f0e8   John W. Linville   geneve: implement...
712
  		goto free_dst;
8ed66f0e8   John W. Linville   geneve: implement...
713

d58ff3512   Johannes Berg   networking: make ...
714
  	gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
715
  	geneve_build_header(gnvh, info);
8ed66f0e8   John W. Linville   geneve: implement...
716
717
718
719
720
721
722
  	skb_set_inner_protocol(skb, htons(ETH_P_TEB));
  	return 0;
  
  free_dst:
  	dst_release(dst);
  	return err;
  }
8ed66f0e8   John W. Linville   geneve: implement...
723
724
725
  
  static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
  				       struct net_device *dev,
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
726
  				       struct geneve_sock *gs4,
8ed66f0e8   John W. Linville   geneve: implement...
727
  				       struct flowi4 *fl4,
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
728
  				       const struct ip_tunnel_info *info)
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
729
  {
db3c6139e   Daniel Borkmann   bpf, vxlan, genev...
730
  	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
731
  	struct geneve_dev *geneve = netdev_priv(dev);
468dfffcd   Paolo Abeni   geneve: add dst c...
732
  	struct dst_cache *dst_cache;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
733
734
  	struct rtable *rt = NULL;
  	__u8 tos;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
735
  	if (!gs4)
fceb9c3e3   pravin shelar   geneve: avoid usi...
736
  		return ERR_PTR(-EIO);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
737
738
739
  	memset(fl4, 0, sizeof(*fl4));
  	fl4->flowi4_mark = skb->mark;
  	fl4->flowi4_proto = IPPROTO_UDP;
9b4437a5b   pravin shelar   geneve: Unify LWT...
740
741
  	fl4->daddr = info->key.u.ipv4.dst;
  	fl4->saddr = info->key.u.ipv4.src;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
742

9b4437a5b   pravin shelar   geneve: Unify LWT...
743
744
745
746
  	tos = info->key.tos;
  	if ((tos == 1) && !geneve->collect_md) {
  		tos = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
  		use_cache = false;
468dfffcd   Paolo Abeni   geneve: add dst c...
747
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
748
  	fl4->flowi4_tos = RT_TOS(tos);
468dfffcd   Paolo Abeni   geneve: add dst c...
749

c3ef5aa5e   pravin shelar   geneve: Merge ipv...
750
  	dst_cache = (struct dst_cache *)&info->dst_cache;
468dfffcd   Paolo Abeni   geneve: add dst c...
751
752
753
754
  	if (use_cache) {
  		rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
  		if (rt)
  			return rt;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
755
  	}
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
756
757
758
759
  	rt = ip_route_output_key(geneve->net, fl4);
  	if (IS_ERR(rt)) {
  		netdev_dbg(dev, "no route to %pI4
  ", &fl4->daddr);
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
760
  		return ERR_PTR(-ENETUNREACH);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
761
762
763
764
  	}
  	if (rt->dst.dev == dev) { /* is this necessary? */
  		netdev_dbg(dev, "circular route to %pI4
  ", &fl4->daddr);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
765
  		ip_rt_put(rt);
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
766
  		return ERR_PTR(-ELOOP);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
767
  	}
468dfffcd   Paolo Abeni   geneve: add dst c...
768
769
  	if (use_cache)
  		dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
770
771
  	return rt;
  }
8ed66f0e8   John W. Linville   geneve: implement...
772
773
774
  #if IS_ENABLED(CONFIG_IPV6)
  static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
  					   struct net_device *dev,
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
775
  					   struct geneve_sock *gs6,
8ed66f0e8   John W. Linville   geneve: implement...
776
  					   struct flowi6 *fl6,
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
777
  					   const struct ip_tunnel_info *info)
8ed66f0e8   John W. Linville   geneve: implement...
778
  {
db3c6139e   Daniel Borkmann   bpf, vxlan, genev...
779
  	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
8ed66f0e8   John W. Linville   geneve: implement...
780
  	struct geneve_dev *geneve = netdev_priv(dev);
8ed66f0e8   John W. Linville   geneve: implement...
781
  	struct dst_entry *dst = NULL;
468dfffcd   Paolo Abeni   geneve: add dst c...
782
  	struct dst_cache *dst_cache;
3a56f86f1   John W. Linville   geneve: handle ip...
783
  	__u8 prio;
8ed66f0e8   John W. Linville   geneve: implement...
784

fceb9c3e3   pravin shelar   geneve: avoid usi...
785
786
  	if (!gs6)
  		return ERR_PTR(-EIO);
8ed66f0e8   John W. Linville   geneve: implement...
787
788
789
  	memset(fl6, 0, sizeof(*fl6));
  	fl6->flowi6_mark = skb->mark;
  	fl6->flowi6_proto = IPPROTO_UDP;
9b4437a5b   pravin shelar   geneve: Unify LWT...
790
791
792
793
794
795
  	fl6->daddr = info->key.u.ipv6.dst;
  	fl6->saddr = info->key.u.ipv6.src;
  	prio = info->key.tos;
  	if ((prio == 1) && !geneve->collect_md) {
  		prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
  		use_cache = false;
468dfffcd   Paolo Abeni   geneve: add dst c...
796
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
797
798
  	fl6->flowlabel = ip6_make_flowinfo(RT_TOS(prio),
  					   info->key.label);
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
799
  	dst_cache = (struct dst_cache *)&info->dst_cache;
468dfffcd   Paolo Abeni   geneve: add dst c...
800
801
802
803
  	if (use_cache) {
  		dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
  		if (dst)
  			return dst;
8ed66f0e8   John W. Linville   geneve: implement...
804
  	}
6c8991f41   Sabrina Dubroca   net: ipv6_stub: u...
805
806
807
  	dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
  					      NULL);
  	if (IS_ERR(dst)) {
8ed66f0e8   John W. Linville   geneve: implement...
808
809
810
811
812
813
814
815
816
817
  		netdev_dbg(dev, "no route to %pI6
  ", &fl6->daddr);
  		return ERR_PTR(-ENETUNREACH);
  	}
  	if (dst->dev == dev) { /* is this necessary? */
  		netdev_dbg(dev, "circular route to %pI6
  ", &fl6->daddr);
  		dst_release(dst);
  		return ERR_PTR(-ELOOP);
  	}
468dfffcd   Paolo Abeni   geneve: add dst c...
818
819
  	if (use_cache)
  		dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
8ed66f0e8   John W. Linville   geneve: implement...
820
821
822
  	return dst;
  }
  #endif
9b4437a5b   pravin shelar   geneve: Unify LWT...
823
  static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
824
825
  			   struct geneve_dev *geneve,
  			   const struct ip_tunnel_info *info)
2d07dc79f   John W. Linville   geneve: add initi...
826
  {
9b4437a5b   pravin shelar   geneve: Unify LWT...
827
828
829
830
  	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
  	struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
  	const struct ip_tunnel_key *key = &info->key;
  	struct rtable *rt;
2d07dc79f   John W. Linville   geneve: add initi...
831
  	struct flowi4 fl4;
8760ce583   John W. Linville   geneve: allow use...
832
  	__u8 tos, ttl;
a025fb5f4   Stefano Brivio   geneve: Allow con...
833
  	__be16 df = 0;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
834
  	__be16 sport;
bcceeec3c   pravin shelar   geneve: Remove re...
835
  	int err;
980c394c5   Pravin B Shelar   geneve: Use skb m...
836

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
837
  	rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
9b4437a5b   pravin shelar   geneve: Unify LWT...
838
839
  	if (IS_ERR(rt))
  		return PTR_ERR(rt);
371bd1061   Pravin B Shelar   geneve: Consolida...
840

6b4f92af3   Stefano Brivio   geneve, vxlan: Do...
841
842
  	skb_tunnel_check_pmtu(skb, &rt->dst,
  			      GENEVE_IPV4_HLEN + info->options_len);
52a589d51   Xin Long   geneve: update sk...
843

371bd1061   Pravin B Shelar   geneve: Consolida...
844
  	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
9b4437a5b   pravin shelar   geneve: Unify LWT...
845
846
  	if (geneve->collect_md) {
  		tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
371bd1061   Pravin B Shelar   geneve: Consolida...
847
  		ttl = key->ttl;
a025fb5f4   Stefano Brivio   geneve: Allow con...
848
849
  
  		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
850
  	} else {
9b4437a5b   pravin shelar   geneve: Unify LWT...
851
  		tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb);
52d0d404d   Hangbin Liu   geneve: add ttl i...
852
853
854
855
856
  		if (geneve->ttl_inherit)
  			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
  		else
  			ttl = key->ttl;
  		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
a025fb5f4   Stefano Brivio   geneve: Allow con...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  
  		if (geneve->df == GENEVE_DF_SET) {
  			df = htons(IP_DF);
  		} else if (geneve->df == GENEVE_DF_INHERIT) {
  			struct ethhdr *eth = eth_hdr(skb);
  
  			if (ntohs(eth->h_proto) == ETH_P_IPV6) {
  				df = htons(IP_DF);
  			} else if (ntohs(eth->h_proto) == ETH_P_IP) {
  				struct iphdr *iph = ip_hdr(skb);
  
  				if (iph->frag_off & htons(IP_DF))
  					df = htons(IP_DF);
  			}
  		}
2d07dc79f   John W. Linville   geneve: add initi...
872
  	}
2d07dc79f   John W. Linville   geneve: add initi...
873

c3ef5aa5e   pravin shelar   geneve: Merge ipv...
874
  	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr));
9b4437a5b   pravin shelar   geneve: Unify LWT...
875
876
  	if (unlikely(err))
  		return err;
efeb2267b   Haishuang Yan   geneve: fix tx_er...
877

9b4437a5b   pravin shelar   geneve: Unify LWT...
878
879
880
881
882
  	udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
  			    tos, ttl, df, sport, geneve->info.key.tp_dst,
  			    !net_eq(geneve->net, dev_net(geneve->dev)),
  			    !(info->key.tun_flags & TUNNEL_CSUM));
  	return 0;
2d07dc79f   John W. Linville   geneve: add initi...
883
  }
8ed66f0e8   John W. Linville   geneve: implement...
884
  #if IS_ENABLED(CONFIG_IPV6)
9b4437a5b   pravin shelar   geneve: Unify LWT...
885
  static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
c3ef5aa5e   pravin shelar   geneve: Merge ipv...
886
887
  			    struct geneve_dev *geneve,
  			    const struct ip_tunnel_info *info)
8ed66f0e8   John W. Linville   geneve: implement...
888
  {
9b4437a5b   pravin shelar   geneve: Unify LWT...
889
890
891
  	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
  	struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
  	const struct ip_tunnel_key *key = &info->key;
8ed66f0e8   John W. Linville   geneve: implement...
892
  	struct dst_entry *dst = NULL;
8ed66f0e8   John W. Linville   geneve: implement...
893
  	struct flowi6 fl6;
3a56f86f1   John W. Linville   geneve: handle ip...
894
  	__u8 prio, ttl;
8ed66f0e8   John W. Linville   geneve: implement...
895
  	__be16 sport;
bcceeec3c   pravin shelar   geneve: Remove re...
896
  	int err;
8ed66f0e8   John W. Linville   geneve: implement...
897

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
898
  	dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
9b4437a5b   pravin shelar   geneve: Unify LWT...
899
900
  	if (IS_ERR(dst))
  		return PTR_ERR(dst);
8ed66f0e8   John W. Linville   geneve: implement...
901

6b4f92af3   Stefano Brivio   geneve, vxlan: Do...
902
  	skb_tunnel_check_pmtu(skb, dst, GENEVE_IPV6_HLEN + info->options_len);
52a589d51   Xin Long   geneve: update sk...
903

8ed66f0e8   John W. Linville   geneve: implement...
904
  	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
9b4437a5b   pravin shelar   geneve: Unify LWT...
905
906
907
908
909
910
  	if (geneve->collect_md) {
  		prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
  		ttl = key->ttl;
  	} else {
  		prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
  					   ip_hdr(skb), skb);
52d0d404d   Hangbin Liu   geneve: add ttl i...
911
912
913
914
915
  		if (geneve->ttl_inherit)
  			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
  		else
  			ttl = key->ttl;
  		ttl = ttl ? : ip6_dst_hoplimit(dst);
9b4437a5b   pravin shelar   geneve: Unify LWT...
916
  	}
31ac1c194   Haishuang Yan   geneve: fix ip_hd...
917
  	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr));
9b4437a5b   pravin shelar   geneve: Unify LWT...
918
919
  	if (unlikely(err))
  		return err;
8ed66f0e8   John W. Linville   geneve: implement...
920

9b4437a5b   pravin shelar   geneve: Unify LWT...
921
922
923
924
925
926
927
  	udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
  			     &fl6.saddr, &fl6.daddr, prio, ttl,
  			     info->key.label, sport, geneve->info.key.tp_dst,
  			     !(info->key.tun_flags & TUNNEL_CSUM));
  	return 0;
  }
  #endif
8ed66f0e8   John W. Linville   geneve: implement...
928

9b4437a5b   pravin shelar   geneve: Unify LWT...
929
930
931
932
933
  static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
  	struct ip_tunnel_info *info = NULL;
  	int err;
abe492b4f   Tom Herbert   geneve: UDP check...
934

9b4437a5b   pravin shelar   geneve: Unify LWT...
935
936
937
938
939
940
  	if (geneve->collect_md) {
  		info = skb_tunnel_info(skb);
  		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
  			err = -EINVAL;
  			netdev_dbg(dev, "no tunnel metadata
  ");
aed069df0   Alexander Duyck   ip_tunnel_core: i...
941
  			goto tx_error;
9b4437a5b   pravin shelar   geneve: Unify LWT...
942
  		}
8ed66f0e8   John W. Linville   geneve: implement...
943
  	} else {
9b4437a5b   pravin shelar   geneve: Unify LWT...
944
  		info = &geneve->info;
8ed66f0e8   John W. Linville   geneve: implement...
945
  	}
8eb3b9955   Daniel Borkmann   geneve: support s...
946

a717e3f74   Jakub Kicinski   geneve: lock RCU ...
947
  	rcu_read_lock();
9b4437a5b   pravin shelar   geneve: Unify LWT...
948
949
950
951
952
953
  #if IS_ENABLED(CONFIG_IPV6)
  	if (info->mode & IP_TUNNEL_INFO_IPV6)
  		err = geneve6_xmit_skb(skb, dev, geneve, info);
  	else
  #endif
  		err = geneve_xmit_skb(skb, dev, geneve, info);
a717e3f74   Jakub Kicinski   geneve: lock RCU ...
954
  	rcu_read_unlock();
8ed66f0e8   John W. Linville   geneve: implement...
955

9b4437a5b   pravin shelar   geneve: Unify LWT...
956
957
  	if (likely(!err))
  		return NETDEV_TX_OK;
8ed66f0e8   John W. Linville   geneve: implement...
958
959
  tx_error:
  	dev_kfree_skb(skb);
aed069df0   Alexander Duyck   ip_tunnel_core: i...
960

8ed66f0e8   John W. Linville   geneve: implement...
961
962
963
964
  	if (err == -ELOOP)
  		dev->stats.collisions++;
  	else if (err == -ENETUNREACH)
  		dev->stats.tx_carrier_errors++;
efeb2267b   Haishuang Yan   geneve: fix tx_er...
965
966
  
  	dev->stats.tx_errors++;
8ed66f0e8   John W. Linville   geneve: implement...
967
968
  	return NETDEV_TX_OK;
  }
8ed66f0e8   John W. Linville   geneve: implement...
969

91572088e   Jarod Wilson   net: use core MTU...
970
  static int geneve_change_mtu(struct net_device *dev, int new_mtu)
55e5bfb53   David Wragg   geneve: Relax MTU...
971
  {
91572088e   Jarod Wilson   net: use core MTU...
972
973
  	if (new_mtu > dev->max_mtu)
  		new_mtu = dev->max_mtu;
321acc1c6   Alexey Kodanev   geneve: check MTU...
974
975
  	else if (new_mtu < dev->min_mtu)
  		new_mtu = dev->min_mtu;
aeee0e66c   David Wragg   geneve: Refine MT...
976

55e5bfb53   David Wragg   geneve: Relax MTU...
977
978
979
  	dev->mtu = new_mtu;
  	return 0;
  }
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
980
981
982
983
  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
  {
  	struct ip_tunnel_info *info = skb_tunnel_info(skb);
  	struct geneve_dev *geneve = netdev_priv(dev);
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
984

b8812fa88   John W. Linville   geneve: add IPv6 ...
985
  	if (ip_tunnel_info_af(info) == AF_INET) {
9b4437a5b   pravin shelar   geneve: Unify LWT...
986
987
  		struct rtable *rt;
  		struct flowi4 fl4;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
988
  		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
9b4437a5b   pravin shelar   geneve: Unify LWT...
989

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
990
  		rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
b8812fa88   John W. Linville   geneve: add IPv6 ...
991
992
  		if (IS_ERR(rt))
  			return PTR_ERR(rt);
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
993

b8812fa88   John W. Linville   geneve: add IPv6 ...
994
995
996
997
  		ip_rt_put(rt);
  		info->key.u.ipv4.src = fl4.saddr;
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (ip_tunnel_info_af(info) == AF_INET6) {
9b4437a5b   pravin shelar   geneve: Unify LWT...
998
999
  		struct dst_entry *dst;
  		struct flowi6 fl6;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1000
  		struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1001

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1002
  		dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
b8812fa88   John W. Linville   geneve: add IPv6 ...
1003
1004
1005
1006
1007
1008
1009
1010
1011
  		if (IS_ERR(dst))
  			return PTR_ERR(dst);
  
  		dst_release(dst);
  		info->key.u.ipv6.src = fl6.saddr;
  #endif
  	} else {
  		return -EINVAL;
  	}
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
1012

fc4099f17   Pravin B Shelar   openvswitch: Fix ...
1013
1014
  	info->key.tp_src = udp_flow_src_port(geneve->net, skb,
  					     1, USHRT_MAX, true);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1015
  	info->key.tp_dst = geneve->info.key.tp_dst;
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
1016
1017
  	return 0;
  }
2d07dc79f   John W. Linville   geneve: add initi...
1018
1019
1020
1021
1022
1023
1024
  static const struct net_device_ops geneve_netdev_ops = {
  	.ndo_init		= geneve_init,
  	.ndo_uninit		= geneve_uninit,
  	.ndo_open		= geneve_open,
  	.ndo_stop		= geneve_stop,
  	.ndo_start_xmit		= geneve_xmit,
  	.ndo_get_stats64	= ip_tunnel_get_stats64,
55e5bfb53   David Wragg   geneve: Relax MTU...
1025
  	.ndo_change_mtu		= geneve_change_mtu,
2d07dc79f   John W. Linville   geneve: add initi...
1026
1027
  	.ndo_validate_addr	= eth_validate_addr,
  	.ndo_set_mac_address	= eth_mac_addr,
fc4099f17   Pravin B Shelar   openvswitch: Fix ...
1028
  	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst,
2d07dc79f   John W. Linville   geneve: add initi...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
  };
  
  static void geneve_get_drvinfo(struct net_device *dev,
  			       struct ethtool_drvinfo *drvinfo)
  {
  	strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
  	strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
  }
  
  static const struct ethtool_ops geneve_ethtool_ops = {
  	.get_drvinfo	= geneve_get_drvinfo,
  	.get_link	= ethtool_op_get_link,
  };
  
  /* Info for udev, that this is a virtual tunnel endpoint */
  static struct device_type geneve_type = {
  	.name = "geneve",
  };
e5de25dce   Sabrina Dubroca   drivers/net: fixu...
1047
  /* Calls the ndo_udp_tunnel_add of the caller in order to
05ca4029b   Singhai, Anjali   geneve: Add genev...
1048
   * supply the listening GENEVE udp ports. Callers are expected
e5de25dce   Sabrina Dubroca   drivers/net: fixu...
1049
   * to implement the ndo_udp_tunnel_add.
05ca4029b   Singhai, Anjali   geneve: Add genev...
1050
   */
2d2b13fcf   Sabrina Dubroca   geneve/vxlan: add...
1051
  static void geneve_offload_rx_ports(struct net_device *dev, bool push)
05ca4029b   Singhai, Anjali   geneve: Add genev...
1052
1053
1054
1055
  {
  	struct net *net = dev_net(dev);
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
  	struct geneve_sock *gs;
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1056

05ca4029b   Singhai, Anjali   geneve: Add genev...
1057
  	rcu_read_lock();
2d2b13fcf   Sabrina Dubroca   geneve/vxlan: add...
1058
1059
1060
1061
1062
1063
1064
1065
1066
  	list_for_each_entry_rcu(gs, &gn->sock_list, list) {
  		if (push) {
  			udp_tunnel_push_rx_port(dev, gs->sock,
  						UDP_TUNNEL_TYPE_GENEVE);
  		} else {
  			udp_tunnel_drop_rx_port(dev, gs->sock,
  						UDP_TUNNEL_TYPE_GENEVE);
  		}
  	}
05ca4029b   Singhai, Anjali   geneve: Add genev...
1067
1068
  	rcu_read_unlock();
  }
05ca4029b   Singhai, Anjali   geneve: Add genev...
1069

2d07dc79f   John W. Linville   geneve: add initi...
1070
1071
1072
1073
1074
1075
1076
  /* Initialize the device structure. */
  static void geneve_setup(struct net_device *dev)
  {
  	ether_setup(dev);
  
  	dev->netdev_ops = &geneve_netdev_ops;
  	dev->ethtool_ops = &geneve_ethtool_ops;
cf124db56   David S. Miller   net: Fix inconsis...
1077
  	dev->needs_free_netdev = true;
2d07dc79f   John W. Linville   geneve: add initi...
1078
1079
  
  	SET_NETDEV_DEVTYPE(dev, &geneve_type);
2d07dc79f   John W. Linville   geneve: add initi...
1080
1081
1082
1083
  	dev->features    |= NETIF_F_LLTX;
  	dev->features    |= NETIF_F_SG | NETIF_F_HW_CSUM;
  	dev->features    |= NETIF_F_RXCSUM;
  	dev->features    |= NETIF_F_GSO_SOFTWARE;
2d07dc79f   John W. Linville   geneve: add initi...
1084
1085
  	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
  	dev->hw_features |= NETIF_F_GSO_SOFTWARE;
2d07dc79f   John W. Linville   geneve: add initi...
1086

91572088e   Jarod Wilson   net: use core MTU...
1087
1088
1089
1090
1091
1092
1093
  	/* MTU range: 68 - (something less than 65535) */
  	dev->min_mtu = ETH_MIN_MTU;
  	/* The max_mtu calculation does not take account of GENEVE
  	 * options, to avoid excluding potentially valid
  	 * configurations. This will be further reduced by IPvX hdr size.
  	 */
  	dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
2d07dc79f   John W. Linville   geneve: add initi...
1094
  	netif_keep_dst(dev);
fc41cdb32   Jiri Benc   geneve: clear IFF...
1095
  	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
ed961ac23   Phil Sutter   net: geneve: conv...
1096
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
87cd3dcaf   Pravin B Shelar   geneve: Initializ...
1097
  	eth_hw_addr_random(dev);
2d07dc79f   John W. Linville   geneve: add initi...
1098
1099
1100
1101
  }
  
  static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
  	[IFLA_GENEVE_ID]		= { .type = NLA_U32 },
c593642c8   Pankaj Bharadiya   treewide: Use siz...
1102
  	[IFLA_GENEVE_REMOTE]		= { .len = sizeof_field(struct iphdr, daddr) },
8ed66f0e8   John W. Linville   geneve: implement...
1103
  	[IFLA_GENEVE_REMOTE6]		= { .len = sizeof(struct in6_addr) },
8760ce583   John W. Linville   geneve: allow use...
1104
  	[IFLA_GENEVE_TTL]		= { .type = NLA_U8 },
d89511251   John W. Linville   geneve: allow use...
1105
  	[IFLA_GENEVE_TOS]		= { .type = NLA_U8 },
8eb3b9955   Daniel Borkmann   geneve: support s...
1106
  	[IFLA_GENEVE_LABEL]		= { .type = NLA_U32 },
cd7918b35   Pravin B Shelar   geneve: Make dst-...
1107
  	[IFLA_GENEVE_PORT]		= { .type = NLA_U16 },
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1108
  	[IFLA_GENEVE_COLLECT_METADATA]	= { .type = NLA_FLAG },
abe492b4f   Tom Herbert   geneve: UDP check...
1109
1110
1111
  	[IFLA_GENEVE_UDP_CSUM]		= { .type = NLA_U8 },
  	[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]	= { .type = NLA_U8 },
  	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
52d0d404d   Hangbin Liu   geneve: add ttl i...
1112
  	[IFLA_GENEVE_TTL_INHERIT]	= { .type = NLA_U8 },
a025fb5f4   Stefano Brivio   geneve: Allow con...
1113
  	[IFLA_GENEVE_DF]		= { .type = NLA_U8 },
2d07dc79f   John W. Linville   geneve: add initi...
1114
  };
a8b8a889e   Matthias Schiffer   net: add netlink_...
1115
1116
  static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
  			   struct netlink_ext_ack *extack)
2d07dc79f   John W. Linville   geneve: add initi...
1117
1118
  {
  	if (tb[IFLA_ADDRESS]) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1119
1120
1121
  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
  			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
  					    "Provided link layer address is not Ethernet");
2d07dc79f   John W. Linville   geneve: add initi...
1122
  			return -EINVAL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1123
  		}
2d07dc79f   John W. Linville   geneve: add initi...
1124

c5ebc4409   Girish Moodalbail   geneve: use netli...
1125
1126
1127
  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
  			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
  					    "Provided Ethernet address is not unicast");
2d07dc79f   John W. Linville   geneve: add initi...
1128
  			return -EADDRNOTAVAIL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1129
  		}
2d07dc79f   John W. Linville   geneve: add initi...
1130
  	}
c5ebc4409   Girish Moodalbail   geneve: use netli...
1131
1132
1133
  	if (!data) {
  		NL_SET_ERR_MSG(extack,
  			       "Not enough attributes provided to perform the operation");
2d07dc79f   John W. Linville   geneve: add initi...
1134
  		return -EINVAL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1135
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1136
1137
1138
  
  	if (data[IFLA_GENEVE_ID]) {
  		__u32 vni =  nla_get_u32(data[IFLA_GENEVE_ID]);
c5ebc4409   Girish Moodalbail   geneve: use netli...
1139
1140
1141
  		if (vni >= GENEVE_N_VID) {
  			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID],
  					    "Geneve ID must be lower than 16777216");
2d07dc79f   John W. Linville   geneve: add initi...
1142
  			return -ERANGE;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1143
  		}
2d07dc79f   John W. Linville   geneve: add initi...
1144
  	}
a025fb5f4   Stefano Brivio   geneve: Allow con...
1145
1146
1147
1148
1149
1150
1151
1152
1153
  	if (data[IFLA_GENEVE_DF]) {
  		enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
  
  		if (df < 0 || df > GENEVE_DF_MAX) {
  			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_GENEVE_DF],
  					    "Invalid DF attribute");
  			return -EINVAL;
  		}
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1154
1155
  	return 0;
  }
371bd1061   Pravin B Shelar   geneve: Consolida...
1156
  static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
9b4437a5b   pravin shelar   geneve: Unify LWT...
1157
  					  const struct ip_tunnel_info *info,
371bd1061   Pravin B Shelar   geneve: Consolida...
1158
1159
1160
  					  bool *tun_on_same_port,
  					  bool *tun_collect_md)
  {
9b4437a5b   pravin shelar   geneve: Unify LWT...
1161
  	struct geneve_dev *geneve, *t = NULL;
371bd1061   Pravin B Shelar   geneve: Consolida...
1162
1163
1164
  
  	*tun_on_same_port = false;
  	*tun_collect_md = false;
371bd1061   Pravin B Shelar   geneve: Consolida...
1165
  	list_for_each_entry(geneve, &gn->geneve_list, next) {
9b4437a5b   pravin shelar   geneve: Unify LWT...
1166
  		if (info->key.tp_dst == geneve->info.key.tp_dst) {
371bd1061   Pravin B Shelar   geneve: Consolida...
1167
1168
1169
  			*tun_collect_md = geneve->collect_md;
  			*tun_on_same_port = true;
  		}
9b4437a5b   pravin shelar   geneve: Unify LWT...
1170
1171
1172
  		if (info->key.tun_id == geneve->info.key.tun_id &&
  		    info->key.tp_dst == geneve->info.key.tp_dst &&
  		    !memcmp(&info->key.u, &geneve->info.key.u, sizeof(info->key.u)))
371bd1061   Pravin B Shelar   geneve: Consolida...
1173
1174
1175
1176
  			t = geneve;
  	}
  	return t;
  }
9b4437a5b   pravin shelar   geneve: Unify LWT...
1177
1178
  static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
  {
3fa5f11de   Stefano Brivio   geneve: Get rid o...
1179
1180
1181
  	return !(info->key.tun_id || info->key.tun_flags || info->key.tos ||
  		 info->key.ttl || info->key.label || info->key.tp_src ||
  		 memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
9b4437a5b   pravin shelar   geneve: Unify LWT...
1182
  }
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1183
1184
1185
1186
1187
1188
1189
1190
  static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
  				  struct ip_tunnel_info *b)
  {
  	if (ip_tunnel_info_af(a) == AF_INET)
  		return a->key.u.ipv4.dst == b->key.u.ipv4.dst;
  	else
  		return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst);
  }
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1191
  static int geneve_configure(struct net *net, struct net_device *dev,
c5ebc4409   Girish Moodalbail   geneve: use netli...
1192
  			    struct netlink_ext_ack *extack,
9b4437a5b   pravin shelar   geneve: Unify LWT...
1193
  			    const struct ip_tunnel_info *info,
52d0d404d   Hangbin Liu   geneve: add ttl i...
1194
  			    bool metadata, bool ipv6_rx_csum,
a025fb5f4   Stefano Brivio   geneve: Allow con...
1195
  			    bool ttl_inherit, enum ifla_geneve_df df)
2d07dc79f   John W. Linville   geneve: add initi...
1196
1197
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
371bd1061   Pravin B Shelar   geneve: Consolida...
1198
1199
  	struct geneve_dev *t, *geneve = netdev_priv(dev);
  	bool tun_collect_md, tun_on_same_port;
184fc8b5e   Paolo Abeni   geneve: initializ...
1200
  	int err, encap_len;
2d07dc79f   John W. Linville   geneve: add initi...
1201

c5ebc4409   Girish Moodalbail   geneve: use netli...
1202
1203
1204
  	if (metadata && !is_tnl_info_zero(info)) {
  		NL_SET_ERR_MSG(extack,
  			       "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified");
8ed66f0e8   John W. Linville   geneve: implement...
1205
  		return -EINVAL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1206
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1207
1208
1209
  
  	geneve->net = net;
  	geneve->dev = dev;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1210
  	t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
371bd1061   Pravin B Shelar   geneve: Consolida...
1211
1212
  	if (t)
  		return -EBUSY;
184fc8b5e   Paolo Abeni   geneve: initializ...
1213
1214
  	/* make enough headroom for basic scenario */
  	encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
9a1c44d98   Eric Garver   geneve: fix neede...
1215
  	if (!metadata && ip_tunnel_info_af(info) == AF_INET) {
184fc8b5e   Paolo Abeni   geneve: initializ...
1216
  		encap_len += sizeof(struct iphdr);
91572088e   Jarod Wilson   net: use core MTU...
1217
1218
  		dev->max_mtu -= sizeof(struct iphdr);
  	} else {
184fc8b5e   Paolo Abeni   geneve: initializ...
1219
  		encap_len += sizeof(struct ipv6hdr);
91572088e   Jarod Wilson   net: use core MTU...
1220
1221
  		dev->max_mtu -= sizeof(struct ipv6hdr);
  	}
184fc8b5e   Paolo Abeni   geneve: initializ...
1222
  	dev->needed_headroom = encap_len + ETH_HLEN;
371bd1061   Pravin B Shelar   geneve: Consolida...
1223
  	if (metadata) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1224
1225
1226
  		if (tun_on_same_port) {
  			NL_SET_ERR_MSG(extack,
  				       "There can be only one externally controlled device on a destination port");
371bd1061   Pravin B Shelar   geneve: Consolida...
1227
  			return -EPERM;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1228
  		}
371bd1061   Pravin B Shelar   geneve: Consolida...
1229
  	} else {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1230
1231
1232
  		if (tun_collect_md) {
  			NL_SET_ERR_MSG(extack,
  				       "There already exists an externally controlled device on this destination port");
371bd1061   Pravin B Shelar   geneve: Consolida...
1233
  			return -EPERM;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1234
  		}
371bd1061   Pravin B Shelar   geneve: Consolida...
1235
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
1236
1237
1238
1239
  	dst_cache_reset(&geneve->info.dst_cache);
  	geneve->info = *info;
  	geneve->collect_md = metadata;
  	geneve->use_udp6_rx_checksums = ipv6_rx_csum;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1240
  	geneve->ttl_inherit = ttl_inherit;
a025fb5f4   Stefano Brivio   geneve: Allow con...
1241
  	geneve->df = df;
468dfffcd   Paolo Abeni   geneve: add dst c...
1242

2d07dc79f   John W. Linville   geneve: add initi...
1243
1244
1245
  	err = register_netdevice(dev);
  	if (err)
  		return err;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1246
  	list_add(&geneve->next, &gn->geneve_list);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1247
1248
  	return 0;
  }
9b4437a5b   pravin shelar   geneve: Unify LWT...
1249
1250
1251
1252
1253
  static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
  {
  	memset(info, 0, sizeof(*info));
  	info->key.tp_dst = htons(dst_port);
  }
c5ebc4409   Girish Moodalbail   geneve: use netli...
1254
1255
1256
  static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
  			  struct netlink_ext_ack *extack,
  			  struct ip_tunnel_info *info, bool *metadata,
52d0d404d   Hangbin Liu   geneve: add ttl i...
1257
  			  bool *use_udp6_rx_checksums, bool *ttl_inherit,
a025fb5f4   Stefano Brivio   geneve: Allow con...
1258
  			  enum ifla_geneve_df *df, bool changelink)
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1259
  {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1260
1261
1262
1263
1264
  	int attrtype;
  
  	if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
  		NL_SET_ERR_MSG(extack,
  			       "Cannot specify both IPv4 and IPv6 Remote addresses");
8ed66f0e8   John W. Linville   geneve: implement...
1265
  		return -EINVAL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1266
  	}
8ed66f0e8   John W. Linville   geneve: implement...
1267
1268
  
  	if (data[IFLA_GENEVE_REMOTE]) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1269
1270
1271
1272
  		if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
  			attrtype = IFLA_GENEVE_REMOTE;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1273
1274
  
  		info->key.u.ipv4.dst =
8ed66f0e8   John W. Linville   geneve: implement...
1275
  			nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1276

842841ece   Dave Taht   Convert usage of ...
1277
  		if (ipv4_is_multicast(info->key.u.ipv4.dst)) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1278
1279
  			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE],
  					    "Remote IPv4 address cannot be Multicast");
9b4437a5b   pravin shelar   geneve: Unify LWT...
1280
1281
  			return -EINVAL;
  		}
8ed66f0e8   John W. Linville   geneve: implement...
1282
1283
1284
  	}
  
  	if (data[IFLA_GENEVE_REMOTE6]) {
4c52a889a   Alexey Kodanev   geneve: remove wh...
1285
  #if IS_ENABLED(CONFIG_IPV6)
c5ebc4409   Girish Moodalbail   geneve: use netli...
1286
1287
1288
1289
  		if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
  			attrtype = IFLA_GENEVE_REMOTE6;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1290
1291
1292
  
  		info->mode = IP_TUNNEL_INFO_IPV6;
  		info->key.u.ipv6.dst =
8ed66f0e8   John W. Linville   geneve: implement...
1293
  			nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1294
  		if (ipv6_addr_type(&info->key.u.ipv6.dst) &
8ed66f0e8   John W. Linville   geneve: implement...
1295
  		    IPV6_ADDR_LINKLOCAL) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1296
1297
  			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
  					    "Remote IPv6 address cannot be link-local");
8ed66f0e8   John W. Linville   geneve: implement...
1298
1299
  			return -EINVAL;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1300
  		if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1301
1302
  			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
  					    "Remote IPv6 address cannot be Multicast");
9b4437a5b   pravin shelar   geneve: Unify LWT...
1303
1304
  			return -EINVAL;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1305
1306
  		info->key.tun_flags |= TUNNEL_CSUM;
  		*use_udp6_rx_checksums = true;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1307
  #else
c5ebc4409   Girish Moodalbail   geneve: use netli...
1308
1309
  		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
  				    "IPv6 support not enabled in the kernel");
9b4437a5b   pravin shelar   geneve: Unify LWT...
1310
1311
  		return -EPFNOSUPPORT;
  #endif
8ed66f0e8   John W. Linville   geneve: implement...
1312
  	}
9b4437a5b   pravin shelar   geneve: Unify LWT...
1313
1314
1315
  	if (data[IFLA_GENEVE_ID]) {
  		__u32 vni;
  		__u8 tvni[3];
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1316
  		__be64 tunid;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1317

e277de5f3   Jesse Gross   tunnels: Don't re...
1318
  		vni = nla_get_u32(data[IFLA_GENEVE_ID]);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1319
1320
1321
  		tvni[0] = (vni & 0x00ff0000) >> 16;
  		tvni[1] = (vni & 0x0000ff00) >> 8;
  		tvni[2] =  vni & 0x000000ff;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1322

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1323
  		tunid = vni_to_tunnel_id(tvni);
c5ebc4409   Girish Moodalbail   geneve: use netli...
1324
1325
1326
1327
  		if (changelink && (tunid != info->key.tun_id)) {
  			attrtype = IFLA_GENEVE_ID;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1328
  		info->key.tun_id = tunid;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1329
  	}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1330

a97d97bac   Hangbin Liu   geneve: allow to ...
1331
1332
1333
1334
1335
1336
  	if (data[IFLA_GENEVE_TTL_INHERIT]) {
  		if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT]))
  			*ttl_inherit = true;
  		else
  			*ttl_inherit = false;
  	} else if (data[IFLA_GENEVE_TTL]) {
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1337
  		info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
a97d97bac   Hangbin Liu   geneve: allow to ...
1338
1339
  		*ttl_inherit = false;
  	}
52d0d404d   Hangbin Liu   geneve: add ttl i...
1340

d89511251   John W. Linville   geneve: allow use...
1341
  	if (data[IFLA_GENEVE_TOS])
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1342
  		info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
d89511251   John W. Linville   geneve: allow use...
1343

a025fb5f4   Stefano Brivio   geneve: Allow con...
1344
1345
  	if (data[IFLA_GENEVE_DF])
  		*df = nla_get_u8(data[IFLA_GENEVE_DF]);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1346
  	if (data[IFLA_GENEVE_LABEL]) {
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1347
  		info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
9b4437a5b   pravin shelar   geneve: Unify LWT...
1348
  				  IPV6_FLOWLABEL_MASK;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1349
1350
1351
  		if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) {
  			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL],
  					    "Label attribute only applies for IPv6 Geneve devices");
9b4437a5b   pravin shelar   geneve: Unify LWT...
1352
  			return -EINVAL;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1353
  		}
9b4437a5b   pravin shelar   geneve: Unify LWT...
1354
  	}
8eb3b9955   Daniel Borkmann   geneve: support s...
1355

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1356
  	if (data[IFLA_GENEVE_PORT]) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1357
1358
1359
1360
  		if (changelink) {
  			attrtype = IFLA_GENEVE_PORT;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1361
1362
  		info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1363

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1364
  	if (data[IFLA_GENEVE_COLLECT_METADATA]) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1365
1366
1367
1368
  		if (changelink) {
  			attrtype = IFLA_GENEVE_COLLECT_METADATA;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1369
1370
  		*metadata = true;
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1371

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1372
  	if (data[IFLA_GENEVE_UDP_CSUM]) {
c5ebc4409   Girish Moodalbail   geneve: use netli...
1373
1374
1375
1376
  		if (changelink) {
  			attrtype = IFLA_GENEVE_UDP_CSUM;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1377
1378
1379
  		if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
  			info->key.tun_flags |= TUNNEL_CSUM;
  	}
abe492b4f   Tom Herbert   geneve: UDP check...
1380

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1381
  	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
f9094b760   Hangbin Liu   geneve: only conf...
1382
  #if IS_ENABLED(CONFIG_IPV6)
c5ebc4409   Girish Moodalbail   geneve: use netli...
1383
1384
1385
1386
  		if (changelink) {
  			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1387
1388
  		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
  			info->key.tun_flags &= ~TUNNEL_CSUM;
f9094b760   Hangbin Liu   geneve: only conf...
1389
1390
1391
1392
1393
  #else
  		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX],
  				    "IPv6 support not enabled in the kernel");
  		return -EPFNOSUPPORT;
  #endif
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1394
  	}
abe492b4f   Tom Herbert   geneve: UDP check...
1395

5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1396
  	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
f9094b760   Hangbin Liu   geneve: only conf...
1397
  #if IS_ENABLED(CONFIG_IPV6)
c5ebc4409   Girish Moodalbail   geneve: use netli...
1398
1399
1400
1401
  		if (changelink) {
  			attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX;
  			goto change_notsup;
  		}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1402
1403
  		if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
  			*use_udp6_rx_checksums = false;
f9094b760   Hangbin Liu   geneve: only conf...
1404
1405
1406
1407
1408
  #else
  		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX],
  				    "IPv6 support not enabled in the kernel");
  		return -EPFNOSUPPORT;
  #endif
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1409
1410
1411
  	}
  
  	return 0;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1412
1413
1414
1415
  change_notsup:
  	NL_SET_ERR_MSG_ATTR(extack, data[attrtype],
  			    "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported");
  	return -EOPNOTSUPP;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1416
  }
c40e89fd3   Alexey Kodanev   geneve: configure...
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  static void geneve_link_config(struct net_device *dev,
  			       struct ip_tunnel_info *info, struct nlattr *tb[])
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
  	int ldev_mtu = 0;
  
  	if (tb[IFLA_MTU]) {
  		geneve_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
  		return;
  	}
  
  	switch (ip_tunnel_info_af(info)) {
  	case AF_INET: {
  		struct flowi4 fl4 = { .daddr = info->key.u.ipv4.dst };
  		struct rtable *rt = ip_route_output_key(geneve->net, &fl4);
  
  		if (!IS_ERR(rt) && rt->dst.dev) {
  			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV4_HLEN;
  			ip_rt_put(rt);
  		}
  		break;
  	}
  #if IS_ENABLED(CONFIG_IPV6)
  	case AF_INET6: {
c0a47e44c   Hangbin Liu   geneve: should no...
1441
1442
1443
1444
1445
1446
1447
  		struct rt6_info *rt;
  
  		if (!__in6_dev_get(dev))
  			break;
  
  		rt = rt6_lookup(geneve->net, &info->key.u.ipv6.dst, NULL, 0,
  				NULL, 0);
c40e89fd3   Alexey Kodanev   geneve: configure...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  
  		if (rt && rt->dst.dev)
  			ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV6_HLEN;
  		ip6_rt_put(rt);
  		break;
  	}
  #endif
  	}
  
  	if (ldev_mtu <= 0)
  		return;
  
  	geneve_change_mtu(dev, ldev_mtu - info->options_len);
  }
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1462
1463
1464
1465
  static int geneve_newlink(struct net *net, struct net_device *dev,
  			  struct nlattr *tb[], struct nlattr *data[],
  			  struct netlink_ext_ack *extack)
  {
a025fb5f4   Stefano Brivio   geneve: Allow con...
1466
  	enum ifla_geneve_df df = GENEVE_DF_UNSET;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1467
1468
  	bool use_udp6_rx_checksums = false;
  	struct ip_tunnel_info info;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1469
  	bool ttl_inherit = false;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1470
1471
1472
1473
  	bool metadata = false;
  	int err;
  
  	init_tnl_info(&info, GENEVE_UDP_PORT);
c5ebc4409   Girish Moodalbail   geneve: use netli...
1474
  	err = geneve_nl2info(tb, data, extack, &info, &metadata,
a025fb5f4   Stefano Brivio   geneve: Allow con...
1475
  			     &use_udp6_rx_checksums, &ttl_inherit, &df, false);
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1476
1477
  	if (err)
  		return err;
abe492b4f   Tom Herbert   geneve: UDP check...
1478

c40e89fd3   Alexey Kodanev   geneve: configure...
1479
  	err = geneve_configure(net, dev, extack, &info, metadata,
a025fb5f4   Stefano Brivio   geneve: Allow con...
1480
  			       use_udp6_rx_checksums, ttl_inherit, df);
c40e89fd3   Alexey Kodanev   geneve: configure...
1481
1482
1483
1484
1485
1486
  	if (err)
  		return err;
  
  	geneve_link_config(dev, &info, tb);
  
  	return 0;
2d07dc79f   John W. Linville   geneve: add initi...
1487
  }
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
  /* Quiesces the geneve device data path for both TX and RX.
   *
   * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
   * So, if we set that socket to NULL under RCU and wait for synchronize_net()
   * to complete for the existing set of in-flight packets to be transmitted,
   * then we would have quiesced the transmit data path. All the future packets
   * will get dropped until we unquiesce the data path.
   *
   * On receive geneve dereference the geneve_sock stashed in the socket. So,
   * if we set that to NULL under RCU and wait for synchronize_net() to
   * complete, then we would have quiesced the receive data path.
   */
  static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
  			   struct geneve_sock **gs6)
  {
  	*gs4 = rtnl_dereference(geneve->sock4);
  	rcu_assign_pointer(geneve->sock4, NULL);
  	if (*gs4)
  		rcu_assign_sk_user_data((*gs4)->sock->sk, NULL);
  #if IS_ENABLED(CONFIG_IPV6)
  	*gs6 = rtnl_dereference(geneve->sock6);
  	rcu_assign_pointer(geneve->sock6, NULL);
  	if (*gs6)
  		rcu_assign_sk_user_data((*gs6)->sock->sk, NULL);
  #else
  	*gs6 = NULL;
  #endif
  	synchronize_net();
  }
  
  /* Resumes the geneve device data path for both TX and RX. */
  static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
  			     struct geneve_sock __maybe_unused *gs6)
  {
  	rcu_assign_pointer(geneve->sock4, gs4);
  	if (gs4)
  		rcu_assign_sk_user_data(gs4->sock->sk, gs4);
  #if IS_ENABLED(CONFIG_IPV6)
  	rcu_assign_pointer(geneve->sock6, gs6);
  	if (gs6)
  		rcu_assign_sk_user_data(gs6->sock->sk, gs6);
  #endif
  	synchronize_net();
  }
  
  static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
  			     struct nlattr *data[],
  			     struct netlink_ext_ack *extack)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
  	struct geneve_sock *gs4, *gs6;
  	struct ip_tunnel_info info;
  	bool metadata;
  	bool use_udp6_rx_checksums;
a025fb5f4   Stefano Brivio   geneve: Allow con...
1542
  	enum ifla_geneve_df df;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1543
  	bool ttl_inherit;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
  	int err;
  
  	/* If the geneve device is configured for metadata (or externally
  	 * controlled, for example, OVS), then nothing can be changed.
  	 */
  	if (geneve->collect_md)
  		return -EOPNOTSUPP;
  
  	/* Start with the existing info. */
  	memcpy(&info, &geneve->info, sizeof(info));
  	metadata = geneve->collect_md;
  	use_udp6_rx_checksums = geneve->use_udp6_rx_checksums;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1556
  	ttl_inherit = geneve->ttl_inherit;
c5ebc4409   Girish Moodalbail   geneve: use netli...
1557
  	err = geneve_nl2info(tb, data, extack, &info, &metadata,
a025fb5f4   Stefano Brivio   geneve: Allow con...
1558
  			     &use_udp6_rx_checksums, &ttl_inherit, &df, true);
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1559
1560
  	if (err)
  		return err;
c40e89fd3   Alexey Kodanev   geneve: configure...
1561
  	if (!geneve_dst_addr_equal(&geneve->info, &info)) {
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1562
  		dst_cache_reset(&info.dst_cache);
c40e89fd3   Alexey Kodanev   geneve: configure...
1563
1564
  		geneve_link_config(dev, &info, tb);
  	}
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1565
1566
1567
1568
1569
  
  	geneve_quiesce(geneve, &gs4, &gs6);
  	geneve->info = info;
  	geneve->collect_md = metadata;
  	geneve->use_udp6_rx_checksums = use_udp6_rx_checksums;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1570
  	geneve->ttl_inherit = ttl_inherit;
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1571
1572
1573
1574
  	geneve_unquiesce(geneve, gs4, gs6);
  
  	return 0;
  }
2d07dc79f   John W. Linville   geneve: add initi...
1575
1576
1577
  static void geneve_dellink(struct net_device *dev, struct list_head *head)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
2d07dc79f   John W. Linville   geneve: add initi...
1578
1579
1580
1581
1582
1583
1584
  	list_del(&geneve->next);
  	unregister_netdevice_queue(dev, head);
  }
  
  static size_t geneve_get_size(const struct net_device *dev)
  {
  	return nla_total_size(sizeof(__u32)) +	/* IFLA_GENEVE_ID */
8ed66f0e8   John W. Linville   geneve: implement...
1585
  		nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
8760ce583   John W. Linville   geneve: allow use...
1586
  		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */
d89511251   John W. Linville   geneve: allow use...
1587
  		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
a025fb5f4   Stefano Brivio   geneve: Allow con...
1588
  		nla_total_size(sizeof(__u8)) +	/* IFLA_GENEVE_DF */
8eb3b9955   Daniel Borkmann   geneve: support s...
1589
  		nla_total_size(sizeof(__be32)) +  /* IFLA_GENEVE_LABEL */
7bbe33ff1   John W. Linville   geneve: use netwo...
1590
  		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1591
  		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */
abe492b4f   Tom Herbert   geneve: UDP check...
1592
1593
1594
  		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
  		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
  		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
52d0d404d   Hangbin Liu   geneve: add ttl i...
1595
  		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */
2d07dc79f   John W. Linville   geneve: add initi...
1596
1597
1598
1599
1600
1601
  		0;
  }
  
  static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct geneve_dev *geneve = netdev_priv(dev);
9b4437a5b   pravin shelar   geneve: Unify LWT...
1602
  	struct ip_tunnel_info *info = &geneve->info;
52d0d404d   Hangbin Liu   geneve: add ttl i...
1603
  	bool ttl_inherit = geneve->ttl_inherit;
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1604
  	bool metadata = geneve->collect_md;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1605
  	__u8 tmp_vni[3];
2d07dc79f   John W. Linville   geneve: add initi...
1606
  	__u32 vni;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1607
1608
  	tunnel_id_to_vni(info->key.tun_id, tmp_vni);
  	vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2];
2d07dc79f   John W. Linville   geneve: add initi...
1609
1610
  	if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
  		goto nla_put_failure;
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1611
  	if (!metadata && ip_tunnel_info_af(info) == AF_INET) {
8ed66f0e8   John W. Linville   geneve: implement...
1612
  		if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
9b4437a5b   pravin shelar   geneve: Unify LWT...
1613
1614
  				    info->key.u.ipv4.dst))
  			goto nla_put_failure;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1615
1616
  		if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
  			       !!(info->key.tun_flags & TUNNEL_CSUM)))
8ed66f0e8   John W. Linville   geneve: implement...
1617
  			goto nla_put_failure;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1618

8ed66f0e8   John W. Linville   geneve: implement...
1619
  #if IS_ENABLED(CONFIG_IPV6)
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1620
  	} else if (!metadata) {
8ed66f0e8   John W. Linville   geneve: implement...
1621
  		if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
9b4437a5b   pravin shelar   geneve: Unify LWT...
1622
1623
  				     &info->key.u.ipv6.dst))
  			goto nla_put_failure;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1624
1625
1626
  		if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
  			       !(info->key.tun_flags & TUNNEL_CSUM)))
  			goto nla_put_failure;
11387fe4a   Eric Garver   geneve: fix fill_...
1627
  #endif
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1628
  	}
2d07dc79f   John W. Linville   geneve: add initi...
1629

9b4437a5b   pravin shelar   geneve: Unify LWT...
1630
1631
1632
  	if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
  	    nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
  	    nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
8760ce583   John W. Linville   geneve: allow use...
1633
  		goto nla_put_failure;
a025fb5f4   Stefano Brivio   geneve: Allow con...
1634
1635
  	if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->df))
  		goto nla_put_failure;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1636
  	if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
cd7918b35   Pravin B Shelar   geneve: Make dst-...
1637
  		goto nla_put_failure;
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1638
  	if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA))
f9094b760   Hangbin Liu   geneve: only conf...
1639
  		goto nla_put_failure;
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1640

f9094b760   Hangbin Liu   geneve: only conf...
1641
  #if IS_ENABLED(CONFIG_IPV6)
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1642
1643
1644
  	if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
  		       !geneve->use_udp6_rx_checksums))
  		goto nla_put_failure;
f9094b760   Hangbin Liu   geneve: only conf...
1645
  #endif
fd7eafd02   Hangbin Liu   geneve: fix fill_...
1646

52d0d404d   Hangbin Liu   geneve: add ttl i...
1647
1648
  	if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
  		goto nla_put_failure;
2d07dc79f   John W. Linville   geneve: add initi...
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static struct rtnl_link_ops geneve_link_ops __read_mostly = {
  	.kind		= "geneve",
  	.maxtype	= IFLA_GENEVE_MAX,
  	.policy		= geneve_policy,
  	.priv_size	= sizeof(struct geneve_dev),
  	.setup		= geneve_setup,
  	.validate	= geneve_validate,
  	.newlink	= geneve_newlink,
5b861f6ba   Girish Moodalbail   geneve: add rtnl ...
1663
  	.changelink	= geneve_changelink,
2d07dc79f   John W. Linville   geneve: add initi...
1664
1665
1666
1667
  	.dellink	= geneve_dellink,
  	.get_size	= geneve_get_size,
  	.fill_info	= geneve_fill_info,
  };
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1668
1669
1670
1671
  struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
  					u8 name_assign_type, u16 dst_port)
  {
  	struct nlattr *tb[IFLA_MAX + 1];
9b4437a5b   pravin shelar   geneve: Unify LWT...
1672
  	struct ip_tunnel_info info;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1673
  	struct net_device *dev;
106da663f   Nicolas Dichtel   ovs/gre,geneve: f...
1674
  	LIST_HEAD(list_kill);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1675
1676
1677
1678
  	int err;
  
  	memset(tb, 0, sizeof(tb));
  	dev = rtnl_create_link(net, name, name_assign_type,
d0522f1cd   David Ahern   net: Add extack a...
1679
  			       &geneve_link_ops, tb, NULL);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1680
1681
  	if (IS_ERR(dev))
  		return dev;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1682
  	init_tnl_info(&info, dst_port);
a025fb5f4   Stefano Brivio   geneve: Allow con...
1683
1684
  	err = geneve_configure(net, dev, NULL, &info,
  			       true, true, false, GENEVE_DF_UNSET);
106da663f   Nicolas Dichtel   ovs/gre,geneve: f...
1685
1686
1687
1688
  	if (err) {
  		free_netdev(dev);
  		return ERR_PTR(err);
  	}
7e059158d   David Wragg   vxlan, gre, genev...
1689
1690
1691
1692
  
  	/* openvswitch users expect packet sizes to be unrestricted,
  	 * so set the largest MTU we can.
  	 */
91572088e   Jarod Wilson   net: use core MTU...
1693
  	err = geneve_change_mtu(dev, IP_MAX_MTU);
7e059158d   David Wragg   vxlan, gre, genev...
1694
1695
  	if (err)
  		goto err;
41009481b   Nicolas Dichtel   ovs/geneve: fix r...
1696
1697
1698
  	err = rtnl_configure_link(dev, NULL);
  	if (err < 0)
  		goto err;
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1699
  	return dev;
9b4437a5b   pravin shelar   geneve: Unify LWT...
1700
  err:
106da663f   Nicolas Dichtel   ovs/gre,geneve: f...
1701
1702
  	geneve_dellink(dev, &list_kill);
  	unregister_netdevice_many(&list_kill);
7e059158d   David Wragg   vxlan, gre, genev...
1703
  	return ERR_PTR(err);
e305ac6cf   Pravin B Shelar   geneve: Add suppo...
1704
1705
  }
  EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1706
1707
1708
1709
  static int geneve_netdevice_event(struct notifier_block *unused,
  				  unsigned long event, void *ptr)
  {
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
2d2b13fcf   Sabrina Dubroca   geneve/vxlan: add...
1710
  	if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
04584957b   Sabrina Dubroca   geneve/vxlan: off...
1711
  	    event == NETDEV_UDP_TUNNEL_DROP_INFO) {
2d2b13fcf   Sabrina Dubroca   geneve/vxlan: add...
1712
  		geneve_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
04584957b   Sabrina Dubroca   geneve/vxlan: off...
1713
1714
1715
1716
1717
  	} else if (event == NETDEV_UNREGISTER) {
  		geneve_offload_rx_ports(dev, false);
  	} else if (event == NETDEV_REGISTER) {
  		geneve_offload_rx_ports(dev, true);
  	}
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1718
1719
1720
1721
1722
1723
1724
  
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block geneve_notifier_block __read_mostly = {
  	.notifier_call = geneve_netdevice_event,
  };
2d07dc79f   John W. Linville   geneve: add initi...
1725
1726
1727
  static __net_init int geneve_init_net(struct net *net)
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
2d07dc79f   John W. Linville   geneve: add initi...
1728
1729
  
  	INIT_LIST_HEAD(&gn->geneve_list);
371bd1061   Pravin B Shelar   geneve: Consolida...
1730
  	INIT_LIST_HEAD(&gn->sock_list);
2d07dc79f   John W. Linville   geneve: add initi...
1731
1732
  	return 0;
  }
2843a2534   Haishuang Yan   geneve: speedup g...
1733
  static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
2d07dc79f   John W. Linville   geneve: add initi...
1734
1735
1736
1737
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
  	struct geneve_dev *geneve, *next;
  	struct net_device *dev, *aux;
2d07dc79f   John W. Linville   geneve: add initi...
1738
1739
1740
1741
  
  	/* gather any geneve devices that were moved into this ns */
  	for_each_netdev_safe(net, dev, aux)
  		if (dev->rtnl_link_ops == &geneve_link_ops)
2843a2534   Haishuang Yan   geneve: speedup g...
1742
  			unregister_netdevice_queue(dev, head);
2d07dc79f   John W. Linville   geneve: add initi...
1743
1744
1745
1746
1747
1748
1749
  
  	/* now gather any other geneve devices that were created in this ns */
  	list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) {
  		/* If geneve->dev is in the same netns, it was already added
  		 * to the list by the previous loop.
  		 */
  		if (!net_eq(dev_net(geneve->dev), net))
2843a2534   Haishuang Yan   geneve: speedup g...
1750
  			unregister_netdevice_queue(geneve->dev, head);
2d07dc79f   John W. Linville   geneve: add initi...
1751
  	}
2843a2534   Haishuang Yan   geneve: speedup g...
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
  	WARN_ON_ONCE(!list_empty(&gn->sock_list));
  }
  
  static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
  {
  	struct net *net;
  	LIST_HEAD(list);
  
  	rtnl_lock();
  	list_for_each_entry(net, net_list, exit_list)
  		geneve_destroy_tunnels(net, &list);
2d07dc79f   John W. Linville   geneve: add initi...
1763
1764
1765
1766
1767
1768
1769
  	/* unregister the devices gathered above */
  	unregister_netdevice_many(&list);
  	rtnl_unlock();
  }
  
  static struct pernet_operations geneve_net_ops = {
  	.init = geneve_init_net,
2843a2534   Haishuang Yan   geneve: speedup g...
1770
  	.exit_batch = geneve_exit_batch_net,
2d07dc79f   John W. Linville   geneve: add initi...
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
  	.id   = &geneve_net_id,
  	.size = sizeof(struct geneve_net),
  };
  
  static int __init geneve_init_module(void)
  {
  	int rc;
  
  	rc = register_pernet_subsys(&geneve_net_ops);
  	if (rc)
  		goto out1;
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1782
  	rc = register_netdevice_notifier(&geneve_notifier_block);
2d07dc79f   John W. Linville   geneve: add initi...
1783
1784
  	if (rc)
  		goto out2;
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1785
1786
1787
  	rc = rtnl_link_register(&geneve_link_ops);
  	if (rc)
  		goto out3;
2d07dc79f   John W. Linville   geneve: add initi...
1788
  	return 0;
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1789
1790
  out3:
  	unregister_netdevice_notifier(&geneve_notifier_block);
2d07dc79f   John W. Linville   geneve: add initi...
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
  out2:
  	unregister_pernet_subsys(&geneve_net_ops);
  out1:
  	return rc;
  }
  late_initcall(geneve_init_module);
  
  static void __exit geneve_cleanup_module(void)
  {
  	rtnl_link_unregister(&geneve_link_ops);
681e683ff   Hannes Frederic Sowa   geneve: break dep...
1801
  	unregister_netdevice_notifier(&geneve_notifier_block);
2d07dc79f   John W. Linville   geneve: add initi...
1802
1803
1804
1805
1806
1807
1808
1809
1810
  	unregister_pernet_subsys(&geneve_net_ops);
  }
  module_exit(geneve_cleanup_module);
  
  MODULE_LICENSE("GPL");
  MODULE_VERSION(GENEVE_NETDEV_VER);
  MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
  MODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic");
  MODULE_ALIAS_RTNL_LINK("geneve");