root/include/net/inet_ecn.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. INET_ECN_is_ce
  2. INET_ECN_is_not_ect
  3. INET_ECN_is_capable
  4. INET_ECN_encapsulate
  5. INET_ECN_xmit
  6. INET_ECN_dontxmit
  7. IP_ECN_set_ce
  8. IP_ECN_set_ect1
  9. IP_ECN_clear
  10. ipv4_copy_dscp
  11. IP6_ECN_set_ce
  12. IP6_ECN_set_ect1
  13. ipv6_copy_dscp
  14. INET_ECN_set_ce
  15. INET_ECN_set_ect1
  16. __INET_ECN_decapsulate
  17. INET_ECN_decapsulate
  18. IP_ECN_decapsulate
  19. IP6_ECN_decapsulate

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 #ifndef _INET_ECN_H_
   3 #define _INET_ECN_H_
   4 
   5 #include <linux/ip.h>
   6 #include <linux/skbuff.h>
   7 
   8 #include <net/inet_sock.h>
   9 #include <net/dsfield.h>
  10 
  11 enum {
  12         INET_ECN_NOT_ECT = 0,
  13         INET_ECN_ECT_1 = 1,
  14         INET_ECN_ECT_0 = 2,
  15         INET_ECN_CE = 3,
  16         INET_ECN_MASK = 3,
  17 };
  18 
  19 extern int sysctl_tunnel_ecn_log;
  20 
  21 static inline int INET_ECN_is_ce(__u8 dsfield)
  22 {
  23         return (dsfield & INET_ECN_MASK) == INET_ECN_CE;
  24 }
  25 
  26 static inline int INET_ECN_is_not_ect(__u8 dsfield)
  27 {
  28         return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT;
  29 }
  30 
  31 static inline int INET_ECN_is_capable(__u8 dsfield)
  32 {
  33         return dsfield & INET_ECN_ECT_0;
  34 }
  35 
  36 /*
  37  * RFC 3168 9.1.1
  38  *  The full-functionality option for ECN encapsulation is to copy the
  39  *  ECN codepoint of the inside header to the outside header on
  40  *  encapsulation if the inside header is not-ECT or ECT, and to set the
  41  *  ECN codepoint of the outside header to ECT(0) if the ECN codepoint of
  42  *  the inside header is CE.
  43  */
  44 static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner)
  45 {
  46         outer &= ~INET_ECN_MASK;
  47         outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) :
  48                                           INET_ECN_ECT_0;
  49         return outer;
  50 }
  51 
  52 static inline void INET_ECN_xmit(struct sock *sk)
  53 {
  54         inet_sk(sk)->tos |= INET_ECN_ECT_0;
  55         if (inet6_sk(sk) != NULL)
  56                 inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
  57 }
  58 
  59 static inline void INET_ECN_dontxmit(struct sock *sk)
  60 {
  61         inet_sk(sk)->tos &= ~INET_ECN_MASK;
  62         if (inet6_sk(sk) != NULL)
  63                 inet6_sk(sk)->tclass &= ~INET_ECN_MASK;
  64 }
  65 
  66 #define IP6_ECN_flow_init(label) do {           \
  67       (label) &= ~htonl(INET_ECN_MASK << 20);   \
  68     } while (0)
  69 
  70 #define IP6_ECN_flow_xmit(sk, label) do {                               \
  71         if (INET_ECN_is_capable(inet6_sk(sk)->tclass))                  \
  72                 (label) |= htonl(INET_ECN_ECT_0 << 20);                 \
  73     } while (0)
  74 
  75 static inline int IP_ECN_set_ce(struct iphdr *iph)
  76 {
  77         u32 check = (__force u32)iph->check;
  78         u32 ecn = (iph->tos + 1) & INET_ECN_MASK;
  79 
  80         /*
  81          * After the last operation we have (in binary):
  82          * INET_ECN_NOT_ECT => 01
  83          * INET_ECN_ECT_1   => 10
  84          * INET_ECN_ECT_0   => 11
  85          * INET_ECN_CE      => 00
  86          */
  87         if (!(ecn & 2))
  88                 return !ecn;
  89 
  90         /*
  91          * The following gives us:
  92          * INET_ECN_ECT_1 => check += htons(0xFFFD)
  93          * INET_ECN_ECT_0 => check += htons(0xFFFE)
  94          */
  95         check += (__force u16)htons(0xFFFB) + (__force u16)htons(ecn);
  96 
  97         iph->check = (__force __sum16)(check + (check>=0xFFFF));
  98         iph->tos |= INET_ECN_CE;
  99         return 1;
 100 }
 101 
 102 static inline int IP_ECN_set_ect1(struct iphdr *iph)
 103 {
 104         u32 check = (__force u32)iph->check;
 105 
 106         if ((iph->tos & INET_ECN_MASK) != INET_ECN_ECT_0)
 107                 return 0;
 108 
 109         check += (__force u16)htons(0x100);
 110 
 111         iph->check = (__force __sum16)(check + (check>=0xFFFF));
 112         iph->tos ^= INET_ECN_MASK;
 113         return 1;
 114 }
 115 
 116 static inline void IP_ECN_clear(struct iphdr *iph)
 117 {
 118         iph->tos &= ~INET_ECN_MASK;
 119 }
 120 
 121 static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner)
 122 {
 123         dscp &= ~INET_ECN_MASK;
 124         ipv4_change_dsfield(inner, INET_ECN_MASK, dscp);
 125 }
 126 
 127 struct ipv6hdr;
 128 
 129 /* Note:
 130  * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE,
 131  * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE
 132  * In IPv6 case, no checksum compensates the change in IPv6 header,
 133  * so we have to update skb->csum.
 134  */
 135 static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
 136 {
 137         __be32 from, to;
 138 
 139         if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
 140                 return 0;
 141 
 142         from = *(__be32 *)iph;
 143         to = from | htonl(INET_ECN_CE << 20);
 144         *(__be32 *)iph = to;
 145         if (skb->ip_summed == CHECKSUM_COMPLETE)
 146                 skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
 147                                      (__force __wsum)to);
 148         return 1;
 149 }
 150 
 151 static inline int IP6_ECN_set_ect1(struct sk_buff *skb, struct ipv6hdr *iph)
 152 {
 153         __be32 from, to;
 154 
 155         if ((ipv6_get_dsfield(iph) & INET_ECN_MASK) != INET_ECN_ECT_0)
 156                 return 0;
 157 
 158         from = *(__be32 *)iph;
 159         to = from ^ htonl(INET_ECN_MASK << 20);
 160         *(__be32 *)iph = to;
 161         if (skb->ip_summed == CHECKSUM_COMPLETE)
 162                 skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
 163                                      (__force __wsum)to);
 164         return 1;
 165 }
 166 
 167 static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner)
 168 {
 169         dscp &= ~INET_ECN_MASK;
 170         ipv6_change_dsfield(inner, INET_ECN_MASK, dscp);
 171 }
 172 
 173 static inline int INET_ECN_set_ce(struct sk_buff *skb)
 174 {
 175         switch (skb->protocol) {
 176         case cpu_to_be16(ETH_P_IP):
 177                 if (skb_network_header(skb) + sizeof(struct iphdr) <=
 178                     skb_tail_pointer(skb))
 179                         return IP_ECN_set_ce(ip_hdr(skb));
 180                 break;
 181 
 182         case cpu_to_be16(ETH_P_IPV6):
 183                 if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
 184                     skb_tail_pointer(skb))
 185                         return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
 186                 break;
 187         }
 188 
 189         return 0;
 190 }
 191 
 192 static inline int INET_ECN_set_ect1(struct sk_buff *skb)
 193 {
 194         switch (skb->protocol) {
 195         case cpu_to_be16(ETH_P_IP):
 196                 if (skb_network_header(skb) + sizeof(struct iphdr) <=
 197                     skb_tail_pointer(skb))
 198                         return IP_ECN_set_ect1(ip_hdr(skb));
 199                 break;
 200 
 201         case cpu_to_be16(ETH_P_IPV6):
 202                 if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
 203                     skb_tail_pointer(skb))
 204                         return IP6_ECN_set_ect1(skb, ipv6_hdr(skb));
 205                 break;
 206         }
 207 
 208         return 0;
 209 }
 210 
 211 /*
 212  * RFC 6040 4.2
 213  *  To decapsulate the inner header at the tunnel egress, a compliant
 214  *  tunnel egress MUST set the outgoing ECN field to the codepoint at the
 215  *  intersection of the appropriate arriving inner header (row) and outer
 216  *  header (column) in Figure 4
 217  *
 218  *      +---------+------------------------------------------------+
 219  *      |Arriving |            Arriving Outer Header               |
 220  *      |   Inner +---------+------------+------------+------------+
 221  *      |  Header | Not-ECT | ECT(0)     | ECT(1)     |     CE     |
 222  *      +---------+---------+------------+------------+------------+
 223  *      | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)|
 224  *      |  ECT(0) |  ECT(0) | ECT(0)     | ECT(1)     |     CE     |
 225  *      |  ECT(1) |  ECT(1) | ECT(1) (!) | ECT(1)     |     CE     |
 226  *      |    CE   |      CE |     CE     |     CE(!!!)|     CE     |
 227  *      +---------+---------+------------+------------+------------+
 228  *
 229  *             Figure 4: New IP in IP Decapsulation Behaviour
 230  *
 231  *  returns 0 on success
 232  *          1 if something is broken and should be logged (!!! above)
 233  *          2 if packet should be dropped
 234  */
 235 static inline int __INET_ECN_decapsulate(__u8 outer, __u8 inner, bool *set_ce)
 236 {
 237         if (INET_ECN_is_not_ect(inner)) {
 238                 switch (outer & INET_ECN_MASK) {
 239                 case INET_ECN_NOT_ECT:
 240                         return 0;
 241                 case INET_ECN_ECT_0:
 242                 case INET_ECN_ECT_1:
 243                         return 1;
 244                 case INET_ECN_CE:
 245                         return 2;
 246                 }
 247         }
 248 
 249         *set_ce = INET_ECN_is_ce(outer);
 250         return 0;
 251 }
 252 
 253 static inline int INET_ECN_decapsulate(struct sk_buff *skb,
 254                                        __u8 outer, __u8 inner)
 255 {
 256         bool set_ce = false;
 257         int rc;
 258 
 259         rc = __INET_ECN_decapsulate(outer, inner, &set_ce);
 260         if (!rc) {
 261                 if (set_ce)
 262                         INET_ECN_set_ce(skb);
 263                 else if ((outer & INET_ECN_MASK) == INET_ECN_ECT_1)
 264                         INET_ECN_set_ect1(skb);
 265         }
 266 
 267         return rc;
 268 }
 269 
 270 static inline int IP_ECN_decapsulate(const struct iphdr *oiph,
 271                                      struct sk_buff *skb)
 272 {
 273         __u8 inner;
 274 
 275         if (skb->protocol == htons(ETH_P_IP))
 276                 inner = ip_hdr(skb)->tos;
 277         else if (skb->protocol == htons(ETH_P_IPV6))
 278                 inner = ipv6_get_dsfield(ipv6_hdr(skb));
 279         else
 280                 return 0;
 281 
 282         return INET_ECN_decapsulate(skb, oiph->tos, inner);
 283 }
 284 
 285 static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h,
 286                                       struct sk_buff *skb)
 287 {
 288         __u8 inner;
 289 
 290         if (skb->protocol == htons(ETH_P_IP))
 291                 inner = ip_hdr(skb)->tos;
 292         else if (skb->protocol == htons(ETH_P_IPV6))
 293                 inner = ipv6_get_dsfield(ipv6_hdr(skb));
 294         else
 295                 return 0;
 296 
 297         return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner);
 298 }
 299 #endif

/* [<][>][^][v][top][bottom][index][help] */