3232#include <linux/slab.h>
3333#include <linux/tcp.h> /* for tcphdr */
3434#include <net/ip.h>
35+ #include <net/gue.h>
3536#include <net/tcp.h> /* for csum_tcpudp_magic */
3637#include <net/udp.h>
3738#include <net/icmp.h> /* for icmp_send */
@@ -382,6 +383,10 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
382383 mtu = dst_mtu (& rt -> dst );
383384 } else {
384385 mtu = dst_mtu (& rt -> dst ) - sizeof (struct iphdr );
386+ if (!dest )
387+ goto err_put ;
388+ if (dest -> tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
389+ mtu -= sizeof (struct udphdr ) + sizeof (struct guehdr );
385390 if (mtu < 68 ) {
386391 IP_VS_DBG_RL ("%s(): mtu less than 68\n" , __func__ );
387392 goto err_put ;
@@ -533,6 +538,10 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
533538 mtu = dst_mtu (& rt -> dst );
534539 else {
535540 mtu = dst_mtu (& rt -> dst ) - sizeof (struct ipv6hdr );
541+ if (!dest )
542+ goto err_put ;
543+ if (dest -> tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
544+ mtu -= sizeof (struct udphdr ) + sizeof (struct guehdr );
536545 if (mtu < IPV6_MIN_MTU ) {
537546 IP_VS_DBG_RL ("%s(): mtu less than %d\n" , __func__ ,
538547 IPV6_MIN_MTU );
@@ -989,6 +998,41 @@ static inline int __tun_gso_type_mask(int encaps_af, int orig_af)
989998 }
990999}
9911000
1001+ static int
1002+ ipvs_gue_encap (struct net * net , struct sk_buff * skb ,
1003+ struct ip_vs_conn * cp , __u8 * next_protocol )
1004+ {
1005+ __be16 dport ;
1006+ __be16 sport = udp_flow_src_port (net , skb , 0 , 0 , false);
1007+ struct udphdr * udph ; /* Our new UDP header */
1008+ struct guehdr * gueh ; /* Our new GUE header */
1009+
1010+ skb_push (skb , sizeof (struct guehdr ));
1011+
1012+ gueh = (struct guehdr * )skb -> data ;
1013+
1014+ gueh -> control = 0 ;
1015+ gueh -> version = 0 ;
1016+ gueh -> hlen = 0 ;
1017+ gueh -> flags = 0 ;
1018+ gueh -> proto_ctype = * next_protocol ;
1019+
1020+ skb_push (skb , sizeof (struct udphdr ));
1021+ skb_reset_transport_header (skb );
1022+
1023+ udph = udp_hdr (skb );
1024+
1025+ dport = cp -> dest -> tun_port ;
1026+ udph -> dest = dport ;
1027+ udph -> source = sport ;
1028+ udph -> len = htons (skb -> len );
1029+ udph -> check = 0 ;
1030+
1031+ * next_protocol = IPPROTO_UDP ;
1032+
1033+ return 0 ;
1034+ }
1035+
9921036/*
9931037 * IP Tunneling transmitter
9941038 *
@@ -1025,6 +1069,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
10251069 struct iphdr * iph ; /* Our new IP header */
10261070 unsigned int max_headroom ; /* The extra header space needed */
10271071 int ret , local ;
1072+ int tun_type , gso_type ;
10281073
10291074 EnterFunction (10 );
10301075
@@ -1046,6 +1091,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
10461091 */
10471092 max_headroom = LL_RESERVED_SPACE (tdev ) + sizeof (struct iphdr );
10481093
1094+ tun_type = cp -> dest -> tun_type ;
1095+
1096+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1097+ max_headroom += sizeof (struct udphdr ) + sizeof (struct guehdr );
1098+
10491099 /* We only care about the df field if sysctl_pmtu_disc(ipvs) is set */
10501100 dfp = sysctl_pmtu_disc (ipvs ) ? & df : NULL ;
10511101 skb = ip_vs_prepare_tunneled_skb (skb , cp -> af , max_headroom ,
@@ -1054,11 +1104,20 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
10541104 if (IS_ERR (skb ))
10551105 goto tx_error ;
10561106
1057- if (iptunnel_handle_offloads (skb , __tun_gso_type_mask (AF_INET , cp -> af )))
1107+ gso_type = __tun_gso_type_mask (AF_INET , cp -> af );
1108+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1109+ gso_type |= SKB_GSO_UDP_TUNNEL ;
1110+
1111+ if (iptunnel_handle_offloads (skb , gso_type ))
10581112 goto tx_error ;
10591113
10601114 skb -> transport_header = skb -> network_header ;
10611115
1116+ skb_set_inner_ipproto (skb , next_protocol );
1117+
1118+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1119+ ipvs_gue_encap (net , skb , cp , & next_protocol );
1120+
10621121 skb_push (skb , sizeof (struct iphdr ));
10631122 skb_reset_network_header (skb );
10641123 memset (& (IPCB (skb )-> opt ), 0 , sizeof (IPCB (skb )-> opt ));
@@ -1102,6 +1161,8 @@ int
11021161ip_vs_tunnel_xmit_v6 (struct sk_buff * skb , struct ip_vs_conn * cp ,
11031162 struct ip_vs_protocol * pp , struct ip_vs_iphdr * ipvsh )
11041163{
1164+ struct netns_ipvs * ipvs = cp -> ipvs ;
1165+ struct net * net = ipvs -> net ;
11051166 struct rt6_info * rt ; /* Route to the other host */
11061167 struct in6_addr saddr ; /* Source for tunnel */
11071168 struct net_device * tdev ; /* Device to other host */
@@ -1112,10 +1173,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
11121173 struct ipv6hdr * iph ; /* Our new IP header */
11131174 unsigned int max_headroom ; /* The extra header space needed */
11141175 int ret , local ;
1176+ int tun_type , gso_type ;
11151177
11161178 EnterFunction (10 );
11171179
1118- local = __ip_vs_get_out_rt_v6 (cp -> ipvs , cp -> af , skb , cp -> dest ,
1180+ local = __ip_vs_get_out_rt_v6 (ipvs , cp -> af , skb , cp -> dest ,
11191181 & cp -> daddr .in6 ,
11201182 & saddr , ipvsh , 1 ,
11211183 IP_VS_RT_MODE_LOCAL |
@@ -1134,17 +1196,31 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
11341196 */
11351197 max_headroom = LL_RESERVED_SPACE (tdev ) + sizeof (struct ipv6hdr );
11361198
1199+ tun_type = cp -> dest -> tun_type ;
1200+
1201+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1202+ max_headroom += sizeof (struct udphdr ) + sizeof (struct guehdr );
1203+
11371204 skb = ip_vs_prepare_tunneled_skb (skb , cp -> af , max_headroom ,
11381205 & next_protocol , & payload_len ,
11391206 & dsfield , & ttl , NULL );
11401207 if (IS_ERR (skb ))
11411208 goto tx_error ;
11421209
1143- if (iptunnel_handle_offloads (skb , __tun_gso_type_mask (AF_INET6 , cp -> af )))
1210+ gso_type = __tun_gso_type_mask (AF_INET6 , cp -> af );
1211+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1212+ gso_type |= SKB_GSO_UDP_TUNNEL ;
1213+
1214+ if (iptunnel_handle_offloads (skb , gso_type ))
11441215 goto tx_error ;
11451216
11461217 skb -> transport_header = skb -> network_header ;
11471218
1219+ skb_set_inner_ipproto (skb , next_protocol );
1220+
1221+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE )
1222+ ipvs_gue_encap (net , skb , cp , & next_protocol );
1223+
11481224 skb_push (skb , sizeof (struct ipv6hdr ));
11491225 skb_reset_network_header (skb );
11501226 memset (& (IPCB (skb )-> opt ), 0 , sizeof (IPCB (skb )-> opt ));
@@ -1167,7 +1243,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
11671243
11681244 ret = ip_vs_tunnel_xmit_prepare (skb , cp );
11691245 if (ret == NF_ACCEPT )
1170- ip6_local_out (cp -> ipvs -> net , skb -> sk , skb );
1246+ ip6_local_out (net , skb -> sk , skb );
11711247 else if (ret == NF_DROP )
11721248 kfree_skb (skb );
11731249
0 commit comments