On Mon, Jul 01, 2019 at 10:34:15PM +0300, Julian Anastasov wrote: > Recognize GRE tunnels in received ICMP errors and > properly strip the tunnel headers. > > Signed-off-by: Julian Anastasov <ja@xxxxxx> Thanks Julian, this looks good to me. Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx> Pablo, please consider including this in nf-next along with the dependency listed below. > --- > net/netfilter/ipvs/ip_vs_core.c | 45 ++++++++++++++++++++++++++++++--- > 1 file changed, 41 insertions(+), 4 deletions(-) > > This patch is based on: > "[PATCH v3] ipvs: allow tunneling with gre encapsulation" > > diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c > index e8651fd621ef..c2c51bdb889d 100644 > --- a/net/netfilter/ipvs/ip_vs_core.c > +++ b/net/netfilter/ipvs/ip_vs_core.c > @@ -1610,6 +1610,38 @@ static int ipvs_udp_decap(struct netns_ipvs *ipvs, struct sk_buff *skb, > return 0; > } > > +/* Check the GRE tunnel and return its header length */ > +static int ipvs_gre_decap(struct netns_ipvs *ipvs, struct sk_buff *skb, > + unsigned int offset, __u16 af, > + const union nf_inet_addr *daddr, __u8 *proto) > +{ > + struct gre_base_hdr _greh, *greh; > + struct ip_vs_dest *dest; > + > + greh = skb_header_pointer(skb, offset, sizeof(_greh), &_greh); > + if (!greh) > + goto unk; > + dest = ip_vs_find_tunnel(ipvs, af, daddr, 0); > + if (!dest) > + goto unk; > + if (dest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE) { > + __be16 type; > + > + /* Only support version 0 and C (csum) */ > + if ((greh->flags & ~GRE_CSUM) != 0) > + goto unk; > + type = greh->protocol; > + /* Later we can support also IPPROTO_IPV6 */ > + if (type != htons(ETH_P_IP)) > + goto unk; > + *proto = IPPROTO_IPIP; > + return gre_calc_hlen(gre_flags_to_tnl_flags(greh->flags)); > + } > + > +unk: > + return 0; > +} > + > /* > * Handle ICMP messages in the outside-to-inside direction (incoming). > * Find any that might be relevant, check against existing connections, > @@ -1689,7 +1721,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, > if (cih == NULL) > return NF_ACCEPT; /* The packet looks wrong, ignore */ > ipip = true; > - } else if (cih->protocol == IPPROTO_UDP && /* Can be UDP encap */ > + } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */ > + cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */ > /* Error for our tunnel must arrive at LOCAL_IN */ > (skb_rtable(skb)->rt_flags & RTCF_LOCAL)) { > __u8 iproto; > @@ -1699,10 +1732,14 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, > if (unlikely(cih->frag_off & htons(IP_OFFSET))) > return NF_ACCEPT; > offset2 = offset + cih->ihl * 4; > - ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET, raddr, > - &iproto); > + if (cih->protocol == IPPROTO_UDP) > + ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET, > + raddr, &iproto); > + else > + ulen = ipvs_gre_decap(ipvs, skb, offset2, AF_INET, > + raddr, &iproto); > if (ulen > 0) { > - /* Skip IP and UDP tunnel headers */ > + /* Skip IP and UDP/GRE tunnel headers */ > offset = offset2 + ulen; > /* Now we should be at the original IP header */ > cih = skb_header_pointer(skb, offset, sizeof(_ciph), > -- > 2.21.0 >