diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/net/inet_ecn.h | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 2fa14691869c..aab73757bc4d 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h | |||
| @@ -15,6 +15,8 @@ enum { | |||
| 15 | INET_ECN_MASK = 3, | 15 | INET_ECN_MASK = 3, |
| 16 | }; | 16 | }; |
| 17 | 17 | ||
| 18 | extern int sysctl_tunnel_ecn_log; | ||
| 19 | |||
| 18 | static inline int INET_ECN_is_ce(__u8 dsfield) | 20 | static inline int INET_ECN_is_ce(__u8 dsfield) |
| 19 | { | 21 | { |
| 20 | return (dsfield & INET_ECN_MASK) == INET_ECN_CE; | 22 | return (dsfield & INET_ECN_MASK) == INET_ECN_CE; |
| @@ -145,4 +147,78 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb) | |||
| 145 | return 0; | 147 | return 0; |
| 146 | } | 148 | } |
| 147 | 149 | ||
| 150 | /* | ||
| 151 | * RFC 6080 4.2 | ||
| 152 | * To decapsulate the inner header at the tunnel egress, a compliant | ||
| 153 | * tunnel egress MUST set the outgoing ECN field to the codepoint at the | ||
| 154 | * intersection of the appropriate arriving inner header (row) and outer | ||
| 155 | * header (column) in Figure 4 | ||
| 156 | * | ||
| 157 | * +---------+------------------------------------------------+ | ||
| 158 | * |Arriving | Arriving Outer Header | | ||
| 159 | * | Inner +---------+------------+------------+------------+ | ||
| 160 | * | Header | Not-ECT | ECT(0) | ECT(1) | CE | | ||
| 161 | * +---------+---------+------------+------------+------------+ | ||
| 162 | * | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)| | ||
| 163 | * | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE | | ||
| 164 | * | ECT(1) | ECT(1) | ECT(1) (!) | ECT(1) | CE | | ||
| 165 | * | CE | CE | CE | CE(!!!)| CE | | ||
| 166 | * +---------+---------+------------+------------+------------+ | ||
| 167 | * | ||
| 168 | * Figure 4: New IP in IP Decapsulation Behaviour | ||
| 169 | * | ||
| 170 | * returns 0 on success | ||
| 171 | * 1 if something is broken and should be logged (!!! above) | ||
| 172 | * 2 if packet should be dropped | ||
| 173 | */ | ||
| 174 | static inline int INET_ECN_decapsulate(struct sk_buff *skb, | ||
| 175 | __u8 outer, __u8 inner) | ||
| 176 | { | ||
| 177 | if (INET_ECN_is_not_ect(inner)) { | ||
| 178 | switch (outer & INET_ECN_MASK) { | ||
| 179 | case INET_ECN_NOT_ECT: | ||
| 180 | return 0; | ||
| 181 | case INET_ECN_ECT_0: | ||
| 182 | case INET_ECN_ECT_1: | ||
| 183 | return 1; | ||
| 184 | case INET_ECN_CE: | ||
| 185 | return 2; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | if (INET_ECN_is_ce(outer)) | ||
| 190 | INET_ECN_set_ce(skb); | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | static inline int IP_ECN_decapsulate(const struct iphdr *oiph, | ||
| 196 | struct sk_buff *skb) | ||
| 197 | { | ||
| 198 | __u8 inner; | ||
| 199 | |||
| 200 | if (skb->protocol == htons(ETH_P_IP)) | ||
| 201 | inner = ip_hdr(skb)->tos; | ||
| 202 | else if (skb->protocol == htons(ETH_P_IPV6)) | ||
| 203 | inner = ipv6_get_dsfield(ipv6_hdr(skb)); | ||
| 204 | else | ||
| 205 | return 0; | ||
| 206 | |||
| 207 | return INET_ECN_decapsulate(skb, oiph->tos, inner); | ||
| 208 | } | ||
| 209 | |||
| 210 | static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h, | ||
| 211 | struct sk_buff *skb) | ||
| 212 | { | ||
| 213 | __u8 inner; | ||
| 214 | |||
| 215 | if (skb->protocol == htons(ETH_P_IP)) | ||
| 216 | inner = ip_hdr(skb)->tos; | ||
| 217 | else if (skb->protocol == htons(ETH_P_IPV6)) | ||
| 218 | inner = ipv6_get_dsfield(ipv6_hdr(skb)); | ||
| 219 | else | ||
| 220 | return 0; | ||
| 221 | |||
| 222 | return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner); | ||
| 223 | } | ||
| 148 | #endif | 224 | #endif |
