Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _INET_ECN_H_
0003 #define _INET_ECN_H_
0004 
0005 #include <linux/ip.h>
0006 #include <linux/skbuff.h>
0007 #include <linux/if_vlan.h>
0008 
0009 #include <net/inet_sock.h>
0010 #include <net/dsfield.h>
0011 #include <net/checksum.h>
0012 
0013 enum {
0014     INET_ECN_NOT_ECT = 0,
0015     INET_ECN_ECT_1 = 1,
0016     INET_ECN_ECT_0 = 2,
0017     INET_ECN_CE = 3,
0018     INET_ECN_MASK = 3,
0019 };
0020 
0021 extern int sysctl_tunnel_ecn_log;
0022 
0023 static inline int INET_ECN_is_ce(__u8 dsfield)
0024 {
0025     return (dsfield & INET_ECN_MASK) == INET_ECN_CE;
0026 }
0027 
0028 static inline int INET_ECN_is_not_ect(__u8 dsfield)
0029 {
0030     return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT;
0031 }
0032 
0033 static inline int INET_ECN_is_capable(__u8 dsfield)
0034 {
0035     return dsfield & INET_ECN_ECT_0;
0036 }
0037 
0038 /*
0039  * RFC 3168 9.1.1
0040  *  The full-functionality option for ECN encapsulation is to copy the
0041  *  ECN codepoint of the inside header to the outside header on
0042  *  encapsulation if the inside header is not-ECT or ECT, and to set the
0043  *  ECN codepoint of the outside header to ECT(0) if the ECN codepoint of
0044  *  the inside header is CE.
0045  */
0046 static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner)
0047 {
0048     outer &= ~INET_ECN_MASK;
0049     outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) :
0050                       INET_ECN_ECT_0;
0051     return outer;
0052 }
0053 
0054 static inline void INET_ECN_xmit(struct sock *sk)
0055 {
0056     inet_sk(sk)->tos |= INET_ECN_ECT_0;
0057     if (inet6_sk(sk) != NULL)
0058         inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
0059 }
0060 
0061 static inline void INET_ECN_dontxmit(struct sock *sk)
0062 {
0063     inet_sk(sk)->tos &= ~INET_ECN_MASK;
0064     if (inet6_sk(sk) != NULL)
0065         inet6_sk(sk)->tclass &= ~INET_ECN_MASK;
0066 }
0067 
0068 #define IP6_ECN_flow_init(label) do {       \
0069       (label) &= ~htonl(INET_ECN_MASK << 20);   \
0070     } while (0)
0071 
0072 #define IP6_ECN_flow_xmit(sk, label) do {               \
0073     if (INET_ECN_is_capable(inet6_sk(sk)->tclass))          \
0074         (label) |= htonl(INET_ECN_ECT_0 << 20);         \
0075     } while (0)
0076 
0077 static inline int IP_ECN_set_ce(struct iphdr *iph)
0078 {
0079     u32 ecn = (iph->tos + 1) & INET_ECN_MASK;
0080     __be16 check_add;
0081 
0082     /*
0083      * After the last operation we have (in binary):
0084      * INET_ECN_NOT_ECT => 01
0085      * INET_ECN_ECT_1   => 10
0086      * INET_ECN_ECT_0   => 11
0087      * INET_ECN_CE      => 00
0088      */
0089     if (!(ecn & 2))
0090         return !ecn;
0091 
0092     /*
0093      * The following gives us:
0094      * INET_ECN_ECT_1 => check += htons(0xFFFD)
0095      * INET_ECN_ECT_0 => check += htons(0xFFFE)
0096      */
0097     check_add = (__force __be16)((__force u16)htons(0xFFFB) +
0098                      (__force u16)htons(ecn));
0099 
0100     iph->check = csum16_add(iph->check, check_add);
0101     iph->tos |= INET_ECN_CE;
0102     return 1;
0103 }
0104 
0105 static inline int IP_ECN_set_ect1(struct iphdr *iph)
0106 {
0107     if ((iph->tos & INET_ECN_MASK) != INET_ECN_ECT_0)
0108         return 0;
0109 
0110     iph->check = csum16_add(iph->check, htons(0x1));
0111     iph->tos ^= INET_ECN_MASK;
0112     return 1;
0113 }
0114 
0115 static inline void IP_ECN_clear(struct iphdr *iph)
0116 {
0117     iph->tos &= ~INET_ECN_MASK;
0118 }
0119 
0120 static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner)
0121 {
0122     dscp &= ~INET_ECN_MASK;
0123     ipv4_change_dsfield(inner, INET_ECN_MASK, dscp);
0124 }
0125 
0126 struct ipv6hdr;
0127 
0128 /* Note:
0129  * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE,
0130  * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE
0131  * In IPv6 case, no checksum compensates the change in IPv6 header,
0132  * so we have to update skb->csum.
0133  */
0134 static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
0135 {
0136     __be32 from, to;
0137 
0138     if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
0139         return 0;
0140 
0141     from = *(__be32 *)iph;
0142     to = from | htonl(INET_ECN_CE << 20);
0143     *(__be32 *)iph = to;
0144     if (skb->ip_summed == CHECKSUM_COMPLETE)
0145         skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
0146                      (__force __wsum)to);
0147     return 1;
0148 }
0149 
0150 static inline int IP6_ECN_set_ect1(struct sk_buff *skb, struct ipv6hdr *iph)
0151 {
0152     __be32 from, to;
0153 
0154     if ((ipv6_get_dsfield(iph) & INET_ECN_MASK) != INET_ECN_ECT_0)
0155         return 0;
0156 
0157     from = *(__be32 *)iph;
0158     to = from ^ htonl(INET_ECN_MASK << 20);
0159     *(__be32 *)iph = to;
0160     if (skb->ip_summed == CHECKSUM_COMPLETE)
0161         skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
0162                      (__force __wsum)to);
0163     return 1;
0164 }
0165 
0166 static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner)
0167 {
0168     dscp &= ~INET_ECN_MASK;
0169     ipv6_change_dsfield(inner, INET_ECN_MASK, dscp);
0170 }
0171 
0172 static inline int INET_ECN_set_ce(struct sk_buff *skb)
0173 {
0174     switch (skb_protocol(skb, true)) {
0175     case cpu_to_be16(ETH_P_IP):
0176         if (skb_network_header(skb) + sizeof(struct iphdr) <=
0177             skb_tail_pointer(skb))
0178             return IP_ECN_set_ce(ip_hdr(skb));
0179         break;
0180 
0181     case cpu_to_be16(ETH_P_IPV6):
0182         if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
0183             skb_tail_pointer(skb))
0184             return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
0185         break;
0186     }
0187 
0188     return 0;
0189 }
0190 
0191 static inline int skb_get_dsfield(struct sk_buff *skb)
0192 {
0193     switch (skb_protocol(skb, true)) {
0194     case cpu_to_be16(ETH_P_IP):
0195         if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
0196             break;
0197         return ipv4_get_dsfield(ip_hdr(skb));
0198 
0199     case cpu_to_be16(ETH_P_IPV6):
0200         if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
0201             break;
0202         return ipv6_get_dsfield(ipv6_hdr(skb));
0203     }
0204 
0205     return -1;
0206 }
0207 
0208 static inline int INET_ECN_set_ect1(struct sk_buff *skb)
0209 {
0210     switch (skb_protocol(skb, true)) {
0211     case cpu_to_be16(ETH_P_IP):
0212         if (skb_network_header(skb) + sizeof(struct iphdr) <=
0213             skb_tail_pointer(skb))
0214             return IP_ECN_set_ect1(ip_hdr(skb));
0215         break;
0216 
0217     case cpu_to_be16(ETH_P_IPV6):
0218         if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
0219             skb_tail_pointer(skb))
0220             return IP6_ECN_set_ect1(skb, ipv6_hdr(skb));
0221         break;
0222     }
0223 
0224     return 0;
0225 }
0226 
0227 /*
0228  * RFC 6040 4.2
0229  *  To decapsulate the inner header at the tunnel egress, a compliant
0230  *  tunnel egress MUST set the outgoing ECN field to the codepoint at the
0231  *  intersection of the appropriate arriving inner header (row) and outer
0232  *  header (column) in Figure 4
0233  *
0234  *      +---------+------------------------------------------------+
0235  *      |Arriving |            Arriving Outer Header               |
0236  *      |   Inner +---------+------------+------------+------------+
0237  *      |  Header | Not-ECT | ECT(0)     | ECT(1)     |     CE     |
0238  *      +---------+---------+------------+------------+------------+
0239  *      | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)|
0240  *      |  ECT(0) |  ECT(0) | ECT(0)     | ECT(1)     |     CE     |
0241  *      |  ECT(1) |  ECT(1) | ECT(1) (!) | ECT(1)     |     CE     |
0242  *      |    CE   |      CE |     CE     |     CE(!!!)|     CE     |
0243  *      +---------+---------+------------+------------+------------+
0244  *
0245  *             Figure 4: New IP in IP Decapsulation Behaviour
0246  *
0247  *  returns 0 on success
0248  *          1 if something is broken and should be logged (!!! above)
0249  *          2 if packet should be dropped
0250  */
0251 static inline int __INET_ECN_decapsulate(__u8 outer, __u8 inner, bool *set_ce)
0252 {
0253     if (INET_ECN_is_not_ect(inner)) {
0254         switch (outer & INET_ECN_MASK) {
0255         case INET_ECN_NOT_ECT:
0256             return 0;
0257         case INET_ECN_ECT_0:
0258         case INET_ECN_ECT_1:
0259             return 1;
0260         case INET_ECN_CE:
0261             return 2;
0262         }
0263     }
0264 
0265     *set_ce = INET_ECN_is_ce(outer);
0266     return 0;
0267 }
0268 
0269 static inline int INET_ECN_decapsulate(struct sk_buff *skb,
0270                        __u8 outer, __u8 inner)
0271 {
0272     bool set_ce = false;
0273     int rc;
0274 
0275     rc = __INET_ECN_decapsulate(outer, inner, &set_ce);
0276     if (!rc) {
0277         if (set_ce)
0278             INET_ECN_set_ce(skb);
0279         else if ((outer & INET_ECN_MASK) == INET_ECN_ECT_1)
0280             INET_ECN_set_ect1(skb);
0281     }
0282 
0283     return rc;
0284 }
0285 
0286 static inline int IP_ECN_decapsulate(const struct iphdr *oiph,
0287                      struct sk_buff *skb)
0288 {
0289     __u8 inner;
0290 
0291     switch (skb_protocol(skb, true)) {
0292     case htons(ETH_P_IP):
0293         inner = ip_hdr(skb)->tos;
0294         break;
0295     case htons(ETH_P_IPV6):
0296         inner = ipv6_get_dsfield(ipv6_hdr(skb));
0297         break;
0298     default:
0299         return 0;
0300     }
0301 
0302     return INET_ECN_decapsulate(skb, oiph->tos, inner);
0303 }
0304 
0305 static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h,
0306                       struct sk_buff *skb)
0307 {
0308     __u8 inner;
0309 
0310     switch (skb_protocol(skb, true)) {
0311     case htons(ETH_P_IP):
0312         inner = ip_hdr(skb)->tos;
0313         break;
0314     case htons(ETH_P_IPV6):
0315         inner = ipv6_get_dsfield(ipv6_hdr(skb));
0316         break;
0317     default:
0318         return 0;
0319     }
0320 
0321     return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner);
0322 }
0323 #endif