@@ -68,6 +68,54 @@ static unsigned int ip_tunnel_hash(struct ip_tunnel_net *itn,
68
68
IP_TNL_HASH_BITS );
69
69
}
70
70
71
+ static inline void __tunnel_dst_set (struct ip_tunnel * t , struct dst_entry * dst )
72
+ {
73
+ struct dst_entry * old_dst ;
74
+
75
+ if (dst && (dst -> flags & DST_NOCACHE ))
76
+ dst = NULL ;
77
+
78
+ spin_lock_bh (& t -> dst_lock );
79
+ old_dst = rcu_dereference_raw (t -> dst_cache );
80
+ rcu_assign_pointer (t -> dst_cache , dst );
81
+ dst_release (old_dst );
82
+ spin_unlock_bh (& t -> dst_lock );
83
+ }
84
+
85
+ static inline void tunnel_dst_set (struct ip_tunnel * t , struct dst_entry * dst )
86
+ {
87
+ __tunnel_dst_set (t , dst );
88
+ }
89
+
90
+ static inline void tunnel_dst_reset (struct ip_tunnel * t )
91
+ {
92
+ tunnel_dst_set (t , NULL );
93
+ }
94
+
95
+ static inline struct dst_entry * tunnel_dst_get (struct ip_tunnel * t )
96
+ {
97
+ struct dst_entry * dst ;
98
+
99
+ rcu_read_lock ();
100
+ dst = rcu_dereference (t -> dst_cache );
101
+ if (dst )
102
+ dst_hold (dst );
103
+ rcu_read_unlock ();
104
+ return dst ;
105
+ }
106
+
107
+ struct dst_entry * tunnel_dst_check (struct ip_tunnel * t , u32 cookie )
108
+ {
109
+ struct dst_entry * dst = tunnel_dst_get (t );
110
+
111
+ if (dst && dst -> obsolete && dst -> ops -> check (dst , cookie ) == NULL ) {
112
+ tunnel_dst_reset (t );
113
+ return NULL ;
114
+ }
115
+
116
+ return dst ;
117
+ }
118
+
71
119
/* Often modified stats are per cpu, other are shared (netdev->stats) */
72
120
struct rtnl_link_stats64 * ip_tunnel_get_stats64 (struct net_device * dev ,
73
121
struct rtnl_link_stats64 * tot )
@@ -318,11 +366,10 @@ static struct net_device *__ip_tunnel_create(struct net *net,
318
366
return ERR_PTR (err );
319
367
}
320
368
321
- static inline struct rtable * ip_route_output_tunnel (struct net * net ,
322
- struct flowi4 * fl4 ,
323
- int proto ,
324
- __be32 daddr , __be32 saddr ,
325
- __be32 key , __u8 tos , int oif )
369
+ static inline void init_tunnel_flow (struct flowi4 * fl4 ,
370
+ int proto ,
371
+ __be32 daddr , __be32 saddr ,
372
+ __be32 key , __u8 tos , int oif )
326
373
{
327
374
memset (fl4 , 0 , sizeof (* fl4 ));
328
375
fl4 -> flowi4_oif = oif ;
@@ -331,7 +378,6 @@ static inline struct rtable *ip_route_output_tunnel(struct net *net,
331
378
fl4 -> flowi4_tos = tos ;
332
379
fl4 -> flowi4_proto = proto ;
333
380
fl4 -> fl4_gre_key = key ;
334
- return ip_route_output_key (net , fl4 );
335
381
}
336
382
337
383
static int ip_tunnel_bind_dev (struct net_device * dev )
@@ -350,14 +396,14 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
350
396
struct flowi4 fl4 ;
351
397
struct rtable * rt ;
352
398
353
- rt = ip_route_output_tunnel (tunnel -> net , & fl4 ,
354
- tunnel -> parms .iph .protocol ,
355
- iph -> daddr , iph -> saddr ,
356
- tunnel -> parms .o_key ,
357
- RT_TOS (iph -> tos ),
358
- tunnel -> parms .link );
399
+ init_tunnel_flow (& fl4 , iph -> protocol , iph -> daddr ,
400
+ iph -> saddr , tunnel -> parms .o_key ,
401
+ RT_TOS (iph -> tos ), tunnel -> parms .link );
402
+ rt = ip_route_output_key (tunnel -> net , & fl4 );
403
+
359
404
if (!IS_ERR (rt )) {
360
405
tdev = rt -> dst .dev ;
406
+ tunnel_dst_set (tunnel , dst_clone (& rt -> dst ));
361
407
ip_rt_put (rt );
362
408
}
363
409
if (dev -> type != ARPHRD_ETHER )
@@ -528,10 +574,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
528
574
struct flowi4 fl4 ;
529
575
u8 tos , ttl ;
530
576
__be16 df ;
531
- struct rtable * rt ; /* Route to the other host */
577
+ struct rtable * rt = NULL ; /* Route to the other host */
532
578
unsigned int max_headroom ; /* The extra header space needed */
533
579
__be32 dst ;
534
580
int err ;
581
+ bool connected = true;
535
582
536
583
inner_iph = (const struct iphdr * )skb_inner_network_header (skb );
537
584
@@ -581,27 +628,39 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
581
628
#endif
582
629
else
583
630
goto tx_error ;
631
+
632
+ connected = false;
584
633
}
585
634
586
635
tos = tnl_params -> tos ;
587
636
if (tos & 0x1 ) {
588
637
tos &= ~0x1 ;
589
- if (skb -> protocol == htons (ETH_P_IP ))
638
+ if (skb -> protocol == htons (ETH_P_IP )) {
590
639
tos = inner_iph -> tos ;
591
- else if (skb -> protocol == htons (ETH_P_IPV6 ))
640
+ connected = false;
641
+ } else if (skb -> protocol == htons (ETH_P_IPV6 )) {
592
642
tos = ipv6_get_dsfield ((const struct ipv6hdr * )inner_iph );
643
+ connected = false;
644
+ }
593
645
}
594
646
595
- rt = ip_route_output_tunnel (tunnel -> net , & fl4 ,
596
- protocol ,
597
- dst , tnl_params -> saddr ,
598
- tunnel -> parms .o_key ,
599
- RT_TOS (tos ),
600
- tunnel -> parms .link );
601
- if (IS_ERR (rt )) {
602
- dev -> stats .tx_carrier_errors ++ ;
603
- goto tx_error ;
647
+ init_tunnel_flow (& fl4 , protocol , dst , tnl_params -> saddr ,
648
+ tunnel -> parms .o_key , RT_TOS (tos ), tunnel -> parms .link );
649
+
650
+ if (connected )
651
+ rt = (struct rtable * )tunnel_dst_check (tunnel , 0 );
652
+
653
+ if (!rt ) {
654
+ rt = ip_route_output_key (tunnel -> net , & fl4 );
655
+
656
+ if (IS_ERR (rt )) {
657
+ dev -> stats .tx_carrier_errors ++ ;
658
+ goto tx_error ;
659
+ }
660
+ if (connected )
661
+ tunnel_dst_set (tunnel , dst_clone (& rt -> dst ));
604
662
}
663
+
605
664
if (rt -> dst .dev == dev ) {
606
665
ip_rt_put (rt );
607
666
dev -> stats .collisions ++ ;
@@ -696,6 +755,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
696
755
if (set_mtu )
697
756
dev -> mtu = mtu ;
698
757
}
758
+ tunnel_dst_reset (t );
699
759
netdev_state_change (dev );
700
760
}
701
761
@@ -1001,6 +1061,9 @@ int ip_tunnel_init(struct net_device *dev)
1001
1061
iph -> version = 4 ;
1002
1062
iph -> ihl = 5 ;
1003
1063
1064
+ tunnel -> dst_cache = NULL ;
1065
+ spin_lock_init (& tunnel -> dst_lock );
1066
+
1004
1067
return 0 ;
1005
1068
}
1006
1069
EXPORT_SYMBOL_GPL (ip_tunnel_init );
@@ -1015,6 +1078,8 @@ void ip_tunnel_uninit(struct net_device *dev)
1015
1078
/* fb_tunnel_dev will be unregisted in net-exit call. */
1016
1079
if (itn -> fb_tunnel_dev != dev )
1017
1080
ip_tunnel_del (netdev_priv (dev ));
1081
+
1082
+ tunnel_dst_reset (tunnel );
1018
1083
}
1019
1084
EXPORT_SYMBOL_GPL (ip_tunnel_uninit );
1020
1085
0 commit comments