X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fnet%2Finet_ecn.h;h=10117c8503e87b649790b9d119467eb3e8d05c8f;hb=refs%2Fheads%2Fvserver;hp=4b9c7556273ae877578b6821c0e2868667a167f5;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 4b9c75562..10117c850 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -2,6 +2,10 @@ #define _INET_ECN_H_ #include +#include + +#include +#include enum { INET_ECN_NOT_ECT = 0, @@ -16,9 +20,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 +33,8 @@ 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 |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) : + INET_ECN_ECT_0; return outer; } @@ -44,15 +48,34 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) #define IP6_ECN_flow_xmit(sk, label) do { \ if (INET_ECN_is_capable(inet_sk(sk)->tos)) \ - (label) |= __constant_htons(INET_ECN_ECT_0 << 4); \ + (label) |= htonl(INET_ECN_ECT_0 << 20); \ } while (0) -static inline void IP_ECN_set_ce(struct iphdr *iph) +static inline int IP_ECN_set_ce(struct iphdr *iph) { - u32 check = iph->check; - check += __constant_htons(0xFFFE); - iph->check = check + (check>=0xFFFF); + u32 check = (__force u32)iph->check; + u32 ecn = (iph->tos + 1) & INET_ECN_MASK; + + /* + * After the last operation we have (in binary): + * INET_ECN_NOT_ECT => 01 + * INET_ECN_ECT_1 => 10 + * INET_ECN_ECT_0 => 11 + * INET_ECN_CE => 00 + */ + if (!(ecn & 2)) + return !ecn; + + /* + * The following gives us: + * INET_ECN_ECT_1 => check += htons(0xFFFD) + * INET_ECN_ECT_0 => check += htons(0xFFFE) + */ + check += (__force u16)htons(0xFFFB) + (__force u16)htons(ecn); + + iph->check = (__force __sum16)(check + (check>=0xFFFF)); iph->tos |= INET_ECN_CE; + return 1; } static inline void IP_ECN_clear(struct iphdr *iph) @@ -60,18 +83,48 @@ static inline void IP_ECN_clear(struct iphdr *iph) iph->tos &= ~INET_ECN_MASK; } +static inline void ipv4_copy_dscp(struct iphdr *outer, struct iphdr *inner) +{ + u32 dscp = ipv4_get_dsfield(outer) & ~INET_ECN_MASK; + ipv4_change_dsfield(inner, INET_ECN_MASK, dscp); +} + struct ipv6hdr; -static inline void IP6_ECN_set_ce(struct ipv6hdr *iph) +static inline int IP6_ECN_set_ce(struct ipv6hdr *iph) { - *(u32*)iph |= htonl(INET_ECN_CE << 20); + if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) + return 0; + *(__be32*)iph |= htonl(INET_ECN_CE << 20); + return 1; } static inline void IP6_ECN_clear(struct ipv6hdr *iph) { - *(u32*)iph &= ~htonl(INET_ECN_MASK << 20); + *(__be32*)iph &= ~htonl(INET_ECN_MASK << 20); } -#define ip6_get_dsfield(iph) ((ntohs(*(u16*)(iph)) >> 4) & 0xFF) +static inline void ipv6_copy_dscp(struct ipv6hdr *outer, struct ipv6hdr *inner) +{ + u32 dscp = ipv6_get_dsfield(outer) & ~INET_ECN_MASK; + ipv6_change_dsfield(inner, INET_ECN_MASK, dscp); +} + +static inline int INET_ECN_set_ce(struct sk_buff *skb) +{ + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + if (skb->nh.raw + sizeof(struct iphdr) <= skb->tail) + return IP_ECN_set_ce(skb->nh.iph); + break; + + case __constant_htons(ETH_P_IPV6): + if (skb->nh.raw + sizeof(struct ipv6hdr) <= skb->tail) + return IP6_ECN_set_ce(skb->nh.ipv6h); + break; + } + + return 0; +} #endif