diff options
Diffstat (limited to 'include/net/inet_ecn.h')
-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 |