aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vrf.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-06-06 18:58:34 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-06 18:58:34 -0400
commit3d9dc408fa6abf8dd1ea39e243e565891004a6f9 (patch)
treecea538919fffbe282da9040e56662b651f56545c /drivers/net/vrf.c
parent2fb7ea455d57e22110c54fc2de0656b6f744263c (diff)
net: Revert vrf-local changes.
This reverts commit 2fb7ea455d57e22110c54fc2de0656b6f744263c. It results in build errors because ip6_input is not a symbol exported to modules. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vrf.c')
-rw-r--r--drivers/net/vrf.c234
1 files changed, 33 insertions, 201 deletions
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 1b214ea4619a..d356f5d0f7b0 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -44,9 +44,7 @@
44 44
45struct net_vrf { 45struct net_vrf {
46 struct rtable __rcu *rth; 46 struct rtable __rcu *rth;
47 struct rtable __rcu *rth_local;
48 struct rt6_info __rcu *rt6; 47 struct rt6_info __rcu *rt6;
49 struct rt6_info __rcu *rt6_local;
50 u32 tb_id; 48 u32 tb_id;
51}; 49};
52 50
@@ -56,20 +54,9 @@ struct pcpu_dstats {
56 u64 tx_drps; 54 u64 tx_drps;
57 u64 rx_pkts; 55 u64 rx_pkts;
58 u64 rx_bytes; 56 u64 rx_bytes;
59 u64 rx_drps;
60 struct u64_stats_sync syncp; 57 struct u64_stats_sync syncp;
61}; 58};
62 59
63static void vrf_rx_stats(struct net_device *dev, int len)
64{
65 struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
66
67 u64_stats_update_begin(&dstats->syncp);
68 dstats->rx_pkts++;
69 dstats->rx_bytes += len;
70 u64_stats_update_end(&dstats->syncp);
71}
72
73static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb) 60static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
74{ 61{
75 vrf_dev->stats.tx_errors++; 62 vrf_dev->stats.tx_errors++;
@@ -104,34 +91,6 @@ static struct rtnl_link_stats64 *vrf_get_stats64(struct net_device *dev,
104 return stats; 91 return stats;
105} 92}
106 93
107/* Local traffic destined to local address. Reinsert the packet to rx
108 * path, similar to loopback handling.
109 */
110static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
111 struct dst_entry *dst)
112{
113 int len = skb->len;
114
115 skb_orphan(skb);
116
117 skb_dst_set(skb, dst);
118 skb_dst_force(skb);
119
120 /* set pkt_type to avoid skb hitting packet taps twice -
121 * once on Tx and again in Rx processing
122 */
123 skb->pkt_type = PACKET_LOOPBACK;
124
125 skb->protocol = eth_type_trans(skb, dev);
126
127 if (likely(netif_rx(skb) == NET_RX_SUCCESS))
128 vrf_rx_stats(dev, len);
129 else
130 this_cpu_inc(dev->dstats->rx_drps);
131
132 return NETDEV_TX_OK;
133}
134
135#if IS_ENABLED(CONFIG_IPV6) 94#if IS_ENABLED(CONFIG_IPV6)
136static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb, 95static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
137 struct net_device *dev) 96 struct net_device *dev)
@@ -158,51 +117,8 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
158 goto err; 117 goto err;
159 118
160 skb_dst_drop(skb); 119 skb_dst_drop(skb);
161
162 /* if dst.dev is loopback or the VRF device again this is locally
163 * originated traffic destined to a local address. Short circuit
164 * to Rx path using our local dst
165 */
166 if (dst->dev == net->loopback_dev || dst->dev == dev) {
167 struct net_vrf *vrf = netdev_priv(dev);
168 struct rt6_info *rt6_local;
169
170 /* release looked up dst and use cached local dst */
171 dst_release(dst);
172
173 rcu_read_lock();
174
175 rt6_local = rcu_dereference(vrf->rt6_local);
176 if (unlikely(!rt6_local)) {
177 rcu_read_unlock();
178 goto err;
179 }
180
181 /* Ordering issue: cached local dst is created on newlink
182 * before the IPv6 initialization. Using the local dst
183 * requires rt6i_idev to be set so make sure it is.
184 */
185 if (unlikely(!rt6_local->rt6i_idev)) {
186 rt6_local->rt6i_idev = in6_dev_get(dev);
187 if (!rt6_local->rt6i_idev) {
188 rcu_read_unlock();
189 goto err;
190 }
191 }
192
193 dst = &rt6_local->dst;
194 dst_hold(dst);
195
196 rcu_read_unlock();
197
198 return vrf_local_xmit(skb, dev, &rt6_local->dst);
199 }
200
201 skb_dst_set(skb, dst); 120 skb_dst_set(skb, dst);
202 121
203 /* strip the ethernet header added for pass through VRF device */
204 __skb_pull(skb, skb_network_offset(skb));
205
206 ret = ip6_local_out(net, skb->sk, skb); 122 ret = ip6_local_out(net, skb->sk, skb);
207 if (unlikely(net_xmit_eval(ret))) 123 if (unlikely(net_xmit_eval(ret)))
208 dev->stats.tx_errors++; 124 dev->stats.tx_errors++;
@@ -223,6 +139,29 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
223} 139}
224#endif 140#endif
225 141
142static int vrf_send_v4_prep(struct sk_buff *skb, struct flowi4 *fl4,
143 struct net_device *vrf_dev)
144{
145 struct rtable *rt;
146 int err = 1;
147
148 rt = ip_route_output_flow(dev_net(vrf_dev), fl4, NULL);
149 if (IS_ERR(rt))
150 goto out;
151
152 /* TO-DO: what about broadcast ? */
153 if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
154 ip_rt_put(rt);
155 goto out;
156 }
157
158 skb_dst_drop(skb);
159 skb_dst_set(skb, &rt->dst);
160 err = 0;
161out:
162 return err;
163}
164
226static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, 165static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
227 struct net_device *vrf_dev) 166 struct net_device *vrf_dev)
228{ 167{
@@ -237,51 +176,9 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
237 FLOWI_FLAG_SKIP_NH_OIF, 176 FLOWI_FLAG_SKIP_NH_OIF,
238 .daddr = ip4h->daddr, 177 .daddr = ip4h->daddr,
239 }; 178 };
240 struct net *net = dev_net(vrf_dev);
241 struct rtable *rt;
242
243 rt = ip_route_output_flow(net, &fl4, NULL);
244 if (IS_ERR(rt))
245 goto err;
246 179
247 if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) { 180 if (vrf_send_v4_prep(skb, &fl4, vrf_dev))
248 ip_rt_put(rt);
249 goto err; 181 goto err;
250 }
251
252 skb_dst_drop(skb);
253
254 /* if dst.dev is loopback or the VRF device again this is locally
255 * originated traffic destined to a local address. Short circuit
256 * to Rx path using our local dst
257 */
258 if (rt->dst.dev == net->loopback_dev || rt->dst.dev == vrf_dev) {
259 struct net_vrf *vrf = netdev_priv(vrf_dev);
260 struct rtable *rth_local;
261 struct dst_entry *dst = NULL;
262
263 ip_rt_put(rt);
264
265 rcu_read_lock();
266
267 rth_local = rcu_dereference(vrf->rth_local);
268 if (likely(rth_local)) {
269 dst = &rth_local->dst;
270 dst_hold(dst);
271 }
272
273 rcu_read_unlock();
274
275 if (unlikely(!dst))
276 goto err;
277
278 return vrf_local_xmit(skb, vrf_dev, dst);
279 }
280
281 skb_dst_set(skb, &rt->dst);
282
283 /* strip the ethernet header added for pass through VRF device */
284 __skb_pull(skb, skb_network_offset(skb));
285 182
286 if (!ip4h->saddr) { 183 if (!ip4h->saddr) {
287 ip4h->saddr = inet_select_addr(skb_dst(skb)->dev, 0, 184 ip4h->saddr = inet_select_addr(skb_dst(skb)->dev, 0,
@@ -303,6 +200,9 @@ err:
303 200
304static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev) 201static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
305{ 202{
203 /* strip the ethernet header added for pass through VRF device */
204 __skb_pull(skb, skb_network_offset(skb));
205
306 switch (skb->protocol) { 206 switch (skb->protocol) {
307 case htons(ETH_P_IP): 207 case htons(ETH_P_IP):
308 return vrf_process_v4_outbound(skb, dev); 208 return vrf_process_v4_outbound(skb, dev);
@@ -377,38 +277,27 @@ static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
377static void vrf_rt6_release(struct net_vrf *vrf) 277static void vrf_rt6_release(struct net_vrf *vrf)
378{ 278{
379 struct rt6_info *rt6 = rtnl_dereference(vrf->rt6); 279 struct rt6_info *rt6 = rtnl_dereference(vrf->rt6);
380 struct rt6_info *rt6_local = rtnl_dereference(vrf->rt6_local);
381 280
382 RCU_INIT_POINTER(vrf->rt6, NULL); 281 rcu_assign_pointer(vrf->rt6, NULL);
383 RCU_INIT_POINTER(vrf->rt6_local, NULL);
384 synchronize_rcu();
385 282
386 if (rt6) 283 if (rt6)
387 dst_release(&rt6->dst); 284 dst_release(&rt6->dst);
388
389 if (rt6_local) {
390 if (rt6_local->rt6i_idev)
391 in6_dev_put(rt6_local->rt6i_idev);
392
393 dst_release(&rt6_local->dst);
394 }
395} 285}
396 286
397static int vrf_rt6_create(struct net_device *dev) 287static int vrf_rt6_create(struct net_device *dev)
398{ 288{
399 int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE;
400 struct net_vrf *vrf = netdev_priv(dev); 289 struct net_vrf *vrf = netdev_priv(dev);
401 struct net *net = dev_net(dev); 290 struct net *net = dev_net(dev);
402 struct fib6_table *rt6i_table; 291 struct fib6_table *rt6i_table;
403 struct rt6_info *rt6, *rt6_local; 292 struct rt6_info *rt6;
404 int rc = -ENOMEM; 293 int rc = -ENOMEM;
405 294
406 rt6i_table = fib6_new_table(net, vrf->tb_id); 295 rt6i_table = fib6_new_table(net, vrf->tb_id);
407 if (!rt6i_table) 296 if (!rt6i_table)
408 goto out; 297 goto out;
409 298
410 /* create a dst for routing packets out a VRF device */ 299 rt6 = ip6_dst_alloc(net, dev,
411 rt6 = ip6_dst_alloc(net, dev, flags); 300 DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
412 if (!rt6) 301 if (!rt6)
413 goto out; 302 goto out;
414 303
@@ -416,25 +305,7 @@ static int vrf_rt6_create(struct net_device *dev)
416 305
417 rt6->rt6i_table = rt6i_table; 306 rt6->rt6i_table = rt6i_table;
418 rt6->dst.output = vrf_output6; 307 rt6->dst.output = vrf_output6;
419
420 /* create a dst for local routing - packets sent locally
421 * to local address via the VRF device as a loopback
422 */
423 rt6_local = ip6_dst_alloc(net, dev, flags);
424 if (!rt6_local) {
425 dst_release(&rt6->dst);
426 goto out;
427 }
428
429 dst_hold(&rt6_local->dst);
430
431 rt6_local->rt6i_idev = in6_dev_get(dev);
432 rt6_local->rt6i_flags = RTF_UP | RTF_NONEXTHOP | RTF_LOCAL;
433 rt6_local->rt6i_table = rt6i_table;
434 rt6_local->dst.input = ip6_input;
435
436 rcu_assign_pointer(vrf->rt6, rt6); 308 rcu_assign_pointer(vrf->rt6, rt6);
437 rcu_assign_pointer(vrf->rt6_local, rt6_local);
438 309
439 rc = 0; 310 rc = 0;
440out: 311out:
@@ -513,48 +384,29 @@ static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)
513static void vrf_rtable_release(struct net_vrf *vrf) 384static void vrf_rtable_release(struct net_vrf *vrf)
514{ 385{
515 struct rtable *rth = rtnl_dereference(vrf->rth); 386 struct rtable *rth = rtnl_dereference(vrf->rth);
516 struct rtable *rth_local = rtnl_dereference(vrf->rth_local);
517 387
518 RCU_INIT_POINTER(vrf->rth, NULL); 388 rcu_assign_pointer(vrf->rth, NULL);
519 RCU_INIT_POINTER(vrf->rth_local, NULL);
520 synchronize_rcu();
521 389
522 if (rth) 390 if (rth)
523 dst_release(&rth->dst); 391 dst_release(&rth->dst);
524
525 if (rth_local)
526 dst_release(&rth_local->dst);
527} 392}
528 393
529static int vrf_rtable_create(struct net_device *dev) 394static int vrf_rtable_create(struct net_device *dev)
530{ 395{
531 struct net_vrf *vrf = netdev_priv(dev); 396 struct net_vrf *vrf = netdev_priv(dev);
532 struct rtable *rth, *rth_local; 397 struct rtable *rth;
533 398
534 if (!fib_new_table(dev_net(dev), vrf->tb_id)) 399 if (!fib_new_table(dev_net(dev), vrf->tb_id))
535 return -ENOMEM; 400 return -ENOMEM;
536 401
537 /* create a dst for routing packets out through a VRF device */
538 rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0); 402 rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
539 if (!rth) 403 if (!rth)
540 return -ENOMEM; 404 return -ENOMEM;
541 405
542 /* create a dst for local ingress routing - packets sent locally
543 * to local address via the VRF device as a loopback
544 */
545 rth_local = rt_dst_alloc(dev, RTCF_LOCAL, RTN_LOCAL, 1, 1, 0);
546 if (!rth_local) {
547 dst_release(&rth->dst);
548 return -ENOMEM;
549 }
550
551 rth->dst.output = vrf_output; 406 rth->dst.output = vrf_output;
552 rth->rt_table_id = vrf->tb_id; 407 rth->rt_table_id = vrf->tb_id;
553 408
554 rth_local->rt_table_id = vrf->tb_id;
555
556 rcu_assign_pointer(vrf->rth, rth); 409 rcu_assign_pointer(vrf->rth, rth);
557 rcu_assign_pointer(vrf->rth_local, rth_local);
558 410
559 return 0; 411 return 0;
560} 412}
@@ -780,16 +632,6 @@ out:
780static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, 632static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
781 struct sk_buff *skb) 633 struct sk_buff *skb)
782{ 634{
783 /* loopback traffic; do not push through packet taps again.
784 * Reset pkt_type for upper layers to process skb
785 */
786 if (skb->pkt_type == PACKET_LOOPBACK) {
787 skb->dev = vrf_dev;
788 skb->skb_iif = vrf_dev->ifindex;
789 skb->pkt_type = PACKET_HOST;
790 goto out;
791 }
792
793 /* if packet is NDISC keep the ingress interface */ 635 /* if packet is NDISC keep the ingress interface */
794 if (!ipv6_ndisc_frame(skb)) { 636 if (!ipv6_ndisc_frame(skb)) {
795 skb->dev = vrf_dev; 637 skb->dev = vrf_dev;
@@ -802,7 +644,6 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
802 IP6CB(skb)->flags |= IP6SKB_L3SLAVE; 644 IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
803 } 645 }
804 646
805out:
806 return skb; 647 return skb;
807} 648}
808 649
@@ -820,19 +661,10 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
820 skb->dev = vrf_dev; 661 skb->dev = vrf_dev;
821 skb->skb_iif = vrf_dev->ifindex; 662 skb->skb_iif = vrf_dev->ifindex;
822 663
823 /* loopback traffic; do not push through packet taps again.
824 * Reset pkt_type for upper layers to process skb
825 */
826 if (skb->pkt_type == PACKET_LOOPBACK) {
827 skb->pkt_type = PACKET_HOST;
828 goto out;
829 }
830
831 skb_push(skb, skb->mac_len); 664 skb_push(skb, skb->mac_len);
832 dev_queue_xmit_nit(skb, vrf_dev); 665 dev_queue_xmit_nit(skb, vrf_dev);
833 skb_pull(skb, skb->mac_len); 666 skb_pull(skb, skb->mac_len);
834 667
835out:
836 return skb; 668 return skb;
837} 669}
838 670