| From f3b8f944d110643410d3f076036bb42c94acc8f8 Mon Sep 17 00:00:00 2001 |
| From: Su Yanjun <suyj.fnst@cn.fujitsu.com> |
| Date: Sun, 6 Jan 2019 21:31:20 -0500 |
| Subject: vti4: Fix a ipip packet processing bug in 'IPCOMP' virtual tunnel |
| |
| [ Upstream commit dd9ee3444014e8f28c0eefc9fffc9ac9c5248c12 ] |
| |
| Recently we run a network test over ipcomp virtual tunnel.We find that |
| if a ipv4 packet needs fragment, then the peer can't receive |
| it. |
| |
| We deep into the code and find that when packet need fragment the smaller |
| fragment will be encapsulated by ipip not ipcomp. So when the ipip packet |
| goes into xfrm, it's skb->dev is not properly set. The ipv4 reassembly code |
| always set skb'dev to the last fragment's dev. After ipv4 defrag processing, |
| when the kernel rp_filter parameter is set, the skb will be drop by -EXDEV |
| error. |
| |
| This patch adds compatible support for the ipip process in ipcomp virtual tunnel. |
| |
| Signed-off-by: Su Yanjun <suyj.fnst@cn.fujitsu.com> |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/ipv4/ip_vti.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 50 insertions(+) |
| |
| diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c |
| index 7f56944b020f..40a7cd56e008 100644 |
| --- a/net/ipv4/ip_vti.c |
| +++ b/net/ipv4/ip_vti.c |
| @@ -74,6 +74,33 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, |
| return 0; |
| } |
| |
| +static int vti_input_ipip(struct sk_buff *skb, int nexthdr, __be32 spi, |
| + int encap_type) |
| +{ |
| + struct ip_tunnel *tunnel; |
| + const struct iphdr *iph = ip_hdr(skb); |
| + struct net *net = dev_net(skb->dev); |
| + struct ip_tunnel_net *itn = net_generic(net, vti_net_id); |
| + |
| + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
| + iph->saddr, iph->daddr, 0); |
| + if (tunnel) { |
| + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) |
| + goto drop; |
| + |
| + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; |
| + |
| + skb->dev = tunnel->dev; |
| + |
| + return xfrm_input(skb, nexthdr, spi, encap_type); |
| + } |
| + |
| + return -EINVAL; |
| +drop: |
| + kfree_skb(skb); |
| + return 0; |
| +} |
| + |
| static int vti_rcv(struct sk_buff *skb) |
| { |
| XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
| @@ -82,6 +109,14 @@ static int vti_rcv(struct sk_buff *skb) |
| return vti_input(skb, ip_hdr(skb)->protocol, 0, 0); |
| } |
| |
| +static int vti_rcv_ipip(struct sk_buff *skb) |
| +{ |
| + XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
| + XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
| + |
| + return vti_input_ipip(skb, ip_hdr(skb)->protocol, ip_hdr(skb)->saddr, 0); |
| +} |
| + |
| static int vti_rcv_cb(struct sk_buff *skb, int err) |
| { |
| unsigned short family; |
| @@ -435,6 +470,12 @@ static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = { |
| .priority = 100, |
| }; |
| |
| +static struct xfrm_tunnel ipip_handler __read_mostly = { |
| + .handler = vti_rcv_ipip, |
| + .err_handler = vti4_err, |
| + .priority = 0, |
| +}; |
| + |
| static int __net_init vti_init_net(struct net *net) |
| { |
| int err; |
| @@ -603,6 +644,13 @@ static int __init vti_init(void) |
| if (err < 0) |
| goto xfrm_proto_comp_failed; |
| |
| + msg = "ipip tunnel"; |
| + err = xfrm4_tunnel_register(&ipip_handler, AF_INET); |
| + if (err < 0) { |
| + pr_info("%s: cant't register tunnel\n",__func__); |
| + goto xfrm_tunnel_failed; |
| + } |
| + |
| msg = "netlink interface"; |
| err = rtnl_link_register(&vti_link_ops); |
| if (err < 0) |
| @@ -612,6 +660,8 @@ static int __init vti_init(void) |
| |
| rtnl_link_failed: |
| xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
| +xfrm_tunnel_failed: |
| + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); |
| xfrm_proto_comp_failed: |
| xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
| xfrm_proto_ah_failed: |
| -- |
| 2.19.1 |
| |