aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-11-26 22:07:11 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-28 11:37:11 -0500
commitf4e0b4c5e1c3eac9b7376ce73fb63de436057db1 (patch)
tree6eadca952e46bd6cd42c4463b92a45f3b8d8f92a /net/ipv6
parente49cc34f7ac30304ef0563d2517f6c5f86525220 (diff)
ip6tnl/sit: drop packet if ECN present with not-ECT
This patch reports the change made by Stephen Hemminger in ipip and gre[6] in commit eccc1bb8d4b4 (tunnel: drop packet if ECN present with not-ECT). Goal is to handle RFC6040, Section 4.2: Default Tunnel Egress Behaviour. o If the inner ECN field is Not-ECT, the decapsulator MUST NOT propagate any other ECN codepoint onwards. This is because the inner Not-ECT marking is set by transports that rely on dropped packets as an indication of congestion and would not understand or respond to any other ECN codepoint [RFC4774]. Specifically: * If the inner ECN field is Not-ECT and the outer ECN field is CE, the decapsulator MUST drop the packet. * If the inner ECN field is Not-ECT and the outer ECN field is Not-ECT, ECT(0), or ECT(1), the decapsulator MUST forward the outgoing packet with the ECN field cleared to Not-ECT. The patch takes benefits from common function added in net/inet_ecn.h. Like it was done for Xin4 tunnels, it adds logging to allow detecting broken systems that set ECN bits incorrectly when tunneling (or an intermediate router might be changing the header). Errors are also tracked via rx_frame_error. CC: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_tunnel.c49
-rw-r--r--net/ipv6/sit.c33
2 files changed, 53 insertions, 29 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index fb828e9fe8e0..a14f28b280f5 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -74,6 +74,10 @@ MODULE_ALIAS_NETDEV("ip6tnl0");
74#define HASH_SIZE_SHIFT 5 74#define HASH_SIZE_SHIFT 5
75#define HASH_SIZE (1 << HASH_SIZE_SHIFT) 75#define HASH_SIZE (1 << HASH_SIZE_SHIFT)
76 76
77static bool log_ecn_error = true;
78module_param(log_ecn_error, bool, 0644);
79MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
80
77static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) 81static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
78{ 82{
79 u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); 83 u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
@@ -683,28 +687,26 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
683 return 0; 687 return 0;
684} 688}
685 689
686static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, 690static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
687 const struct ipv6hdr *ipv6h, 691 const struct ipv6hdr *ipv6h,
688 struct sk_buff *skb) 692 struct sk_buff *skb)
689{ 693{
690 __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; 694 __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
691 695
692 if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) 696 if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
693 ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); 697 ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
694 698
695 if (INET_ECN_is_ce(dsfield)) 699 return IP6_ECN_decapsulate(ipv6h, skb);
696 IP_ECN_set_ce(ip_hdr(skb));
697} 700}
698 701
699static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, 702static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
700 const struct ipv6hdr *ipv6h, 703 const struct ipv6hdr *ipv6h,
701 struct sk_buff *skb) 704 struct sk_buff *skb)
702{ 705{
703 if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) 706 if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
704 ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); 707 ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
705 708
706 if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h))) 709 return IP6_ECN_decapsulate(ipv6h, skb);
707 IP6_ECN_set_ce(ipv6_hdr(skb));
708} 710}
709 711
710__u32 ip6_tnl_get_cap(struct ip6_tnl *t, 712__u32 ip6_tnl_get_cap(struct ip6_tnl *t,
@@ -768,12 +770,13 @@ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
768 770
769static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, 771static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
770 __u8 ipproto, 772 __u8 ipproto,
771 void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, 773 int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
772 const struct ipv6hdr *ipv6h, 774 const struct ipv6hdr *ipv6h,
773 struct sk_buff *skb)) 775 struct sk_buff *skb))
774{ 776{
775 struct ip6_tnl *t; 777 struct ip6_tnl *t;
776 const struct ipv6hdr *ipv6h = ipv6_hdr(skb); 778 const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
779 int err;
777 780
778 rcu_read_lock(); 781 rcu_read_lock();
779 782
@@ -803,14 +806,26 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
803 skb->pkt_type = PACKET_HOST; 806 skb->pkt_type = PACKET_HOST;
804 memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); 807 memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
805 808
809 __skb_tunnel_rx(skb, t->dev);
810
811 err = dscp_ecn_decapsulate(t, ipv6h, skb);
812 if (unlikely(err)) {
813 if (log_ecn_error)
814 net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n",
815 &ipv6h->saddr,
816 ipv6_get_dsfield(ipv6h));
817 if (err > 1) {
818 ++t->dev->stats.rx_frame_errors;
819 ++t->dev->stats.rx_errors;
820 rcu_read_unlock();
821 goto discard;
822 }
823 }
824
806 tstats = this_cpu_ptr(t->dev->tstats); 825 tstats = this_cpu_ptr(t->dev->tstats);
807 tstats->rx_packets++; 826 tstats->rx_packets++;
808 tstats->rx_bytes += skb->len; 827 tstats->rx_bytes += skb->len;
809 828
810 __skb_tunnel_rx(skb, t->dev);
811
812 dscp_ecn_decapsulate(t, ipv6h, skb);
813
814 netif_rx(skb); 829 netif_rx(skb);
815 830
816 rcu_read_unlock(); 831 rcu_read_unlock();
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 80cb3829831c..cfba99b2c2a4 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -65,6 +65,10 @@
65#define HASH_SIZE 16 65#define HASH_SIZE 16
66#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) 66#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
67 67
68static bool log_ecn_error = true;
69module_param(log_ecn_error, bool, 0644);
70MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
71
68static int ipip6_tunnel_init(struct net_device *dev); 72static int ipip6_tunnel_init(struct net_device *dev);
69static void ipip6_tunnel_setup(struct net_device *dev); 73static void ipip6_tunnel_setup(struct net_device *dev);
70static void ipip6_dev_free(struct net_device *dev); 74static void ipip6_dev_free(struct net_device *dev);
@@ -106,6 +110,7 @@ static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev,
106 } 110 }
107 111
108 tot->rx_errors = dev->stats.rx_errors; 112 tot->rx_errors = dev->stats.rx_errors;
113 tot->rx_frame_errors = dev->stats.rx_frame_errors;
109 tot->tx_fifo_errors = dev->stats.tx_fifo_errors; 114 tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
110 tot->tx_carrier_errors = dev->stats.tx_carrier_errors; 115 tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
111 tot->tx_dropped = dev->stats.tx_dropped; 116 tot->tx_dropped = dev->stats.tx_dropped;
@@ -585,16 +590,11 @@ out:
585 return err; 590 return err;
586} 591}
587 592
588static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
589{
590 if (INET_ECN_is_ce(iph->tos))
591 IP6_ECN_set_ce(ipv6_hdr(skb));
592}
593
594static int ipip6_rcv(struct sk_buff *skb) 593static int ipip6_rcv(struct sk_buff *skb)
595{ 594{
596 const struct iphdr *iph; 595 const struct iphdr *iph;
597 struct ip_tunnel *tunnel; 596 struct ip_tunnel *tunnel;
597 int err;
598 598
599 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 599 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
600 goto out; 600 goto out;
@@ -616,18 +616,27 @@ static int ipip6_rcv(struct sk_buff *skb)
616 if ((tunnel->dev->priv_flags & IFF_ISATAP) && 616 if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
617 !isatap_chksrc(skb, iph, tunnel)) { 617 !isatap_chksrc(skb, iph, tunnel)) {
618 tunnel->dev->stats.rx_errors++; 618 tunnel->dev->stats.rx_errors++;
619 kfree_skb(skb); 619 goto out;
620 return 0; 620 }
621
622 __skb_tunnel_rx(skb, tunnel->dev);
623
624 err = IP_ECN_decapsulate(iph, skb);
625 if (unlikely(err)) {
626 if (log_ecn_error)
627 net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
628 &iph->saddr, iph->tos);
629 if (err > 1) {
630 ++tunnel->dev->stats.rx_frame_errors;
631 ++tunnel->dev->stats.rx_errors;
632 goto out;
633 }
621 } 634 }
622 635
623 tstats = this_cpu_ptr(tunnel->dev->tstats); 636 tstats = this_cpu_ptr(tunnel->dev->tstats);
624 tstats->rx_packets++; 637 tstats->rx_packets++;
625 tstats->rx_bytes += skb->len; 638 tstats->rx_bytes += skb->len;
626 639
627 __skb_tunnel_rx(skb, tunnel->dev);
628
629 ipip6_ecn_decapsulate(iph, skb);
630
631 netif_rx(skb); 640 netif_rx(skb);
632 641
633 return 0; 642 return 0;