diff options
author | Peter Kosyh <p.kosyh@gmail.com> | 2019-07-19 04:11:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-07-21 16:32:51 -0400 |
commit | 107e47cc80ec37cb332bd41b22b1c7779e22e018 (patch) | |
tree | ad7e68bbfcbb8e66acce7611af31597eadfd9ca9 | |
parent | 903e9d1bffb557220af276eda97b9d6b103ec9e0 (diff) |
vrf: make sure skb->data contains ip header to make routing
vrf_process_v4_outbound() and vrf_process_v6_outbound() do routing
using ip/ipv6 addresses, but don't make sure the header is available
in skb->data[] (skb_headlen() is less then header size).
Case:
1) igb driver from intel.
2) Packet size is greater then 255.
3) MPLS forwards to VRF device.
So, patch adds pskb_may_pull() calls in vrf_process_v4/v6_outbound()
functions.
Signed-off-by: Peter Kosyh <p.kosyh@gmail.com>
Reviewed-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/vrf.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 54edf8956a25..6e84328bdd40 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c | |||
@@ -165,23 +165,29 @@ static int vrf_ip6_local_out(struct net *net, struct sock *sk, | |||
165 | static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb, | 165 | static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb, |
166 | struct net_device *dev) | 166 | struct net_device *dev) |
167 | { | 167 | { |
168 | const struct ipv6hdr *iph = ipv6_hdr(skb); | 168 | const struct ipv6hdr *iph; |
169 | struct net *net = dev_net(skb->dev); | 169 | struct net *net = dev_net(skb->dev); |
170 | struct flowi6 fl6 = { | 170 | struct flowi6 fl6; |
171 | /* needed to match OIF rule */ | ||
172 | .flowi6_oif = dev->ifindex, | ||
173 | .flowi6_iif = LOOPBACK_IFINDEX, | ||
174 | .daddr = iph->daddr, | ||
175 | .saddr = iph->saddr, | ||
176 | .flowlabel = ip6_flowinfo(iph), | ||
177 | .flowi6_mark = skb->mark, | ||
178 | .flowi6_proto = iph->nexthdr, | ||
179 | .flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF, | ||
180 | }; | ||
181 | int ret = NET_XMIT_DROP; | 171 | int ret = NET_XMIT_DROP; |
182 | struct dst_entry *dst; | 172 | struct dst_entry *dst; |
183 | struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst; | 173 | struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst; |
184 | 174 | ||
175 | if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr))) | ||
176 | goto err; | ||
177 | |||
178 | iph = ipv6_hdr(skb); | ||
179 | |||
180 | memset(&fl6, 0, sizeof(fl6)); | ||
181 | /* needed to match OIF rule */ | ||
182 | fl6.flowi6_oif = dev->ifindex; | ||
183 | fl6.flowi6_iif = LOOPBACK_IFINDEX; | ||
184 | fl6.daddr = iph->daddr; | ||
185 | fl6.saddr = iph->saddr; | ||
186 | fl6.flowlabel = ip6_flowinfo(iph); | ||
187 | fl6.flowi6_mark = skb->mark; | ||
188 | fl6.flowi6_proto = iph->nexthdr; | ||
189 | fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF; | ||
190 | |||
185 | dst = ip6_route_output(net, NULL, &fl6); | 191 | dst = ip6_route_output(net, NULL, &fl6); |
186 | if (dst == dst_null) | 192 | if (dst == dst_null) |
187 | goto err; | 193 | goto err; |
@@ -237,21 +243,27 @@ static int vrf_ip_local_out(struct net *net, struct sock *sk, | |||
237 | static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, | 243 | static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, |
238 | struct net_device *vrf_dev) | 244 | struct net_device *vrf_dev) |
239 | { | 245 | { |
240 | struct iphdr *ip4h = ip_hdr(skb); | 246 | struct iphdr *ip4h; |
241 | int ret = NET_XMIT_DROP; | 247 | int ret = NET_XMIT_DROP; |
242 | struct flowi4 fl4 = { | 248 | struct flowi4 fl4; |
243 | /* needed to match OIF rule */ | ||
244 | .flowi4_oif = vrf_dev->ifindex, | ||
245 | .flowi4_iif = LOOPBACK_IFINDEX, | ||
246 | .flowi4_tos = RT_TOS(ip4h->tos), | ||
247 | .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF, | ||
248 | .flowi4_proto = ip4h->protocol, | ||
249 | .daddr = ip4h->daddr, | ||
250 | .saddr = ip4h->saddr, | ||
251 | }; | ||
252 | struct net *net = dev_net(vrf_dev); | 249 | struct net *net = dev_net(vrf_dev); |
253 | struct rtable *rt; | 250 | struct rtable *rt; |
254 | 251 | ||
252 | if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr))) | ||
253 | goto err; | ||
254 | |||
255 | ip4h = ip_hdr(skb); | ||
256 | |||
257 | memset(&fl4, 0, sizeof(fl4)); | ||
258 | /* needed to match OIF rule */ | ||
259 | fl4.flowi4_oif = vrf_dev->ifindex; | ||
260 | fl4.flowi4_iif = LOOPBACK_IFINDEX; | ||
261 | fl4.flowi4_tos = RT_TOS(ip4h->tos); | ||
262 | fl4.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF; | ||
263 | fl4.flowi4_proto = ip4h->protocol; | ||
264 | fl4.daddr = ip4h->daddr; | ||
265 | fl4.saddr = ip4h->saddr; | ||
266 | |||
255 | rt = ip_route_output_flow(net, &fl4, NULL); | 267 | rt = ip_route_output_flow(net, &fl4, NULL); |
256 | if (IS_ERR(rt)) | 268 | if (IS_ERR(rt)) |
257 | goto err; | 269 | goto err; |