X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fnet%2Finet_ecn.h;h=d599c6bfbb86bc5eb0e83f91f9f7fb417d4631f2;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=55dc2b3be699e6b34b1b456df74a494ae5e30f8f;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 55dc2b3be..d599c6bfb 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -2,67 +2,129 @@ #define _INET_ECN_H_ #include +#include + +#include +#include + +enum { + INET_ECN_NOT_ECT = 0, + INET_ECN_ECT_1 = 1, + INET_ECN_ECT_0 = 2, + INET_ECN_CE = 3, + INET_ECN_MASK = 3, +}; static inline int INET_ECN_is_ce(__u8 dsfield) { - return (dsfield&3) == 3; + 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&3) == 2; + return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT; } static inline int INET_ECN_is_capable(__u8 dsfield) { - return (dsfield&2); + return (dsfield & INET_ECN_ECT_0); } static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) { - outer &= ~3; - if (INET_ECN_is_capable(inner)) - outer |= (inner & 3); + outer &= ~INET_ECN_MASK; + outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) : + INET_ECN_ECT_0; return outer; } -#define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= 2; } while (0) -#define INET_ECN_dontxmit(sk) do { inet_sk(sk)->tos &= ~3; } while (0) +#define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= INET_ECN_ECT_0; } while (0) +#define INET_ECN_dontxmit(sk) \ + do { inet_sk(sk)->tos &= ~INET_ECN_MASK; } while (0) -#define IP6_ECN_flow_init(label) do { \ - (label) &= ~htonl(3<<20); \ +#define IP6_ECN_flow_init(label) do { \ + (label) &= ~htonl(INET_ECN_MASK << 20); \ } while (0) -#define IP6_ECN_flow_xmit(sk, label) do { \ - if (INET_ECN_is_capable(inet_sk(sk)->tos)) \ - (label) |= __constant_htons(2 << 4); \ +#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); \ } 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); + 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 += htons(0xFFFB) + htons(ecn); + iph->check = check + (check>=0xFFFF); - iph->tos |= 1; + iph->tos |= INET_ECN_CE; + return 1; } static inline void IP_ECN_clear(struct iphdr *iph) { - iph->tos &= ~3; + 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(1<<20); + if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) + return 0; + *(u32*)iph |= htonl(INET_ECN_CE << 20); + return 1; } static inline void IP6_ECN_clear(struct ipv6hdr *iph) { - *(u32*)iph &= ~htonl(3<<20); + *(u32*)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