Skip to content

Commit

Permalink
tunnel: Propagate ECT(1) when decapsulating as recommended by RFC6040
Browse files Browse the repository at this point in the history
RFC 6040 recommends propagating an ECT(1) mark from an outer tunnel header
to the inner header if that inner header is already marked as ECT(0). When
RFC 6040 decapsulation was implemented, this case of propagation was not
added. This simply appears to be an oversight, so let's fix that.

Fixes: eccc1bb ("tunnel: drop packet if ECN present with not-ECT")
Reported-by: Bob Briscoe <[email protected]>
Reported-by: Olivier Tilmans <[email protected]>
Cc: Dave Taht <[email protected]>
Cc: Stephen Hemminger <[email protected]>
Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
tohojo authored and davem330 committed May 1, 2020
1 parent 0ce205d commit b723748
Showing 1 changed file with 55 additions and 2 deletions.
57 changes: 55 additions & 2 deletions include/net/inet_ecn.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ static inline int IP_ECN_set_ce(struct iphdr *iph)
return 1;
}

static inline int IP_ECN_set_ect1(struct iphdr *iph)
{
u32 check = (__force u32)iph->check;

if ((iph->tos & INET_ECN_MASK) != INET_ECN_ECT_0)
return 0;

check += (__force u16)htons(0x100);

iph->check = (__force __sum16)(check + (check>=0xFFFF));
iph->tos ^= INET_ECN_MASK;
return 1;
}

static inline void IP_ECN_clear(struct iphdr *iph)
{
iph->tos &= ~INET_ECN_MASK;
Expand Down Expand Up @@ -134,6 +148,22 @@ static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
return 1;
}

static inline int IP6_ECN_set_ect1(struct sk_buff *skb, struct ipv6hdr *iph)
{
__be32 from, to;

if ((ipv6_get_dsfield(iph) & INET_ECN_MASK) != INET_ECN_ECT_0)
return 0;

from = *(__be32 *)iph;
to = from ^ htonl(INET_ECN_MASK << 20);
*(__be32 *)iph = to;
if (skb->ip_summed == CHECKSUM_COMPLETE)
skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
(__force __wsum)to);
return 1;
}

static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner)
{
dscp &= ~INET_ECN_MASK;
Expand All @@ -159,6 +189,25 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb)
return 0;
}

static inline int INET_ECN_set_ect1(struct sk_buff *skb)
{
switch (skb->protocol) {
case cpu_to_be16(ETH_P_IP):
if (skb_network_header(skb) + sizeof(struct iphdr) <=
skb_tail_pointer(skb))
return IP_ECN_set_ect1(ip_hdr(skb));
break;

case cpu_to_be16(ETH_P_IPV6):
if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
skb_tail_pointer(skb))
return IP6_ECN_set_ect1(skb, ipv6_hdr(skb));
break;
}

return 0;
}

/*
* RFC 6040 4.2
* To decapsulate the inner header at the tunnel egress, a compliant
Expand Down Expand Up @@ -208,8 +257,12 @@ static inline int INET_ECN_decapsulate(struct sk_buff *skb,
int rc;

rc = __INET_ECN_decapsulate(outer, inner, &set_ce);
if (!rc && set_ce)
INET_ECN_set_ce(skb);
if (!rc) {
if (set_ce)
INET_ECN_set_ce(skb);
else if ((outer & INET_ECN_MASK) == INET_ECN_ECT_1)
INET_ECN_set_ect1(skb);
}

return rc;
}
Expand Down

0 comments on commit b723748

Please sign in to comment.