diff options
author | David S. Miller <davem@davemloft.net> | 2016-06-06 18:58:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-06-06 18:58:34 -0400 |
commit | 3d9dc408fa6abf8dd1ea39e243e565891004a6f9 (patch) | |
tree | cea538919fffbe282da9040e56662b651f56545c /drivers/net/vrf.c | |
parent | 2fb7ea455d57e22110c54fc2de0656b6f744263c (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.c | 234 |
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 | ||
45 | struct net_vrf { | 45 | struct 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 | ||
63 | static 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 | |||
73 | static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb) | 60 | static 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 | */ | ||
110 | static 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) |
136 | static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb, | 95 | static 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 | ||
142 | static 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; | ||
161 | out: | ||
162 | return err; | ||
163 | } | ||
164 | |||
226 | static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, | 165 | static 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 | ||
304 | static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev) | 201 | static 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) | |||
377 | static void vrf_rt6_release(struct net_vrf *vrf) | 277 | static 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 | ||
397 | static int vrf_rt6_create(struct net_device *dev) | 287 | static 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; |
440 | out: | 311 | out: |
@@ -513,48 +384,29 @@ static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
513 | static void vrf_rtable_release(struct net_vrf *vrf) | 384 | static 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 | ||
529 | static int vrf_rtable_create(struct net_device *dev) | 394 | static 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: | |||
780 | static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, | 632 | static 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 | ||
805 | out: | ||
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 | ||
835 | out: | ||
836 | return skb; | 668 | return skb; |
837 | } | 669 | } |
838 | 670 | ||