From b6eeb1e525be68e87e762946786788c4256a7054 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 7 Sep 2004 23:38:11 -0700 Subject: [PATCH] [IPV4/IPV6]: Update ECN handling. This patch brings the IP ECN handling up-to-date with repsect to RFC 3168. Mostly this means treating ECT(1) in the same way as ECT(0). Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/inet_ecn.h | 27 ++++++++++++++++++++------- include/net/tcp_ecn.h | 2 +- net/ipv4/ip_gre.c | 6 ++---- net/ipv4/ipip.c | 3 +-- net/ipv4/xfrm4_input.c | 3 +-- net/ipv6/sit.c | 3 +-- net/ipv6/xfrm6_input.c | 3 +-- net/sched/sch_red.c | 7 +++---- 8 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 4b9c7556273ae..8d0df10e4549b 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -16,9 +16,9 @@ static inline int INET_ECN_is_ce(__u8 dsfield) return (dsfield & INET_ECN_MASK) == INET_ECN_CE; } -static inline int INET_ECN_is_not_ce(__u8 dsfield) +static inline int INET_ECN_is_not_ect(__u8 dsfield) { - return (dsfield & INET_ECN_MASK) == INET_ECN_ECT_0; + return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT; } static inline int INET_ECN_is_capable(__u8 dsfield) @@ -29,8 +29,7 @@ static inline int INET_ECN_is_capable(__u8 dsfield) static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) { outer &= ~INET_ECN_MASK; - if (INET_ECN_is_capable(inner)) - outer |= (inner & INET_ECN_MASK); + outer |= (inner & INET_ECN_MASK) ?: INET_ECN_ECT_0; return outer; } @@ -50,7 +49,19 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) static inline void IP_ECN_set_ce(struct iphdr *iph) { u32 check = iph->check; - check += __constant_htons(0xFFFE); + + switch (iph->tos & INET_ECN_MASK) { + default: + case INET_ECN_NOT_ECT: + case INET_ECN_CE: + return; + case INET_ECN_ECT_1: + check += __constant_htons(0xFFFD); + break; + case INET_ECN_ECT_0: + check += __constant_htons(0xFFFE); + break; + } iph->check = check + (check>=0xFFFF); iph->tos |= INET_ECN_CE; } @@ -60,10 +71,14 @@ static inline void IP_ECN_clear(struct iphdr *iph) iph->tos &= ~INET_ECN_MASK; } +#define ip6_get_dsfield(iph) ((ntohs(*(u16*)(iph)) >> 4) & 0xFF) + struct ipv6hdr; static inline void IP6_ECN_set_ce(struct ipv6hdr *iph) { + if (INET_ECN_is_not_ect(ip6_get_dsfield(iph))) + return; *(u32*)iph |= htonl(INET_ECN_CE << 20); } @@ -72,6 +87,4 @@ static inline void IP6_ECN_clear(struct ipv6hdr *iph) *(u32*)iph &= ~htonl(INET_ECN_MASK << 20); } -#define ip6_get_dsfield(iph) ((ntohs(*(u16*)(iph)) >> 4) & 0xFF) - #endif diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h index 06105757262db..38e0feddc148f 100644 --- a/include/net/tcp_ecn.h +++ b/include/net/tcp_ecn.h @@ -90,7 +90,7 @@ TCP_ECN_check_ce(struct tcp_opt *tp, struct sk_buff *skb) /* Funny extension: if ECT is not set on a segment, * it is surely retransmit. It is not in ECN RFC, * but Linux follows this rule. */ - else if (!INET_ECN_is_capable((TCP_SKB_CB(skb)->flags))) + else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags))) tcp_enter_quickack_mode(tp); } } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 2a3a8fb7e6a1f..ed106d11aba17 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -533,11 +533,9 @@ static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) { if (INET_ECN_is_ce(iph->tos)) { if (skb->protocol == htons(ETH_P_IP)) { - if (INET_ECN_is_not_ce(skb->nh.iph->tos)) - IP_ECN_set_ce(skb->nh.iph); + IP_ECN_set_ce(skb->nh.iph); } else if (skb->protocol == htons(ETH_P_IPV6)) { - if (INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) - IP6_ECN_set_ce(skb->nh.ipv6h); + IP6_ECN_set_ce(skb->nh.ipv6h); } } } diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 98ba22404ac37..5c480d407dd88 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -461,8 +461,7 @@ static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff { struct iphdr *inner_iph = skb->nh.iph; - if (INET_ECN_is_ce(outer_iph->tos) && - INET_ECN_is_not_ce(inner_iph->tos)) + if (INET_ECN_is_ce(outer_iph->tos)) IP_ECN_set_ce(inner_iph); } diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index b045c87197f13..f074d49306368 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -24,8 +24,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) struct iphdr *outer_iph = skb->nh.iph; struct iphdr *inner_iph = skb->h.ipiph; - if (INET_ECN_is_ce(outer_iph->tos) && - INET_ECN_is_not_ce(inner_iph->tos)) + if (INET_ECN_is_ce(outer_iph->tos)) IP_ECN_set_ce(inner_iph); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 23482d1bdcf09..6ce7719d43a9c 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -360,8 +360,7 @@ out: static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) { - if (INET_ECN_is_ce(iph->tos) && - INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) + if (INET_ECN_is_ce(iph->tos)) IP6_ECN_set_ce(skb->nh.ipv6h); } diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 92e74233fcdbc..89000c7889f80 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -21,8 +21,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) struct ipv6hdr *outer_iph = skb->nh.ipv6h; struct ipv6hdr *inner_iph = skb->h.ipv6h; - if (INET_ECN_is_ce(ip6_get_dsfield(outer_iph)) && - INET_ECN_is_not_ce(ip6_get_dsfield(inner_iph))) + if (INET_ECN_is_ce(ip6_get_dsfield(outer_iph))) IP6_ECN_set_ce(inner_iph); } diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 5630abb209adb..e5899f67ed640 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -162,13 +162,12 @@ static int red_ecn_mark(struct sk_buff *skb) switch (skb->protocol) { case __constant_htons(ETH_P_IP): - if (!INET_ECN_is_capable(skb->nh.iph->tos)) + if (INET_ECN_is_not_ect(skb->nh.iph->tos)) return 0; - if (INET_ECN_is_not_ce(skb->nh.iph->tos)) - IP_ECN_set_ce(skb->nh.iph); + IP_ECN_set_ce(skb->nh.iph); return 1; case __constant_htons(ETH_P_IPV6): - if (!INET_ECN_is_capable(ip6_get_dsfield(skb->nh.ipv6h))) + if (INET_ECN_is_not_ect(ip6_get_dsfield(skb->nh.ipv6h))) return 0; IP6_ECN_set_ce(skb->nh.ipv6h); return 1; -- 2.53.0