diff options
Diffstat (limited to 'net/ipv4/ipip.c')
-rw-r--r-- | net/ipv4/ipip.c | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 618bde867ac1..e15b45297c09 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -120,6 +120,10 @@ | |||
120 | #define HASH_SIZE 16 | 120 | #define HASH_SIZE 16 |
121 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 121 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
122 | 122 | ||
123 | static bool log_ecn_error = true; | ||
124 | module_param(log_ecn_error, bool, 0644); | ||
125 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | ||
126 | |||
123 | static int ipip_net_id __read_mostly; | 127 | static int ipip_net_id __read_mostly; |
124 | struct ipip_net { | 128 | struct ipip_net { |
125 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; | 129 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; |
@@ -400,28 +404,18 @@ out: | |||
400 | return err; | 404 | return err; |
401 | } | 405 | } |
402 | 406 | ||
403 | static inline void ipip_ecn_decapsulate(const struct iphdr *outer_iph, | ||
404 | struct sk_buff *skb) | ||
405 | { | ||
406 | struct iphdr *inner_iph = ip_hdr(skb); | ||
407 | |||
408 | if (INET_ECN_is_ce(outer_iph->tos)) | ||
409 | IP_ECN_set_ce(inner_iph); | ||
410 | } | ||
411 | |||
412 | static int ipip_rcv(struct sk_buff *skb) | 407 | static int ipip_rcv(struct sk_buff *skb) |
413 | { | 408 | { |
414 | struct ip_tunnel *tunnel; | 409 | struct ip_tunnel *tunnel; |
415 | const struct iphdr *iph = ip_hdr(skb); | 410 | const struct iphdr *iph = ip_hdr(skb); |
411 | int err; | ||
416 | 412 | ||
417 | tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr); | 413 | tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr); |
418 | if (tunnel != NULL) { | 414 | if (tunnel != NULL) { |
419 | struct pcpu_tstats *tstats; | 415 | struct pcpu_tstats *tstats; |
420 | 416 | ||
421 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 417 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) |
422 | kfree_skb(skb); | 418 | goto drop; |
423 | return 0; | ||
424 | } | ||
425 | 419 | ||
426 | secpath_reset(skb); | 420 | secpath_reset(skb); |
427 | 421 | ||
@@ -430,21 +424,35 @@ static int ipip_rcv(struct sk_buff *skb) | |||
430 | skb->protocol = htons(ETH_P_IP); | 424 | skb->protocol = htons(ETH_P_IP); |
431 | skb->pkt_type = PACKET_HOST; | 425 | skb->pkt_type = PACKET_HOST; |
432 | 426 | ||
427 | __skb_tunnel_rx(skb, tunnel->dev); | ||
428 | |||
429 | err = IP_ECN_decapsulate(iph, skb); | ||
430 | if (unlikely(err)) { | ||
431 | if (log_ecn_error) | ||
432 | net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", | ||
433 | &iph->saddr, iph->tos); | ||
434 | if (err > 1) { | ||
435 | ++tunnel->dev->stats.rx_frame_errors; | ||
436 | ++tunnel->dev->stats.rx_errors; | ||
437 | goto drop; | ||
438 | } | ||
439 | } | ||
440 | |||
433 | tstats = this_cpu_ptr(tunnel->dev->tstats); | 441 | tstats = this_cpu_ptr(tunnel->dev->tstats); |
434 | u64_stats_update_begin(&tstats->syncp); | 442 | u64_stats_update_begin(&tstats->syncp); |
435 | tstats->rx_packets++; | 443 | tstats->rx_packets++; |
436 | tstats->rx_bytes += skb->len; | 444 | tstats->rx_bytes += skb->len; |
437 | u64_stats_update_end(&tstats->syncp); | 445 | u64_stats_update_end(&tstats->syncp); |
438 | 446 | ||
439 | __skb_tunnel_rx(skb, tunnel->dev); | ||
440 | |||
441 | ipip_ecn_decapsulate(iph, skb); | ||
442 | |||
443 | netif_rx(skb); | 447 | netif_rx(skb); |
444 | return 0; | 448 | return 0; |
445 | } | 449 | } |
446 | 450 | ||
447 | return -1; | 451 | return -1; |
452 | |||
453 | drop: | ||
454 | kfree_skb(skb); | ||
455 | return 0; | ||
448 | } | 456 | } |
449 | 457 | ||
450 | /* | 458 | /* |