summaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-11-27 04:07:11 +0100
committerDavid S. Miller <davem@davemloft.net>2012-11-28 17:37:11 +0100
commitf4e0b4c5e1c3eac9b7376ce73fb63de436057db1 (patch)
tree6eadca952e46bd6cd42c4463b92a45f3b8d8f92a /net/ipv6/sit.c
parentbe2net: fix INTx ISR for interrupt behaviour on BE2 (diff)
downloadlinux-f4e0b4c5e1c3eac9b7376ce73fb63de436057db1.tar.xz
linux-f4e0b4c5e1c3eac9b7376ce73fb63de436057db1.zip
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/sit.c')
-rw-r--r--net/ipv6/sit.c33
1 files changed, 21 insertions, 12 deletions
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 @@
#define HASH_SIZE 16
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
+static bool log_ecn_error = true;
+module_param(log_ecn_error, bool, 0644);
+MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+
static int ipip6_tunnel_init(struct net_device *dev);
static void ipip6_tunnel_setup(struct net_device *dev);
static void ipip6_dev_free(struct net_device *dev);
@@ -106,6 +110,7 @@ static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev,
}
tot->rx_errors = dev->stats.rx_errors;
+ tot->rx_frame_errors = dev->stats.rx_frame_errors;
tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
tot->tx_dropped = dev->stats.tx_dropped;
@@ -585,16 +590,11 @@ out:
return err;
}
-static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
-{
- if (INET_ECN_is_ce(iph->tos))
- IP6_ECN_set_ce(ipv6_hdr(skb));
-}
-
static int ipip6_rcv(struct sk_buff *skb)
{
const struct iphdr *iph;
struct ip_tunnel *tunnel;
+ int err;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto out;
@@ -616,18 +616,27 @@ static int ipip6_rcv(struct sk_buff *skb)
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
!isatap_chksrc(skb, iph, tunnel)) {
tunnel->dev->stats.rx_errors++;
- kfree_skb(skb);
- return 0;
+ goto out;
+ }
+
+ __skb_tunnel_rx(skb, tunnel->dev);
+
+ err = IP_ECN_decapsulate(iph, skb);
+ if (unlikely(err)) {
+ if (log_ecn_error)
+ net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
+ &iph->saddr, iph->tos);
+ if (err > 1) {
+ ++tunnel->dev->stats.rx_frame_errors;
+ ++tunnel->dev->stats.rx_errors;
+ goto out;
+ }
}
tstats = this_cpu_ptr(tunnel->dev->tstats);
tstats->rx_packets++;
tstats->rx_bytes += skb->len;
- __skb_tunnel_rx(skb, tunnel->dev);
-
- ipip6_ecn_decapsulate(iph, skb);
-
netif_rx(skb);
return 0;