35
35
#include <net/udp.h>
36
36
#include <net/icmp.h> /* for icmp_send */
37
37
#include <net/gue.h>
38
+ #include <net/gre.h>
38
39
#include <net/route.h>
39
40
#include <net/ip6_checksum.h>
40
41
#include <net/netns/generic.h> /* net_generic() */
@@ -1610,6 +1611,38 @@ static int ipvs_udp_decap(struct netns_ipvs *ipvs, struct sk_buff *skb,
1610
1611
return 0 ;
1611
1612
}
1612
1613
1614
+ /* Check the GRE tunnel and return its header length */
1615
+ static int ipvs_gre_decap (struct netns_ipvs * ipvs , struct sk_buff * skb ,
1616
+ unsigned int offset , __u16 af ,
1617
+ const union nf_inet_addr * daddr , __u8 * proto )
1618
+ {
1619
+ struct gre_base_hdr _greh , * greh ;
1620
+ struct ip_vs_dest * dest ;
1621
+
1622
+ greh = skb_header_pointer (skb , offset , sizeof (_greh ), & _greh );
1623
+ if (!greh )
1624
+ goto unk ;
1625
+ dest = ip_vs_find_tunnel (ipvs , af , daddr , 0 );
1626
+ if (!dest )
1627
+ goto unk ;
1628
+ if (dest -> tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE ) {
1629
+ __be16 type ;
1630
+
1631
+ /* Only support version 0 and C (csum) */
1632
+ if ((greh -> flags & ~GRE_CSUM ) != 0 )
1633
+ goto unk ;
1634
+ type = greh -> protocol ;
1635
+ /* Later we can support also IPPROTO_IPV6 */
1636
+ if (type != htons (ETH_P_IP ))
1637
+ goto unk ;
1638
+ * proto = IPPROTO_IPIP ;
1639
+ return gre_calc_hlen (gre_flags_to_tnl_flags (greh -> flags ));
1640
+ }
1641
+
1642
+ unk :
1643
+ return 0 ;
1644
+ }
1645
+
1613
1646
/*
1614
1647
* Handle ICMP messages in the outside-to-inside direction (incoming).
1615
1648
* Find any that might be relevant, check against existing connections,
@@ -1689,7 +1722,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
1689
1722
if (cih == NULL )
1690
1723
return NF_ACCEPT ; /* The packet looks wrong, ignore */
1691
1724
ipip = true;
1692
- } else if (cih -> protocol == IPPROTO_UDP && /* Can be UDP encap */
1725
+ } else if ((cih -> protocol == IPPROTO_UDP || /* Can be UDP encap */
1726
+ cih -> protocol == IPPROTO_GRE ) && /* Can be GRE encap */
1693
1727
/* Error for our tunnel must arrive at LOCAL_IN */
1694
1728
(skb_rtable (skb )-> rt_flags & RTCF_LOCAL )) {
1695
1729
__u8 iproto ;
@@ -1699,10 +1733,14 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
1699
1733
if (unlikely (cih -> frag_off & htons (IP_OFFSET )))
1700
1734
return NF_ACCEPT ;
1701
1735
offset2 = offset + cih -> ihl * 4 ;
1702
- ulen = ipvs_udp_decap (ipvs , skb , offset2 , AF_INET , raddr ,
1703
- & iproto );
1736
+ if (cih -> protocol == IPPROTO_UDP )
1737
+ ulen = ipvs_udp_decap (ipvs , skb , offset2 , AF_INET ,
1738
+ raddr , & iproto );
1739
+ else
1740
+ ulen = ipvs_gre_decap (ipvs , skb , offset2 , AF_INET ,
1741
+ raddr , & iproto );
1704
1742
if (ulen > 0 ) {
1705
- /* Skip IP and UDP tunnel headers */
1743
+ /* Skip IP and UDP/GRE tunnel headers */
1706
1744
offset = offset2 + ulen ;
1707
1745
/* Now we should be at the original IP header */
1708
1746
cih = skb_header_pointer (skb , offset , sizeof (_ciph ),
0 commit comments