Skip to content

Commit a4fa2a1

Browse files
suyj-fnstgregkh
authored andcommitted
vti4: Fix a ipip packet processing bug in 'IPCOMP' virtual tunnel
[ Upstream commit dd9ee34 ] 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>
1 parent bba078c commit a4fa2a1

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

net/ipv4/ip_vti.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,33 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi,
7575
return 0;
7676
}
7777

78+
static int vti_input_ipip(struct sk_buff *skb, int nexthdr, __be32 spi,
79+
int encap_type)
80+
{
81+
struct ip_tunnel *tunnel;
82+
const struct iphdr *iph = ip_hdr(skb);
83+
struct net *net = dev_net(skb->dev);
84+
struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
85+
86+
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
87+
iph->saddr, iph->daddr, 0);
88+
if (tunnel) {
89+
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
90+
goto drop;
91+
92+
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;
93+
94+
skb->dev = tunnel->dev;
95+
96+
return xfrm_input(skb, nexthdr, spi, encap_type);
97+
}
98+
99+
return -EINVAL;
100+
drop:
101+
kfree_skb(skb);
102+
return 0;
103+
}
104+
78105
static int vti_rcv(struct sk_buff *skb)
79106
{
80107
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
@@ -83,6 +110,14 @@ static int vti_rcv(struct sk_buff *skb)
83110
return vti_input(skb, ip_hdr(skb)->protocol, 0, 0);
84111
}
85112

113+
static int vti_rcv_ipip(struct sk_buff *skb)
114+
{
115+
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
116+
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
117+
118+
return vti_input_ipip(skb, ip_hdr(skb)->protocol, ip_hdr(skb)->saddr, 0);
119+
}
120+
86121
static int vti_rcv_cb(struct sk_buff *skb, int err)
87122
{
88123
unsigned short family;
@@ -409,6 +444,12 @@ static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = {
409444
.priority = 100,
410445
};
411446

447+
static struct xfrm_tunnel ipip_handler __read_mostly = {
448+
.handler = vti_rcv_ipip,
449+
.err_handler = vti4_err,
450+
.priority = 0,
451+
};
452+
412453
static int __net_init vti_init_net(struct net *net)
413454
{
414455
int err;
@@ -592,6 +633,13 @@ static int __init vti_init(void)
592633
if (err < 0)
593634
goto xfrm_proto_comp_failed;
594635

636+
msg = "ipip tunnel";
637+
err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
638+
if (err < 0) {
639+
pr_info("%s: cant't register tunnel\n",__func__);
640+
goto xfrm_tunnel_failed;
641+
}
642+
595643
msg = "netlink interface";
596644
err = rtnl_link_register(&vti_link_ops);
597645
if (err < 0)
@@ -601,6 +649,8 @@ static int __init vti_init(void)
601649

602650
rtnl_link_failed:
603651
xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
652+
xfrm_tunnel_failed:
653+
xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
604654
xfrm_proto_comp_failed:
605655
xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
606656
xfrm_proto_ah_failed:

0 commit comments

Comments
 (0)