Blame view

drivers/net/vrf.c 33.9 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
193125dbd   David Ahern   net: Introduce VR...
2
3
4
5
6
7
8
9
  /*
   * vrf.c: device driver to encapsulate a VRF space
   *
   * Copyright (c) 2015 Cumulus Networks. All rights reserved.
   * Copyright (c) 2015 Shrijeet Mukherjee <shm@cumulusnetworks.com>
   * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
   *
   * Based on dummy, team and ipvlan drivers
193125dbd   David Ahern   net: Introduce VR...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   */
  
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/ip.h>
  #include <linux/init.h>
  #include <linux/moduleparam.h>
  #include <linux/netfilter.h>
  #include <linux/rtnetlink.h>
  #include <net/rtnetlink.h>
  #include <linux/u64_stats_sync.h>
  #include <linux/hashtable.h>
  
  #include <linux/inetdevice.h>
8f58336d3   David Ahern   net: Add ethernet...
26
  #include <net/arp.h>
193125dbd   David Ahern   net: Introduce VR...
27
28
  #include <net/ip.h>
  #include <net/ip_fib.h>
35402e313   David Ahern   net: Add IPv6 sup...
29
  #include <net/ip6_fib.h>
193125dbd   David Ahern   net: Introduce VR...
30
  #include <net/ip6_route.h>
193125dbd   David Ahern   net: Introduce VR...
31
32
  #include <net/route.h>
  #include <net/addrconf.h>
ee15ee5d9   David Ahern   net: Add support ...
33
  #include <net/l3mdev.h>
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
34
  #include <net/fib_rules.h>
097d3c950   David Ahern   net: vrf: Make ad...
35
  #include <net/netns/generic.h>
193125dbd   David Ahern   net: Introduce VR...
36
37
38
  
  #define DRV_NAME	"vrf"
  #define DRV_VERSION	"1.0"
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
39
  #define FIB_RULE_PREF  1000       /* default preference for FIB rules */
097d3c950   David Ahern   net: vrf: Make ad...
40
41
  
  static unsigned int vrf_net_id;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
42

ec539514e   David Ahern   net: Remove vrf h...
43
  struct net_vrf {
b0e95ccdd   David Ahern   net: vrf: protect...
44
45
  	struct rtable __rcu	*rth;
  	struct rt6_info	__rcu	*rt6;
43b059a31   David Ahern   vrf: Move fib6_ta...
46
47
48
  #if IS_ENABLED(CONFIG_IPV6)
  	struct fib6_table	*fib6_table;
  #endif
ec539514e   David Ahern   net: Remove vrf h...
49
50
  	u32                     tb_id;
  };
193125dbd   David Ahern   net: Introduce VR...
51
52
53
54
55
56
  struct pcpu_dstats {
  	u64			tx_pkts;
  	u64			tx_bytes;
  	u64			tx_drps;
  	u64			rx_pkts;
  	u64			rx_bytes;
afe80a499   David Ahern   net: vrf: ipv4 su...
57
  	u64			rx_drps;
193125dbd   David Ahern   net: Introduce VR...
58
59
  	struct u64_stats_sync	syncp;
  };
afe80a499   David Ahern   net: vrf: ipv4 su...
60
61
62
63
64
65
66
67
68
  static void vrf_rx_stats(struct net_device *dev, int len)
  {
  	struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
  
  	u64_stats_update_begin(&dstats->syncp);
  	dstats->rx_pkts++;
  	dstats->rx_bytes += len;
  	u64_stats_update_end(&dstats->syncp);
  }
57b8efa1a   Nikolay Aleksandrov   vrf: plug skb leaks
69
70
71
72
73
  static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
  {
  	vrf_dev->stats.tx_errors++;
  	kfree_skb(skb);
  }
bc1f44709   stephen hemminger   net: make ndo_get...
74
75
  static void vrf_get_stats64(struct net_device *dev,
  			    struct rtnl_link_stats64 *stats)
193125dbd   David Ahern   net: Introduce VR...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  {
  	int i;
  
  	for_each_possible_cpu(i) {
  		const struct pcpu_dstats *dstats;
  		u64 tbytes, tpkts, tdrops, rbytes, rpkts;
  		unsigned int start;
  
  		dstats = per_cpu_ptr(dev->dstats, i);
  		do {
  			start = u64_stats_fetch_begin_irq(&dstats->syncp);
  			tbytes = dstats->tx_bytes;
  			tpkts = dstats->tx_pkts;
  			tdrops = dstats->tx_drps;
  			rbytes = dstats->rx_bytes;
  			rpkts = dstats->rx_pkts;
  		} while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
  		stats->tx_bytes += tbytes;
  		stats->tx_packets += tpkts;
  		stats->tx_dropped += tdrops;
  		stats->rx_bytes += rbytes;
  		stats->rx_packets += rpkts;
  	}
193125dbd   David Ahern   net: Introduce VR...
99
  }
dcdd43c41   David Ahern   net: vrf: perform...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  /* by default VRF devices do not have a qdisc and are expected
   * to be created with only a single queue.
   */
  static bool qdisc_tx_is_default(const struct net_device *dev)
  {
  	struct netdev_queue *txq;
  	struct Qdisc *qdisc;
  
  	if (dev->num_tx_queues > 1)
  		return false;
  
  	txq = netdev_get_tx_queue(dev, 0);
  	qdisc = rcu_access_pointer(txq->qdisc);
  
  	return !qdisc->enqueue;
  }
afe80a499   David Ahern   net: vrf: ipv4 su...
116
117
118
119
120
121
122
123
124
125
126
  /* Local traffic destined to local address. Reinsert the packet to rx
   * path, similar to loopback handling.
   */
  static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
  			  struct dst_entry *dst)
  {
  	int len = skb->len;
  
  	skb_orphan(skb);
  
  	skb_dst_set(skb, dst);
afe80a499   David Ahern   net: vrf: ipv4 su...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  
  	/* set pkt_type to avoid skb hitting packet taps twice -
  	 * once on Tx and again in Rx processing
  	 */
  	skb->pkt_type = PACKET_LOOPBACK;
  
  	skb->protocol = eth_type_trans(skb, dev);
  
  	if (likely(netif_rx(skb) == NET_RX_SUCCESS))
  		vrf_rx_stats(dev, len);
  	else
  		this_cpu_inc(dev->dstats->rx_drps);
  
  	return NETDEV_TX_OK;
  }
35402e313   David Ahern   net: Add IPv6 sup...
142
  #if IS_ENABLED(CONFIG_IPV6)
4c1feac58   David Ahern   net: vrf: Flip IP...
143
144
145
146
147
148
149
150
151
152
153
154
155
  static int vrf_ip6_local_out(struct net *net, struct sock *sk,
  			     struct sk_buff *skb)
  {
  	int err;
  
  	err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net,
  		      sk, skb, NULL, skb_dst(skb)->dev, dst_output);
  
  	if (likely(err == 1))
  		err = dst_output(net, sk, skb);
  
  	return err;
  }
35402e313   David Ahern   net: Add IPv6 sup...
156
157
158
  static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
  					   struct net_device *dev)
  {
107e47cc8   Peter Kosyh   vrf: make sure sk...
159
  	const struct ipv6hdr *iph;
35402e313   David Ahern   net: Add IPv6 sup...
160
  	struct net *net = dev_net(skb->dev);
107e47cc8   Peter Kosyh   vrf: make sure sk...
161
  	struct flowi6 fl6;
35402e313   David Ahern   net: Add IPv6 sup...
162
163
164
  	int ret = NET_XMIT_DROP;
  	struct dst_entry *dst;
  	struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst;
107e47cc8   Peter Kosyh   vrf: make sure sk...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  	if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
  		goto err;
  
  	iph = ipv6_hdr(skb);
  
  	memset(&fl6, 0, sizeof(fl6));
  	/* needed to match OIF rule */
  	fl6.flowi6_oif = dev->ifindex;
  	fl6.flowi6_iif = LOOPBACK_IFINDEX;
  	fl6.daddr = iph->daddr;
  	fl6.saddr = iph->saddr;
  	fl6.flowlabel = ip6_flowinfo(iph);
  	fl6.flowi6_mark = skb->mark;
  	fl6.flowi6_proto = iph->nexthdr;
  	fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
35402e313   David Ahern   net: Add IPv6 sup...
180
181
182
183
184
  	dst = ip6_route_output(net, NULL, &fl6);
  	if (dst == dst_null)
  		goto err;
  
  	skb_dst_drop(skb);
b4869aa2f   David Ahern   net: vrf: ipv6 su...
185
186
187
  
  	/* if dst.dev is loopback or the VRF device again this is locally
  	 * originated traffic destined to a local address. Short circuit
4f04256c9   David Ahern   net: vrf: Drop lo...
188
  	 * to Rx path
b4869aa2f   David Ahern   net: vrf: ipv6 su...
189
  	 */
4f04256c9   David Ahern   net: vrf: Drop lo...
190
191
  	if (dst->dev == dev)
  		return vrf_local_xmit(skb, dev, dst);
b4869aa2f   David Ahern   net: vrf: ipv6 su...
192

35402e313   David Ahern   net: Add IPv6 sup...
193
  	skb_dst_set(skb, dst);
911a66fbc   David Ahern   net: vrf: Minor r...
194
195
  	/* strip the ethernet header added for pass through VRF device */
  	__skb_pull(skb, skb_network_offset(skb));
4c1feac58   David Ahern   net: vrf: Flip IP...
196
  	ret = vrf_ip6_local_out(net, skb->sk, skb);
35402e313   David Ahern   net: Add IPv6 sup...
197
198
199
200
201
202
203
204
205
206
207
  	if (unlikely(net_xmit_eval(ret)))
  		dev->stats.tx_errors++;
  	else
  		ret = NET_XMIT_SUCCESS;
  
  	return ret;
  err:
  	vrf_tx_error(dev, skb);
  	return NET_XMIT_DROP;
  }
  #else
193125dbd   David Ahern   net: Introduce VR...
208
209
210
  static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
  					   struct net_device *dev)
  {
57b8efa1a   Nikolay Aleksandrov   vrf: plug skb leaks
211
212
  	vrf_tx_error(dev, skb);
  	return NET_XMIT_DROP;
193125dbd   David Ahern   net: Introduce VR...
213
  }
35402e313   David Ahern   net: Add IPv6 sup...
214
  #endif
193125dbd   David Ahern   net: Introduce VR...
215

ebfc102c5   David Ahern   net: vrf: Flip IP...
216
217
218
219
220
221
222
223
224
225
226
227
228
  /* based on ip_local_out; can't use it b/c the dst is switched pointing to us */
  static int vrf_ip_local_out(struct net *net, struct sock *sk,
  			    struct sk_buff *skb)
  {
  	int err;
  
  	err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
  		      skb, NULL, skb_dst(skb)->dev, dst_output);
  	if (likely(err == 1))
  		err = dst_output(net, sk, skb);
  
  	return err;
  }
193125dbd   David Ahern   net: Introduce VR...
229
230
231
  static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
  					   struct net_device *vrf_dev)
  {
107e47cc8   Peter Kosyh   vrf: make sure sk...
232
  	struct iphdr *ip4h;
193125dbd   David Ahern   net: Introduce VR...
233
  	int ret = NET_XMIT_DROP;
107e47cc8   Peter Kosyh   vrf: make sure sk...
234
  	struct flowi4 fl4;
911a66fbc   David Ahern   net: vrf: Minor r...
235
236
  	struct net *net = dev_net(vrf_dev);
  	struct rtable *rt;
107e47cc8   Peter Kosyh   vrf: make sure sk...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
  		goto err;
  
  	ip4h = ip_hdr(skb);
  
  	memset(&fl4, 0, sizeof(fl4));
  	/* needed to match OIF rule */
  	fl4.flowi4_oif = vrf_dev->ifindex;
  	fl4.flowi4_iif = LOOPBACK_IFINDEX;
  	fl4.flowi4_tos = RT_TOS(ip4h->tos);
  	fl4.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF;
  	fl4.flowi4_proto = ip4h->protocol;
  	fl4.daddr = ip4h->daddr;
  	fl4.saddr = ip4h->saddr;
911a66fbc   David Ahern   net: vrf: Minor r...
251
252
253
  	rt = ip_route_output_flow(net, &fl4, NULL);
  	if (IS_ERR(rt))
  		goto err;
193125dbd   David Ahern   net: Introduce VR...
254

911a66fbc   David Ahern   net: vrf: Minor r...
255
  	skb_dst_drop(skb);
afe80a499   David Ahern   net: vrf: ipv4 su...
256
257
258
  
  	/* if dst.dev is loopback or the VRF device again this is locally
  	 * originated traffic destined to a local address. Short circuit
4f04256c9   David Ahern   net: vrf: Drop lo...
259
  	 * to Rx path
afe80a499   David Ahern   net: vrf: ipv4 su...
260
  	 */
4f04256c9   David Ahern   net: vrf: Drop lo...
261
262
  	if (rt->dst.dev == vrf_dev)
  		return vrf_local_xmit(skb, vrf_dev, &rt->dst);
afe80a499   David Ahern   net: vrf: ipv4 su...
263

911a66fbc   David Ahern   net: vrf: Minor r...
264
265
266
267
  	skb_dst_set(skb, &rt->dst);
  
  	/* strip the ethernet header added for pass through VRF device */
  	__skb_pull(skb, skb_network_offset(skb));
193125dbd   David Ahern   net: Introduce VR...
268
269
270
271
272
  
  	if (!ip4h->saddr) {
  		ip4h->saddr = inet_select_addr(skb_dst(skb)->dev, 0,
  					       RT_SCOPE_LINK);
  	}
ebfc102c5   David Ahern   net: vrf: Flip IP...
273
  	ret = vrf_ip_local_out(dev_net(skb_dst(skb)->dev), skb->sk, skb);
193125dbd   David Ahern   net: Introduce VR...
274
275
276
277
278
279
280
281
  	if (unlikely(net_xmit_eval(ret)))
  		vrf_dev->stats.tx_errors++;
  	else
  		ret = NET_XMIT_SUCCESS;
  
  out:
  	return ret;
  err:
57b8efa1a   Nikolay Aleksandrov   vrf: plug skb leaks
282
  	vrf_tx_error(vrf_dev, skb);
193125dbd   David Ahern   net: Introduce VR...
283
284
285
286
287
288
289
290
291
292
293
  	goto out;
  }
  
  static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
  {
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
  		return vrf_process_v4_outbound(skb, dev);
  	case htons(ETH_P_IPV6):
  		return vrf_process_v6_outbound(skb, dev);
  	default:
57b8efa1a   Nikolay Aleksandrov   vrf: plug skb leaks
294
  		vrf_tx_error(dev, skb);
193125dbd   David Ahern   net: Introduce VR...
295
296
297
298
299
300
  		return NET_XMIT_DROP;
  	}
  }
  
  static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
  {
f7887d40e   David Ahern   vrf: Fix use-afte...
301
  	int len = skb->len;
193125dbd   David Ahern   net: Introduce VR...
302
303
304
305
306
307
308
  	netdev_tx_t ret = is_ip_tx_frame(skb, dev);
  
  	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
  		struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
  
  		u64_stats_update_begin(&dstats->syncp);
  		dstats->tx_pkts++;
f7887d40e   David Ahern   vrf: Fix use-afte...
309
  		dstats->tx_bytes += len;
193125dbd   David Ahern   net: Introduce VR...
310
311
312
313
314
315
316
  		u64_stats_update_end(&dstats->syncp);
  	} else {
  		this_cpu_inc(dev->dstats->tx_drps);
  	}
  
  	return ret;
  }
dcdd43c41   David Ahern   net: vrf: perform...
317
318
319
320
321
322
323
  static int vrf_finish_direct(struct net *net, struct sock *sk,
  			     struct sk_buff *skb)
  {
  	struct net_device *vrf_dev = skb->dev;
  
  	if (!list_empty(&vrf_dev->ptype_all) &&
  	    likely(skb_headroom(skb) >= ETH_HLEN)) {
d58ff3512   Johannes Berg   networking: make ...
324
  		struct ethhdr *eth = skb_push(skb, ETH_HLEN);
dcdd43c41   David Ahern   net: vrf: perform...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  
  		ether_addr_copy(eth->h_source, vrf_dev->dev_addr);
  		eth_zero_addr(eth->h_dest);
  		eth->h_proto = skb->protocol;
  
  		rcu_read_lock_bh();
  		dev_queue_xmit_nit(skb, vrf_dev);
  		rcu_read_unlock_bh();
  
  		skb_pull(skb, ETH_HLEN);
  	}
  
  	return 1;
  }
35402e313   David Ahern   net: Add IPv6 sup...
339
  #if IS_ENABLED(CONFIG_IPV6)
35402e313   David Ahern   net: Add IPv6 sup...
340
341
342
343
344
345
  /* modelled after ip6_finish_output2 */
  static int vrf_finish_output6(struct net *net, struct sock *sk,
  			      struct sk_buff *skb)
  {
  	struct dst_entry *dst = skb_dst(skb);
  	struct net_device *dev = dst->dev;
9b1c1ef13   Nicolas Dichtel   ipv6: constify rt...
346
  	const struct in6_addr *nexthop;
35402e313   David Ahern   net: Add IPv6 sup...
347
  	struct neighbour *neigh;
35402e313   David Ahern   net: Add IPv6 sup...
348
  	int ret;
895b5c9f2   Florian Westphal   netfilter: drop b...
349
  	nf_reset_ct(skb);
eb63ecc17   David Ahern   net: vrf: Drop co...
350

35402e313   David Ahern   net: Add IPv6 sup...
351
352
353
354
355
356
357
358
359
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
  
  	rcu_read_lock_bh();
  	nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
  	neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
  	if (unlikely(!neigh))
  		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
  	if (!IS_ERR(neigh)) {
4ff062035   Julian Anastasov   net: add dst_pend...
360
  		sock_confirm_neigh(skb, neigh);
0353f2823   David Ahern   neighbor: Add ski...
361
  		ret = neigh_output(neigh, skb, false);
35402e313   David Ahern   net: Add IPv6 sup...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  		rcu_read_unlock_bh();
  		return ret;
  	}
  	rcu_read_unlock_bh();
  
  	IP6_INC_STATS(dev_net(dst->dev),
  		      ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
  	kfree_skb(skb);
  	return -EINVAL;
  }
  
  /* modelled after ip6_output */
  static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
  {
  	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, skb_dst(skb)->dev,
  			    vrf_finish_output6,
  			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
  }
4c1feac58   David Ahern   net: vrf: Flip IP...
381
382
383
384
  /* set dst on skb to send packet to us via dev_xmit path. Allows
   * packet to go through device based features such as qdisc, netfilter
   * hooks and packet sockets with skb->dev set to vrf device.
   */
a9ec54d1b   David Ahern   net: vrf: perform...
385
386
  static struct sk_buff *vrf_ip6_out_redirect(struct net_device *vrf_dev,
  					    struct sk_buff *skb)
4c1feac58   David Ahern   net: vrf: Flip IP...
387
388
389
390
  {
  	struct net_vrf *vrf = netdev_priv(vrf_dev);
  	struct dst_entry *dst = NULL;
  	struct rt6_info *rt6;
4c1feac58   David Ahern   net: vrf: Flip IP...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  	rcu_read_lock();
  
  	rt6 = rcu_dereference(vrf->rt6);
  	if (likely(rt6)) {
  		dst = &rt6->dst;
  		dst_hold(dst);
  	}
  
  	rcu_read_unlock();
  
  	if (unlikely(!dst)) {
  		vrf_tx_error(vrf_dev, skb);
  		return NULL;
  	}
  
  	skb_dst_drop(skb);
  	skb_dst_set(skb, dst);
  
  	return skb;
  }
a9ec54d1b   David Ahern   net: vrf: perform...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  static int vrf_output6_direct(struct net *net, struct sock *sk,
  			      struct sk_buff *skb)
  {
  	skb->protocol = htons(ETH_P_IPV6);
  
  	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, skb->dev,
  			    vrf_finish_direct,
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
  
  static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
  					  struct sock *sk,
  					  struct sk_buff *skb)
  {
  	struct net *net = dev_net(vrf_dev);
  	int err;
  
  	skb->dev = vrf_dev;
  
  	err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk,
  		      skb, NULL, vrf_dev, vrf_output6_direct);
  
  	if (likely(err == 1))
  		err = vrf_output6_direct(net, sk, skb);
  
  	/* reset skb device */
  	if (likely(err == 1))
895b5c9f2   Florian Westphal   netfilter: drop b...
439
  		nf_reset_ct(skb);
a9ec54d1b   David Ahern   net: vrf: perform...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  	else
  		skb = NULL;
  
  	return skb;
  }
  
  static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
  				   struct sock *sk,
  				   struct sk_buff *skb)
  {
  	/* don't divert link scope packets */
  	if (rt6_need_strict(&ipv6_hdr(skb)->daddr))
  		return skb;
  
  	if (qdisc_tx_is_default(vrf_dev))
  		return vrf_ip6_out_direct(vrf_dev, sk, skb);
  
  	return vrf_ip6_out_redirect(vrf_dev, skb);
  }
b0e95ccdd   David Ahern   net: vrf: protect...
459
  /* holding rtnl */
810e530bf   David Ahern   net: vrf: Switch ...
460
  static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf)
35402e313   David Ahern   net: Add IPv6 sup...
461
  {
b0e95ccdd   David Ahern   net: vrf: protect...
462
  	struct rt6_info *rt6 = rtnl_dereference(vrf->rt6);
810e530bf   David Ahern   net: vrf: Switch ...
463
464
  	struct net *net = dev_net(dev);
  	struct dst_entry *dst;
b0e95ccdd   David Ahern   net: vrf: protect...
465

b4869aa2f   David Ahern   net: vrf: ipv6 su...
466
  	RCU_INIT_POINTER(vrf->rt6, NULL);
b4869aa2f   David Ahern   net: vrf: ipv6 su...
467
  	synchronize_rcu();
b0e95ccdd   David Ahern   net: vrf: protect...
468

810e530bf   David Ahern   net: vrf: Switch ...
469
470
471
472
473
474
475
476
477
478
  	/* move dev in dst's to loopback so this VRF device can be deleted
  	 * - based on dst_ifdown
  	 */
  	if (rt6) {
  		dst = &rt6->dst;
  		dev_put(dst->dev);
  		dst->dev = net->loopback_dev;
  		dev_hold(dst->dev);
  		dst_release(dst);
  	}
35402e313   David Ahern   net: Add IPv6 sup...
479
480
481
482
  }
  
  static int vrf_rt6_create(struct net_device *dev)
  {
a4c2fd7f7   Wei Wang   net: remove DST_N...
483
  	int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM;
35402e313   David Ahern   net: Add IPv6 sup...
484
  	struct net_vrf *vrf = netdev_priv(dev);
9ab179d83   David Ahern   net: vrf: Fix dst...
485
  	struct net *net = dev_net(dev);
4f04256c9   David Ahern   net: vrf: Drop lo...
486
  	struct rt6_info *rt6;
35402e313   David Ahern   net: Add IPv6 sup...
487
  	int rc = -ENOMEM;
e43486371   David Ahern   net: vrf: Fix cra...
488
489
490
  	/* IPv6 can be CONFIG enabled and then disabled runtime */
  	if (!ipv6_mod_enabled())
  		return 0;
43b059a31   David Ahern   vrf: Move fib6_ta...
491
492
  	vrf->fib6_table = fib6_new_table(net, vrf->tb_id);
  	if (!vrf->fib6_table)
b3b4663c9   David Ahern   net: vrf: Create ...
493
  		goto out;
b4869aa2f   David Ahern   net: vrf: ipv6 su...
494
495
  	/* create a dst for routing packets out a VRF device */
  	rt6 = ip6_dst_alloc(net, dev, flags);
35402e313   David Ahern   net: Add IPv6 sup...
496
497
  	if (!rt6)
  		goto out;
b3b4663c9   David Ahern   net: vrf: Create ...
498
  	rt6->dst.output	= vrf_output6;
b4869aa2f   David Ahern   net: vrf: ipv6 su...
499

b0e95ccdd   David Ahern   net: vrf: protect...
500
  	rcu_assign_pointer(vrf->rt6, rt6);
35402e313   David Ahern   net: Add IPv6 sup...
501
502
503
504
505
  	rc = 0;
  out:
  	return rc;
  }
  #else
4c1feac58   David Ahern   net: vrf: Flip IP...
506
507
508
509
510
511
  static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
  				   struct sock *sk,
  				   struct sk_buff *skb)
  {
  	return skb;
  }
810e530bf   David Ahern   net: vrf: Switch ...
512
  static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf)
35402e313   David Ahern   net: Add IPv6 sup...
513
514
515
516
517
518
519
520
  {
  }
  
  static int vrf_rt6_create(struct net_device *dev)
  {
  	return 0;
  }
  #endif
8f58336d3   David Ahern   net: Add ethernet...
521
  /* modelled after ip_finish_output2 */
0c4b51f00   Eric W. Biederman   netfilter: Pass n...
522
  static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
193125dbd   David Ahern   net: Introduce VR...
523
  {
8f58336d3   David Ahern   net: Add ethernet...
524
525
526
527
528
  	struct dst_entry *dst = skb_dst(skb);
  	struct rtable *rt = (struct rtable *)dst;
  	struct net_device *dev = dst->dev;
  	unsigned int hh_len = LL_RESERVED_SPACE(dev);
  	struct neighbour *neigh;
5c9f7c1df   David Ahern   ipv4: Add helpers...
529
  	bool is_v6gw = false;
8f58336d3   David Ahern   net: Add ethernet...
530
  	int ret = -EINVAL;
895b5c9f2   Florian Westphal   netfilter: drop b...
531
  	nf_reset_ct(skb);
eb63ecc17   David Ahern   net: vrf: Drop co...
532

8f58336d3   David Ahern   net: Add ethernet...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  	/* Be paranoid, rather than too clever. */
  	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
  		struct sk_buff *skb2;
  
  		skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
  		if (!skb2) {
  			ret = -ENOMEM;
  			goto err;
  		}
  		if (skb->sk)
  			skb_set_owner_w(skb2, skb->sk);
  
  		consume_skb(skb);
  		skb = skb2;
  	}
  
  	rcu_read_lock_bh();
5c9f7c1df   David Ahern   ipv4: Add helpers...
550
  	neigh = ip_neigh_for_gw(rt, skb, &is_v6gw);
4ff062035   Julian Anastasov   net: add dst_pend...
551
552
  	if (!IS_ERR(neigh)) {
  		sock_confirm_neigh(skb, neigh);
5c9f7c1df   David Ahern   ipv4: Add helpers...
553
554
  		/* if crossing protocols, can not use the cached header */
  		ret = neigh_output(neigh, skb, is_v6gw);
82dd0d2a9   David Ahern   vrf: Fix use afte...
555
556
  		rcu_read_unlock_bh();
  		return ret;
4ff062035   Julian Anastasov   net: add dst_pend...
557
  	}
8f58336d3   David Ahern   net: Add ethernet...
558
559
560
  
  	rcu_read_unlock_bh();
  err:
82dd0d2a9   David Ahern   vrf: Fix use afte...
561
  	vrf_tx_error(skb->dev, skb);
8f58336d3   David Ahern   net: Add ethernet...
562
  	return ret;
193125dbd   David Ahern   net: Introduce VR...
563
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
564
  static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)
193125dbd   David Ahern   net: Introduce VR...
565
566
  {
  	struct net_device *dev = skb_dst(skb)->dev;
29a26a568   Eric W. Biederman   netfilter: Pass s...
567
  	IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
193125dbd   David Ahern   net: Introduce VR...
568
569
570
  
  	skb->dev = dev;
  	skb->protocol = htons(ETH_P_IP);
29a26a568   Eric W. Biederman   netfilter: Pass s...
571
572
  	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, dev,
8f58336d3   David Ahern   net: Add ethernet...
573
  			    vrf_finish_output,
193125dbd   David Ahern   net: Introduce VR...
574
575
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
ebfc102c5   David Ahern   net: vrf: Flip IP...
576
577
578
579
  /* set dst on skb to send packet to us via dev_xmit path. Allows
   * packet to go through device based features such as qdisc, netfilter
   * hooks and packet sockets with skb->dev set to vrf device.
   */
dcdd43c41   David Ahern   net: vrf: perform...
580
581
  static struct sk_buff *vrf_ip_out_redirect(struct net_device *vrf_dev,
  					   struct sk_buff *skb)
ebfc102c5   David Ahern   net: vrf: Flip IP...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  {
  	struct net_vrf *vrf = netdev_priv(vrf_dev);
  	struct dst_entry *dst = NULL;
  	struct rtable *rth;
  
  	rcu_read_lock();
  
  	rth = rcu_dereference(vrf->rth);
  	if (likely(rth)) {
  		dst = &rth->dst;
  		dst_hold(dst);
  	}
  
  	rcu_read_unlock();
  
  	if (unlikely(!dst)) {
  		vrf_tx_error(vrf_dev, skb);
  		return NULL;
  	}
  
  	skb_dst_drop(skb);
  	skb_dst_set(skb, dst);
  
  	return skb;
  }
dcdd43c41   David Ahern   net: vrf: perform...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  static int vrf_output_direct(struct net *net, struct sock *sk,
  			     struct sk_buff *skb)
  {
  	skb->protocol = htons(ETH_P_IP);
  
  	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, skb->dev,
  			    vrf_finish_direct,
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
  
  static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
  					 struct sock *sk,
  					 struct sk_buff *skb)
  {
  	struct net *net = dev_net(vrf_dev);
  	int err;
  
  	skb->dev = vrf_dev;
  
  	err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
  		      skb, NULL, vrf_dev, vrf_output_direct);
  
  	if (likely(err == 1))
  		err = vrf_output_direct(net, sk, skb);
  
  	/* reset skb device */
  	if (likely(err == 1))
895b5c9f2   Florian Westphal   netfilter: drop b...
635
  		nf_reset_ct(skb);
dcdd43c41   David Ahern   net: vrf: perform...
636
637
638
639
640
641
642
643
644
645
  	else
  		skb = NULL;
  
  	return skb;
  }
  
  static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,
  				  struct sock *sk,
  				  struct sk_buff *skb)
  {
1e19c4d68   David Ahern   net: vrf: Add sup...
646
647
648
  	/* don't divert multicast or local broadcast */
  	if (ipv4_is_multicast(ip_hdr(skb)->daddr) ||
  	    ipv4_is_lbcast(ip_hdr(skb)->daddr))
dcdd43c41   David Ahern   net: vrf: perform...
649
650
651
652
653
654
655
  		return skb;
  
  	if (qdisc_tx_is_default(vrf_dev))
  		return vrf_ip_out_direct(vrf_dev, sk, skb);
  
  	return vrf_ip_out_redirect(vrf_dev, skb);
  }
ebfc102c5   David Ahern   net: vrf: Flip IP...
656
657
658
659
660
661
662
663
664
  /* called with rcu lock held */
  static struct sk_buff *vrf_l3_out(struct net_device *vrf_dev,
  				  struct sock *sk,
  				  struct sk_buff *skb,
  				  u16 proto)
  {
  	switch (proto) {
  	case AF_INET:
  		return vrf_ip_out(vrf_dev, sk, skb);
4c1feac58   David Ahern   net: vrf: Flip IP...
665
666
  	case AF_INET6:
  		return vrf_ip6_out(vrf_dev, sk, skb);
ebfc102c5   David Ahern   net: vrf: Flip IP...
667
668
669
670
  	}
  
  	return skb;
  }
b0e95ccdd   David Ahern   net: vrf: protect...
671
  /* holding rtnl */
810e530bf   David Ahern   net: vrf: Switch ...
672
  static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf)
193125dbd   David Ahern   net: Introduce VR...
673
  {
b0e95ccdd   David Ahern   net: vrf: protect...
674
  	struct rtable *rth = rtnl_dereference(vrf->rth);
810e530bf   David Ahern   net: vrf: Switch ...
675
676
  	struct net *net = dev_net(dev);
  	struct dst_entry *dst;
b0e95ccdd   David Ahern   net: vrf: protect...
677

afe80a499   David Ahern   net: vrf: ipv4 su...
678
  	RCU_INIT_POINTER(vrf->rth, NULL);
afe80a499   David Ahern   net: vrf: ipv4 su...
679
  	synchronize_rcu();
193125dbd   David Ahern   net: Introduce VR...
680

810e530bf   David Ahern   net: vrf: Switch ...
681
682
683
684
685
686
687
688
689
690
  	/* move dev in dst's to loopback so this VRF device can be deleted
  	 * - based on dst_ifdown
  	 */
  	if (rth) {
  		dst = &rth->dst;
  		dev_put(dst->dev);
  		dst->dev = net->loopback_dev;
  		dev_hold(dst->dev);
  		dst_release(dst);
  	}
193125dbd   David Ahern   net: Introduce VR...
691
  }
b0e95ccdd   David Ahern   net: vrf: protect...
692
  static int vrf_rtable_create(struct net_device *dev)
193125dbd   David Ahern   net: Introduce VR...
693
  {
b7503e0cd   David Ahern   net: Add FIB tabl...
694
  	struct net_vrf *vrf = netdev_priv(dev);
4f04256c9   David Ahern   net: vrf: Drop lo...
695
  	struct rtable *rth;
193125dbd   David Ahern   net: Introduce VR...
696

b3b4663c9   David Ahern   net: vrf: Create ...
697
  	if (!fib_new_table(dev_net(dev), vrf->tb_id))
b0e95ccdd   David Ahern   net: vrf: protect...
698
  		return -ENOMEM;
b3b4663c9   David Ahern   net: vrf: Create ...
699

afe80a499   David Ahern   net: vrf: ipv4 su...
700
  	/* create a dst for routing packets out through a VRF device */
9ab179d83   David Ahern   net: vrf: Fix dst...
701
  	rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
b0e95ccdd   David Ahern   net: vrf: protect...
702
703
  	if (!rth)
  		return -ENOMEM;
193125dbd   David Ahern   net: Introduce VR...
704

b0e95ccdd   David Ahern   net: vrf: protect...
705
  	rth->dst.output	= vrf_output;
b0e95ccdd   David Ahern   net: vrf: protect...
706
707
708
709
  
  	rcu_assign_pointer(vrf->rth, rth);
  
  	return 0;
193125dbd   David Ahern   net: Introduce VR...
710
711
712
713
714
  }
  
  /**************************** device handling ********************/
  
  /* cycle interface to flush neighbor cache and move routes across tables */
dc1aea1e0   Petr Machata   net: vrf: cycle_n...
715
716
  static void cycle_netdev(struct net_device *dev,
  			 struct netlink_ext_ack *extack)
193125dbd   David Ahern   net: Introduce VR...
717
718
719
720
721
722
  {
  	unsigned int flags = dev->flags;
  	int ret;
  
  	if (!netif_running(dev))
  		return;
567c5e13b   Petr Machata   net: core: dev: A...
723
  	ret = dev_change_flags(dev, flags & ~IFF_UP, extack);
193125dbd   David Ahern   net: Introduce VR...
724
  	if (ret >= 0)
567c5e13b   Petr Machata   net: core: dev: A...
725
  		ret = dev_change_flags(dev, flags, extack);
193125dbd   David Ahern   net: Introduce VR...
726
727
728
729
730
731
732
733
  
  	if (ret < 0) {
  		netdev_err(dev,
  			   "Failed to cycle device %s; route tables might be wrong!
  ",
  			   dev->name);
  	}
  }
42ab19ee9   David Ahern   net: Add extack t...
734
735
  static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
  			    struct netlink_ext_ack *extack)
193125dbd   David Ahern   net: Introduce VR...
736
  {
bad531623   Nikolay Aleksandrov   vrf: remove slave...
737
  	int ret;
193125dbd   David Ahern   net: Introduce VR...
738

26d31ac11   David Ahern   net: vrf: Do not ...
739
740
741
  	/* do not allow loopback device to be enslaved to a VRF.
  	 * The vrf device acts as the loopback for the vrf.
  	 */
de3baa3ed   David Ahern   net: vrf: Add ext...
742
743
744
  	if (port_dev == dev_net(dev)->loopback_dev) {
  		NL_SET_ERR_MSG(extack,
  			       "Can not enslave loopback device to a VRF");
26d31ac11   David Ahern   net: vrf: Do not ...
745
  		return -EOPNOTSUPP;
de3baa3ed   David Ahern   net: vrf: Add ext...
746
  	}
26d31ac11   David Ahern   net: vrf: Do not ...
747

fdeea7be8   Ido Schimmel   net: vrf: Set sla...
748
  	port_dev->priv_flags |= IFF_L3MDEV_SLAVE;
42ab19ee9   David Ahern   net: Add extack t...
749
  	ret = netdev_master_upper_dev_link(port_dev, dev, NULL, NULL, extack);
193125dbd   David Ahern   net: Introduce VR...
750
  	if (ret < 0)
fdeea7be8   Ido Schimmel   net: vrf: Set sla...
751
  		goto err;
193125dbd   David Ahern   net: Introduce VR...
752

dc1aea1e0   Petr Machata   net: vrf: cycle_n...
753
  	cycle_netdev(port_dev, extack);
193125dbd   David Ahern   net: Introduce VR...
754
755
  
  	return 0;
fdeea7be8   Ido Schimmel   net: vrf: Set sla...
756
757
758
759
  
  err:
  	port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
  	return ret;
193125dbd   David Ahern   net: Introduce VR...
760
  }
33eaf2a6e   David Ahern   net: Add extack t...
761
762
  static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
  			 struct netlink_ext_ack *extack)
193125dbd   David Ahern   net: Introduce VR...
763
  {
de3baa3ed   David Ahern   net: vrf: Add ext...
764
765
766
767
768
769
770
  	if (netif_is_l3_master(port_dev)) {
  		NL_SET_ERR_MSG(extack,
  			       "Can not enslave an L3 master device to a VRF");
  		return -EINVAL;
  	}
  
  	if (netif_is_l3_slave(port_dev))
193125dbd   David Ahern   net: Introduce VR...
771
  		return -EINVAL;
42ab19ee9   David Ahern   net: Add extack t...
772
  	return do_vrf_add_slave(dev, port_dev, extack);
193125dbd   David Ahern   net: Introduce VR...
773
774
775
776
777
  }
  
  /* inverse of do_vrf_add_slave */
  static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
  {
193125dbd   David Ahern   net: Introduce VR...
778
  	netdev_upper_dev_unlink(port_dev, dev);
fee6d4c77   David Ahern   net: Add netif_is...
779
  	port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
193125dbd   David Ahern   net: Introduce VR...
780

dc1aea1e0   Petr Machata   net: vrf: cycle_n...
781
  	cycle_netdev(port_dev, NULL);
193125dbd   David Ahern   net: Introduce VR...
782

193125dbd   David Ahern   net: Introduce VR...
783
784
785
786
787
  	return 0;
  }
  
  static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
  {
193125dbd   David Ahern   net: Introduce VR...
788
789
790
791
792
793
  	return do_vrf_del_slave(dev, port_dev);
  }
  
  static void vrf_dev_uninit(struct net_device *dev)
  {
  	struct net_vrf *vrf = netdev_priv(dev);
193125dbd   David Ahern   net: Introduce VR...
794

810e530bf   David Ahern   net: vrf: Switch ...
795
796
  	vrf_rtable_release(dev, vrf);
  	vrf_rt6_release(dev, vrf);
193125dbd   David Ahern   net: Introduce VR...
797

3a4a27d3b   Nikolay Aleksandrov   vrf: don't check ...
798
  	free_percpu(dev->dstats);
193125dbd   David Ahern   net: Introduce VR...
799
800
801
802
803
804
  	dev->dstats = NULL;
  }
  
  static int vrf_dev_init(struct net_device *dev)
  {
  	struct net_vrf *vrf = netdev_priv(dev);
193125dbd   David Ahern   net: Introduce VR...
805
806
807
808
809
  	dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
  	if (!dev->dstats)
  		goto out_nomem;
  
  	/* create the default dst which points back to us */
b0e95ccdd   David Ahern   net: vrf: protect...
810
  	if (vrf_rtable_create(dev) != 0)
193125dbd   David Ahern   net: Introduce VR...
811
  		goto out_stats;
35402e313   David Ahern   net: Add IPv6 sup...
812
813
  	if (vrf_rt6_create(dev) != 0)
  		goto out_rth;
193125dbd   David Ahern   net: Introduce VR...
814
  	dev->flags = IFF_MASTER | IFF_NOARP;
b87ab6b8e   David Ahern   net: vrf: set ope...
815
816
817
818
819
  	/* MTU is irrelevant for VRF device; set to 64k similar to lo */
  	dev->mtu = 64 * 1024;
  
  	/* similarly, oper state is irrelevant; set to up to avoid confusion */
  	dev->operstate = IF_OPER_UP;
193125dbd   David Ahern   net: Introduce VR...
820
  	return 0;
35402e313   David Ahern   net: Add IPv6 sup...
821
  out_rth:
810e530bf   David Ahern   net: vrf: Switch ...
822
  	vrf_rtable_release(dev, vrf);
193125dbd   David Ahern   net: Introduce VR...
823
824
825
826
827
828
829
830
831
832
833
  out_stats:
  	free_percpu(dev->dstats);
  	dev->dstats = NULL;
  out_nomem:
  	return -ENOMEM;
  }
  
  static const struct net_device_ops vrf_netdev_ops = {
  	.ndo_init		= vrf_dev_init,
  	.ndo_uninit		= vrf_dev_uninit,
  	.ndo_start_xmit		= vrf_xmit,
6819e3f6d   Miaohe Lin   net: vrf: Fix ope...
834
  	.ndo_set_mac_address	= eth_mac_addr,
193125dbd   David Ahern   net: Introduce VR...
835
836
837
838
  	.ndo_get_stats64	= vrf_get_stats64,
  	.ndo_add_slave		= vrf_add_slave,
  	.ndo_del_slave		= vrf_del_slave,
  };
ee15ee5d9   David Ahern   net: Add support ...
839
840
841
842
843
844
  static u32 vrf_fib_table(const struct net_device *dev)
  {
  	struct net_vrf *vrf = netdev_priv(dev);
  
  	return vrf->tb_id;
  }
73e20b761   David Ahern   net: vrf: Add sup...
845
846
  static int vrf_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
  {
1a4a5bf52   Gao Feng   driver: vrf: Fix ...
847
  	kfree_skb(skb);
73e20b761   David Ahern   net: vrf: Add sup...
848
849
850
851
852
853
854
855
  	return 0;
  }
  
  static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook,
  				      struct sk_buff *skb,
  				      struct net_device *dev)
  {
  	struct net *net = dev_net(dev);
1a4a5bf52   Gao Feng   driver: vrf: Fix ...
856
  	if (nf_hook(pf, hook, net, NULL, skb, dev, NULL, vrf_rcv_finish) != 1)
73e20b761   David Ahern   net: vrf: Add sup...
857
858
859
860
  		skb = NULL;    /* kfree_skb(skb) handled by nf code */
  
  	return skb;
  }
35402e313   David Ahern   net: Add IPv6 sup...
861
  #if IS_ENABLED(CONFIG_IPV6)
74b20582a   David Ahern   net: l3mdev: Add ...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  /* neighbor handling is done with actual device; do not want
   * to flip skb->dev for those ndisc packets. This really fails
   * for multiple next protocols (e.g., NEXTHDR_HOP). But it is
   * a start.
   */
  static bool ipv6_ndisc_frame(const struct sk_buff *skb)
  {
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
  	bool rc = false;
  
  	if (iph->nexthdr == NEXTHDR_ICMP) {
  		const struct icmp6hdr *icmph;
  		struct icmp6hdr _icmph;
  
  		icmph = skb_header_pointer(skb, sizeof(*iph),
  					   sizeof(_icmph), &_icmph);
  		if (!icmph)
  			goto out;
  
  		switch (icmph->icmp6_type) {
  		case NDISC_ROUTER_SOLICITATION:
  		case NDISC_ROUTER_ADVERTISEMENT:
  		case NDISC_NEIGHBOUR_SOLICITATION:
  		case NDISC_NEIGHBOUR_ADVERTISEMENT:
  		case NDISC_REDIRECT:
  			rc = true;
  			break;
  		}
  	}
  
  out:
  	return rc;
  }
9ff743846   David Ahern   net: vrf: Handle ...
895
896
897
898
  static struct rt6_info *vrf_ip6_route_lookup(struct net *net,
  					     const struct net_device *dev,
  					     struct flowi6 *fl6,
  					     int ifindex,
b75cc8f90   David Ahern   net/ipv6: Pass sk...
899
  					     const struct sk_buff *skb,
9ff743846   David Ahern   net: vrf: Handle ...
900
901
902
  					     int flags)
  {
  	struct net_vrf *vrf = netdev_priv(dev);
9ff743846   David Ahern   net: vrf: Handle ...
903

43b059a31   David Ahern   vrf: Move fib6_ta...
904
  	return ip6_pol_route(net, vrf->fib6_table, ifindex, fl6, skb, flags);
9ff743846   David Ahern   net: vrf: Handle ...
905
906
907
908
909
910
911
  }
  
  static void vrf_ip6_input_dst(struct sk_buff *skb, struct net_device *vrf_dev,
  			      int ifindex)
  {
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
  	struct flowi6 fl6 = {
ecf091171   Arnd Bergmann   net: vrf: avoid g...
912
913
914
  		.flowi6_iif     = ifindex,
  		.flowi6_mark    = skb->mark,
  		.flowi6_proto   = iph->nexthdr,
9ff743846   David Ahern   net: vrf: Handle ...
915
916
917
  		.daddr          = iph->daddr,
  		.saddr          = iph->saddr,
  		.flowlabel      = ip6_flowinfo(iph),
9ff743846   David Ahern   net: vrf: Handle ...
918
919
920
  	};
  	struct net *net = dev_net(vrf_dev);
  	struct rt6_info *rt6;
b75cc8f90   David Ahern   net/ipv6: Pass sk...
921
  	rt6 = vrf_ip6_route_lookup(net, vrf_dev, &fl6, ifindex, skb,
9ff743846   David Ahern   net: vrf: Handle ...
922
923
924
925
926
927
928
929
930
  				   RT6_LOOKUP_F_HAS_SADDR | RT6_LOOKUP_F_IFACE);
  	if (unlikely(!rt6))
  		return;
  
  	if (unlikely(&rt6->dst == &net->ipv6.ip6_null_entry->dst))
  		return;
  
  	skb_dst_set(skb, &rt6->dst);
  }
74b20582a   David Ahern   net: l3mdev: Add ...
931
932
933
  static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
  				   struct sk_buff *skb)
  {
9ff743846   David Ahern   net: vrf: Handle ...
934
  	int orig_iif = skb->skb_iif;
6f12fa775   Mike Manning   vrf: mark skb for...
935
936
  	bool need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr);
  	bool is_ndisc = ipv6_ndisc_frame(skb);
9ff743846   David Ahern   net: vrf: Handle ...
937

6f12fa775   Mike Manning   vrf: mark skb for...
938
939
  	/* loopback, multicast & non-ND link-local traffic; do not push through
  	 * packet taps again. Reset pkt_type for upper layers to process skb
b4869aa2f   David Ahern   net: vrf: ipv6 su...
940
  	 */
6f12fa775   Mike Manning   vrf: mark skb for...
941
  	if (skb->pkt_type == PACKET_LOOPBACK || (need_strict && !is_ndisc)) {
b4869aa2f   David Ahern   net: vrf: ipv6 su...
942
943
  		skb->dev = vrf_dev;
  		skb->skb_iif = vrf_dev->ifindex;
a04a480d4   David Ahern   net: Require exac...
944
  		IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
6f12fa775   Mike Manning   vrf: mark skb for...
945
946
  		if (skb->pkt_type == PACKET_LOOPBACK)
  			skb->pkt_type = PACKET_HOST;
b4869aa2f   David Ahern   net: vrf: ipv6 su...
947
948
  		goto out;
  	}
6f12fa775   Mike Manning   vrf: mark skb for...
949
950
  	/* if packet is NDISC then keep the ingress interface */
  	if (!is_ndisc) {
926d93a33   David Ahern   net: vrf: Add mis...
951
  		vrf_rx_stats(vrf_dev, skb->len);
74b20582a   David Ahern   net: l3mdev: Add ...
952
953
  		skb->dev = vrf_dev;
  		skb->skb_iif = vrf_dev->ifindex;
a9ec54d1b   David Ahern   net: vrf: perform...
954
955
956
957
958
  		if (!list_empty(&vrf_dev->ptype_all)) {
  			skb_push(skb, skb->mac_len);
  			dev_queue_xmit_nit(skb, vrf_dev);
  			skb_pull(skb, skb->mac_len);
  		}
74b20582a   David Ahern   net: l3mdev: Add ...
959
960
961
  
  		IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
  	}
9ff743846   David Ahern   net: vrf: Handle ...
962
963
  	if (need_strict)
  		vrf_ip6_input_dst(skb, vrf_dev, orig_iif);
73e20b761   David Ahern   net: vrf: Add sup...
964
  	skb = vrf_rcv_nfhook(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, vrf_dev);
b4869aa2f   David Ahern   net: vrf: ipv6 su...
965
  out:
74b20582a   David Ahern   net: l3mdev: Add ...
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
  	return skb;
  }
  
  #else
  static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
  				   struct sk_buff *skb)
  {
  	return skb;
  }
  #endif
  
  static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
  				  struct sk_buff *skb)
  {
  	skb->dev = vrf_dev;
  	skb->skb_iif = vrf_dev->ifindex;
a04a480d4   David Ahern   net: Require exac...
982
  	IPCB(skb)->flags |= IPSKB_L3SLAVE;
74b20582a   David Ahern   net: l3mdev: Add ...
983

e58e41596   David Ahern   net: Enable suppo...
984
985
  	if (ipv4_is_multicast(ip_hdr(skb)->daddr))
  		goto out;
afe80a499   David Ahern   net: vrf: ipv4 su...
986
987
988
989
990
991
992
  	/* loopback traffic; do not push through packet taps again.
  	 * Reset pkt_type for upper layers to process skb
  	 */
  	if (skb->pkt_type == PACKET_LOOPBACK) {
  		skb->pkt_type = PACKET_HOST;
  		goto out;
  	}
926d93a33   David Ahern   net: vrf: Add mis...
993
  	vrf_rx_stats(vrf_dev, skb->len);
dcdd43c41   David Ahern   net: vrf: perform...
994
995
996
997
998
  	if (!list_empty(&vrf_dev->ptype_all)) {
  		skb_push(skb, skb->mac_len);
  		dev_queue_xmit_nit(skb, vrf_dev);
  		skb_pull(skb, skb->mac_len);
  	}
74b20582a   David Ahern   net: l3mdev: Add ...
999

73e20b761   David Ahern   net: vrf: Add sup...
1000
  	skb = vrf_rcv_nfhook(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, vrf_dev);
afe80a499   David Ahern   net: vrf: ipv4 su...
1001
  out:
74b20582a   David Ahern   net: l3mdev: Add ...
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  	return skb;
  }
  
  /* called with rcu lock held */
  static struct sk_buff *vrf_l3_rcv(struct net_device *vrf_dev,
  				  struct sk_buff *skb,
  				  u16 proto)
  {
  	switch (proto) {
  	case AF_INET:
  		return vrf_ip_rcv(vrf_dev, skb);
  	case AF_INET6:
  		return vrf_ip6_rcv(vrf_dev, skb);
  	}
  
  	return skb;
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
4c1feac58   David Ahern   net: vrf: Flip IP...
1021
1022
  /* send to link-local or multicast address via interface enslaved to
   * VRF device. Force lookup to VRF table without changing flow struct
7d9e5f422   Wei Wang   ipv6: convert maj...
1023
1024
   * Note: Caller to this function must hold rcu_read_lock() and no refcnt
   * is taken on the dst by this function.
4c1feac58   David Ahern   net: vrf: Flip IP...
1025
1026
1027
   */
  static struct dst_entry *vrf_link_scope_lookup(const struct net_device *dev,
  					      struct flowi6 *fl6)
35402e313   David Ahern   net: Add IPv6 sup...
1028
  {
9ff743846   David Ahern   net: vrf: Handle ...
1029
  	struct net *net = dev_net(dev);
7d9e5f422   Wei Wang   ipv6: convert maj...
1030
  	int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_DST_NOREF;
b0e95ccdd   David Ahern   net: vrf: protect...
1031
  	struct dst_entry *dst = NULL;
9ff743846   David Ahern   net: vrf: Handle ...
1032
  	struct rt6_info *rt;
35402e313   David Ahern   net: Add IPv6 sup...
1033

4c1feac58   David Ahern   net: vrf: Flip IP...
1034
1035
1036
1037
1038
1039
  	/* VRF device does not have a link-local address and
  	 * sending packets to link-local or mcast addresses over
  	 * a VRF device does not make sense
  	 */
  	if (fl6->flowi6_oif == dev->ifindex) {
  		dst = &net->ipv6.ip6_null_entry->dst;
4c1feac58   David Ahern   net: vrf: Flip IP...
1040
  		return dst;
35402e313   David Ahern   net: Add IPv6 sup...
1041
  	}
4c1feac58   David Ahern   net: vrf: Flip IP...
1042
1043
  	if (!ipv6_addr_any(&fl6->saddr))
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
b75cc8f90   David Ahern   net/ipv6: Pass sk...
1044
  	rt = vrf_ip6_route_lookup(net, dev, fl6, fl6->flowi6_oif, NULL, flags);
4c1feac58   David Ahern   net: vrf: Flip IP...
1045
1046
  	if (rt)
  		dst = &rt->dst;
9ff743846   David Ahern   net: vrf: Handle ...
1047

b0e95ccdd   David Ahern   net: vrf: protect...
1048
  	return dst;
35402e313   David Ahern   net: Add IPv6 sup...
1049
1050
  }
  #endif
ee15ee5d9   David Ahern   net: Add support ...
1051
1052
  static const struct l3mdev_ops vrf_l3mdev_ops = {
  	.l3mdev_fib_table	= vrf_fib_table,
74b20582a   David Ahern   net: l3mdev: Add ...
1053
  	.l3mdev_l3_rcv		= vrf_l3_rcv,
ebfc102c5   David Ahern   net: vrf: Flip IP...
1054
  	.l3mdev_l3_out		= vrf_l3_out,
35402e313   David Ahern   net: Add IPv6 sup...
1055
  #if IS_ENABLED(CONFIG_IPV6)
4c1feac58   David Ahern   net: vrf: Flip IP...
1056
  	.l3mdev_link_scope_lookup = vrf_link_scope_lookup,
35402e313   David Ahern   net: Add IPv6 sup...
1057
  #endif
ee15ee5d9   David Ahern   net: Add support ...
1058
  };
193125dbd   David Ahern   net: Introduce VR...
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
  static void vrf_get_drvinfo(struct net_device *dev,
  			    struct ethtool_drvinfo *info)
  {
  	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
  	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
  }
  
  static const struct ethtool_ops vrf_ethtool_ops = {
  	.get_drvinfo	= vrf_get_drvinfo,
  };
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1069
1070
1071
1072
1073
1074
1075
  static inline size_t vrf_fib_rule_nl_size(void)
  {
  	size_t sz;
  
  	sz  = NLMSG_ALIGN(sizeof(struct fib_rule_hdr));
  	sz += nla_total_size(sizeof(u8));	/* FRA_L3MDEV */
  	sz += nla_total_size(sizeof(u32));	/* FRA_PRIORITY */
1b71af605   Donald Sharp   net: fib_rules: A...
1076
  	sz += nla_total_size(sizeof(u8));       /* FRA_PROTOCOL */
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  
  	return sz;
  }
  
  static int vrf_fib_rule(const struct net_device *dev, __u8 family, bool add_it)
  {
  	struct fib_rule_hdr *frh;
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
  	int err;
dac91170f   David Ahern   vrf: Do not attem...
1087
1088
  	if ((family == AF_INET6 || family == RTNL_FAMILY_IP6MR) &&
  	    !ipv6_mod_enabled())
e43486371   David Ahern   net: vrf: Fix cra...
1089
  		return 0;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1090
1091
1092
1093
1094
1095
1096
1097
1098
  	skb = nlmsg_new(vrf_fib_rule_nl_size(), GFP_KERNEL);
  	if (!skb)
  		return -ENOMEM;
  
  	nlh = nlmsg_put(skb, 0, 0, 0, sizeof(*frh), 0);
  	if (!nlh)
  		goto nla_put_failure;
  
  	/* rule only needs to appear once */
426c87caa   David Ahern   net: vrf: Fix set...
1099
  	nlh->nlmsg_flags |= NLM_F_EXCL;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1100
1101
1102
1103
1104
  
  	frh = nlmsg_data(nlh);
  	memset(frh, 0, sizeof(*frh));
  	frh->family = family;
  	frh->action = FR_ACT_TO_TBL;
1b71af605   Donald Sharp   net: fib_rules: A...
1105
1106
1107
  
  	if (nla_put_u8(skb, FRA_PROTOCOL, RTPROT_KERNEL))
  		goto nla_put_failure;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1108

18129a249   Jeff Barnhill   net: vrf: correct...
1109
  	if (nla_put_u8(skb, FRA_L3MDEV, 1))
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  		goto nla_put_failure;
  
  	if (nla_put_u32(skb, FRA_PRIORITY, FIB_RULE_PREF))
  		goto nla_put_failure;
  
  	nlmsg_end(skb, nlh);
  
  	/* fib_nl_{new,del}rule handling looks for net from skb->sk */
  	skb->sk = dev_net(dev)->rtnl;
  	if (add_it) {
c21ef3e34   David Ahern   net: rtnetlink: p...
1120
  		err = fib_nl_newrule(skb, nlh, NULL);
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1121
1122
1123
  		if (err == -EEXIST)
  			err = 0;
  	} else {
c21ef3e34   David Ahern   net: rtnetlink: p...
1124
  		err = fib_nl_delrule(skb, nlh, NULL);
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  		if (err == -ENOENT)
  			err = 0;
  	}
  	nlmsg_free(skb);
  
  	return err;
  
  nla_put_failure:
  	nlmsg_free(skb);
  
  	return -EMSGSIZE;
  }
  
  static int vrf_add_fib_rules(const struct net_device *dev)
  {
  	int err;
  
  	err = vrf_fib_rule(dev, AF_INET,  true);
  	if (err < 0)
  		goto out_err;
  
  	err = vrf_fib_rule(dev, AF_INET6, true);
  	if (err < 0)
  		goto ipv6_err;
e58e41596   David Ahern   net: Enable suppo...
1149
1150
1151
1152
1153
  #if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)
  	err = vrf_fib_rule(dev, RTNL_FAMILY_IPMR, true);
  	if (err < 0)
  		goto ipmr_err;
  #endif
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1154
1155
1156
1157
1158
  #if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
  	err = vrf_fib_rule(dev, RTNL_FAMILY_IP6MR, true);
  	if (err < 0)
  		goto ip6mr_err;
  #endif
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1159
  	return 0;
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1160
1161
1162
1163
  #if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
  ip6mr_err:
  	vrf_fib_rule(dev, RTNL_FAMILY_IPMR,  false);
  #endif
e58e41596   David Ahern   net: Enable suppo...
1164
1165
1166
1167
  #if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)
  ipmr_err:
  	vrf_fib_rule(dev, AF_INET6,  false);
  #endif
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1168
1169
1170
1171
1172
1173
1174
1175
  ipv6_err:
  	vrf_fib_rule(dev, AF_INET,  false);
  
  out_err:
  	netdev_err(dev, "Failed to add FIB rules.
  ");
  	return err;
  }
193125dbd   David Ahern   net: Introduce VR...
1176
1177
1178
1179
1180
1181
  static void vrf_setup(struct net_device *dev)
  {
  	ether_setup(dev);
  
  	/* Initialize the device structure. */
  	dev->netdev_ops = &vrf_netdev_ops;
ee15ee5d9   David Ahern   net: Add support ...
1182
  	dev->l3mdev_ops = &vrf_l3mdev_ops;
193125dbd   David Ahern   net: Introduce VR...
1183
  	dev->ethtool_ops = &vrf_ethtool_ops;
cf124db56   David S. Miller   net: Fix inconsis...
1184
  	dev->needs_free_netdev = true;
193125dbd   David Ahern   net: Introduce VR...
1185
1186
1187
1188
1189
1190
1191
1192
1193
  
  	/* Fill in device structure with ethernet-generic values. */
  	eth_hw_addr_random(dev);
  
  	/* don't acquire vrf device's netif_tx_lock when transmitting */
  	dev->features |= NETIF_F_LLTX;
  
  	/* don't allow vrf devices to change network namespaces. */
  	dev->features |= NETIF_F_NETNS_LOCAL;
7889681f4   David Ahern   net: vrf: Update ...
1194
1195
1196
1197
1198
1199
  
  	/* does not make sense for a VLAN to be added to a vrf device */
  	dev->features   |= NETIF_F_VLAN_CHALLENGED;
  
  	/* enable offload features */
  	dev->features   |= NETIF_F_GSO_SOFTWARE;
cb1603948   Davide Caratti   vrf: add CRC32c o...
1200
  	dev->features   |= NETIF_F_RXCSUM | NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC;
7889681f4   David Ahern   net: vrf: Update ...
1201
1202
1203
1204
1205
1206
1207
  	dev->features   |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA;
  
  	dev->hw_features = dev->features;
  	dev->hw_enc_features = dev->features;
  
  	/* default to no qdisc; user can add if desired */
  	dev->priv_flags |= IFF_NO_QUEUE;
1017e0987   Sabrina Dubroca   vrf: prevent addi...
1208
  	dev->priv_flags |= IFF_NO_RX_HANDLER;
6819e3f6d   Miaohe Lin   net: vrf: Fix ope...
1209
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
ad49bc636   Hangbin Liu   net: vrf: remove ...
1210

5055376a3   Miaohe Lin   net: vrf: Fix pin...
1211
1212
1213
1214
1215
1216
  	/* VRF devices do not care about MTU, but if the MTU is set
  	 * too low then the ipv4 and ipv6 protocols are disabled
  	 * which breaks networking.
  	 */
  	dev->min_mtu = IPV6_MIN_MTU;
  	dev->max_mtu = ETH_MAX_MTU;
193125dbd   David Ahern   net: Introduce VR...
1217
  }
a8b8a889e   Matthias Schiffer   net: add netlink_...
1218
1219
  static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],
  			struct netlink_ext_ack *extack)
193125dbd   David Ahern   net: Introduce VR...
1220
1221
  {
  	if (tb[IFLA_ADDRESS]) {
53b948356   David Ahern   net: vrf: Add ext...
1222
1223
  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
  			NL_SET_ERR_MSG(extack, "Invalid hardware address");
193125dbd   David Ahern   net: Introduce VR...
1224
  			return -EINVAL;
53b948356   David Ahern   net: vrf: Add ext...
1225
1226
1227
  		}
  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
  			NL_SET_ERR_MSG(extack, "Invalid hardware address");
193125dbd   David Ahern   net: Introduce VR...
1228
  			return -EADDRNOTAVAIL;
53b948356   David Ahern   net: vrf: Add ext...
1229
  		}
193125dbd   David Ahern   net: Introduce VR...
1230
1231
1232
1233
1234
1235
  	}
  	return 0;
  }
  
  static void vrf_dellink(struct net_device *dev, struct list_head *head)
  {
f630c38ef   Nikolay Aleksandrov   vrf: fix bug_on t...
1236
1237
1238
1239
1240
  	struct net_device *port_dev;
  	struct list_head *iter;
  
  	netdev_for_each_lower_dev(dev, port_dev, iter)
  		vrf_del_slave(dev, port_dev);
193125dbd   David Ahern   net: Introduce VR...
1241
1242
1243
1244
  	unregister_netdevice_queue(dev, head);
  }
  
  static int vrf_newlink(struct net *src_net, struct net_device *dev,
7a3f4a185   Matthias Schiffer   net: add netlink_...
1245
1246
  		       struct nlattr *tb[], struct nlattr *data[],
  		       struct netlink_ext_ack *extack)
193125dbd   David Ahern   net: Introduce VR...
1247
1248
  {
  	struct net_vrf *vrf = netdev_priv(dev);
097d3c950   David Ahern   net: vrf: Make ad...
1249
1250
  	bool *add_fib_rules;
  	struct net *net;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1251
  	int err;
193125dbd   David Ahern   net: Introduce VR...
1252

53b948356   David Ahern   net: vrf: Add ext...
1253
1254
  	if (!data || !data[IFLA_VRF_TABLE]) {
  		NL_SET_ERR_MSG(extack, "VRF table id is missing");
193125dbd   David Ahern   net: Introduce VR...
1255
  		return -EINVAL;
53b948356   David Ahern   net: vrf: Add ext...
1256
  	}
193125dbd   David Ahern   net: Introduce VR...
1257
1258
  
  	vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]);
53b948356   David Ahern   net: vrf: Add ext...
1259
1260
1261
  	if (vrf->tb_id == RT_TABLE_UNSPEC) {
  		NL_SET_ERR_MSG_ATTR(extack, data[IFLA_VRF_TABLE],
  				    "Invalid VRF table id");
24c63bbc1   David Ahern   net: vrf: do not ...
1262
  		return -EINVAL;
53b948356   David Ahern   net: vrf: Add ext...
1263
  	}
193125dbd   David Ahern   net: Introduce VR...
1264

007979eaf   David Ahern   net: Rename IFF_V...
1265
  	dev->priv_flags |= IFF_L3MDEV_MASTER;
193125dbd   David Ahern   net: Introduce VR...
1266

1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1267
1268
1269
  	err = register_netdevice(dev);
  	if (err)
  		goto out;
097d3c950   David Ahern   net: vrf: Make ad...
1270
1271
1272
  	net = dev_net(dev);
  	add_fib_rules = net_generic(net, vrf_net_id);
  	if (*add_fib_rules) {
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1273
1274
1275
1276
1277
  		err = vrf_add_fib_rules(dev);
  		if (err) {
  			unregister_netdevice(dev);
  			goto out;
  		}
097d3c950   David Ahern   net: vrf: Make ad...
1278
  		*add_fib_rules = false;
1aa6c4f6b   David Ahern   net: vrf: Add l3m...
1279
1280
1281
1282
  	}
  
  out:
  	return err;
193125dbd   David Ahern   net: Introduce VR...
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
  }
  
  static size_t vrf_nl_getsize(const struct net_device *dev)
  {
  	return nla_total_size(sizeof(u32));  /* IFLA_VRF_TABLE */
  }
  
  static int vrf_fillinfo(struct sk_buff *skb,
  			const struct net_device *dev)
  {
  	struct net_vrf *vrf = netdev_priv(dev);
  
  	return nla_put_u32(skb, IFLA_VRF_TABLE, vrf->tb_id);
  }
67eb03318   David Ahern   net: Add support ...
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
  static size_t vrf_get_slave_size(const struct net_device *bond_dev,
  				 const struct net_device *slave_dev)
  {
  	return nla_total_size(sizeof(u32));  /* IFLA_VRF_PORT_TABLE */
  }
  
  static int vrf_fill_slave_info(struct sk_buff *skb,
  			       const struct net_device *vrf_dev,
  			       const struct net_device *slave_dev)
  {
  	struct net_vrf *vrf = netdev_priv(vrf_dev);
  
  	if (nla_put_u32(skb, IFLA_VRF_PORT_TABLE, vrf->tb_id))
  		return -EMSGSIZE;
  
  	return 0;
  }
193125dbd   David Ahern   net: Introduce VR...
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
  static const struct nla_policy vrf_nl_policy[IFLA_VRF_MAX + 1] = {
  	[IFLA_VRF_TABLE] = { .type = NLA_U32 },
  };
  
  static struct rtnl_link_ops vrf_link_ops __read_mostly = {
  	.kind		= DRV_NAME,
  	.priv_size	= sizeof(struct net_vrf),
  
  	.get_size	= vrf_nl_getsize,
  	.policy		= vrf_nl_policy,
  	.validate	= vrf_validate,
  	.fill_info	= vrf_fillinfo,
67eb03318   David Ahern   net: Add support ...
1326
1327
  	.get_slave_size  = vrf_get_slave_size,
  	.fill_slave_info = vrf_fill_slave_info,
193125dbd   David Ahern   net: Introduce VR...
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
  	.newlink	= vrf_newlink,
  	.dellink	= vrf_dellink,
  	.setup		= vrf_setup,
  	.maxtype	= IFLA_VRF_MAX,
  };
  
  static int vrf_device_event(struct notifier_block *unused,
  			    unsigned long event, void *ptr)
  {
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  
  	/* only care about unregister events to drop slave references */
  	if (event == NETDEV_UNREGISTER) {
193125dbd   David Ahern   net: Introduce VR...
1341
  		struct net_device *vrf_dev;
fee6d4c77   David Ahern   net: Add netif_is...
1342
  		if (!netif_is_l3_slave(dev))
193125dbd   David Ahern   net: Introduce VR...
1343
  			goto out;
58aa90875   Nikolay Aleksandrov   vrf: simplify the...
1344
1345
  		vrf_dev = netdev_master_upper_dev_get(dev);
  		vrf_del_slave(vrf_dev, dev);
193125dbd   David Ahern   net: Introduce VR...
1346
1347
1348
1349
1350
1351
1352
1353
  	}
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block vrf_notifier_block __read_mostly = {
  	.notifier_call = vrf_device_event,
  };
097d3c950   David Ahern   net: vrf: Make ad...
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  /* Initialize per network namespace state */
  static int __net_init vrf_netns_init(struct net *net)
  {
  	bool *add_fib_rules = net_generic(net, vrf_net_id);
  
  	*add_fib_rules = true;
  
  	return 0;
  }
  
  static struct pernet_operations vrf_net_ops __net_initdata = {
  	.init = vrf_netns_init,
  	.id   = &vrf_net_id,
  	.size = sizeof(bool),
  };
193125dbd   David Ahern   net: Introduce VR...
1369
1370
1371
  static int __init vrf_init_module(void)
  {
  	int rc;
193125dbd   David Ahern   net: Introduce VR...
1372
  	register_netdevice_notifier(&vrf_notifier_block);
097d3c950   David Ahern   net: vrf: Make ad...
1373
  	rc = register_pernet_subsys(&vrf_net_ops);
193125dbd   David Ahern   net: Introduce VR...
1374
1375
  	if (rc < 0)
  		goto error;
097d3c950   David Ahern   net: vrf: Make ad...
1376
1377
1378
1379
1380
  	rc = rtnl_link_register(&vrf_link_ops);
  	if (rc < 0) {
  		unregister_pernet_subsys(&vrf_net_ops);
  		goto error;
  	}
193125dbd   David Ahern   net: Introduce VR...
1381
1382
1383
1384
  	return 0;
  
  error:
  	unregister_netdevice_notifier(&vrf_notifier_block);
193125dbd   David Ahern   net: Introduce VR...
1385
1386
  	return rc;
  }
193125dbd   David Ahern   net: Introduce VR...
1387
  module_init(vrf_init_module);
193125dbd   David Ahern   net: Introduce VR...
1388
1389
1390
1391
1392
  MODULE_AUTHOR("Shrijeet Mukherjee, David Ahern");
  MODULE_DESCRIPTION("Device driver to instantiate VRF domains");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_RTNL_LINK(DRV_NAME);
  MODULE_VERSION(DRV_VERSION);