tunnel: support copying TTL and flow label from inner to outer
[vpp.git] / src / vnet / ip / ip4_packet.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * ip4/packet.h: ip4 packet format
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #ifndef included_ip4_packet_h
41 #define included_ip4_packet_h
42
43 #include <vnet/ip/ip_packet.h>  /* for ip_csum_t */
44 #include <vnet/tcp/tcp_packet.h>        /* for tcp_header_t */
45 #include <vppinfra/byte_order.h>        /* for clib_net_to_host_u16 */
46 #include <vppinfra/warnings.h>  /* for WARN_OFF/WARN_ON macro */
47
48 /* IP4 address which can be accessed either as 4 bytes
49    or as a 32-bit number. */
50 typedef union
51 {
52   u8 data[4];
53   u32 data_u32;
54   /* Aliases. */
55   u8 as_u8[4];
56   u16 as_u16[2];
57   u32 as_u32;
58 } ip4_address_t;
59
60 typedef struct
61 {
62   /* IP address must be first for ip_interface_address_get_address() to work */
63   ip4_address_t ip4_addr;
64   u32 fib_index;
65 } ip4_address_fib_t;
66
67 always_inline void
68 ip4_addr_fib_init (ip4_address_fib_t * addr_fib,
69                    const ip4_address_t * address, u32 fib_index)
70 {
71   clib_memcpy_fast (&addr_fib->ip4_addr, address,
72                     sizeof (addr_fib->ip4_addr));
73   addr_fib->fib_index = fib_index;
74 }
75
76 /* (src,dst) pair of addresses as found in packet header. */
77 typedef struct
78 {
79   ip4_address_t src, dst;
80 } ip4_address_pair_t;
81
82 typedef struct
83 {
84   ip4_address_t addr, mask;
85 } ip4_address_and_mask_t;
86
87 typedef union
88 {
89   struct
90   {
91     /* 4 bit packet length (in 32bit units) and version VVVVLLLL.
92        e.g. for packets w/ no options ip_version_and_header_length == 0x45. */
93     u8 ip_version_and_header_length;
94
95     /* Type of service. */
96     ip_dscp_t tos;
97
98     /* Total layer 3 packet length including this header. */
99     u16 length;
100
101     /* Fragmentation ID. */
102     u16 fragment_id;
103
104     /* 3 bits of flags and 13 bits of fragment offset (in units
105        of 8 byte quantities). */
106     u16 flags_and_fragment_offset;
107 #define IP4_HEADER_FLAG_MORE_FRAGMENTS (1 << 13)
108 #define IP4_HEADER_FLAG_DONT_FRAGMENT (1 << 14)
109 #define IP4_HEADER_FLAG_CONGESTION (1 << 15)
110
111     /* Time to live decremented by router at each hop. */
112     u8 ttl;
113
114     /* Next level protocol packet. */
115     u8 protocol;
116
117     /* Checksum. */
118     u16 checksum;
119
120     /* Source and destination address. */
121     union
122     {
123       struct
124       {
125         ip4_address_t src_address, dst_address;
126       };
127       ip4_address_pair_t address_pair;
128     };
129   };
130
131   /* For checksumming we'll want to access IP header in word sized chunks. */
132   /* For 64 bit machines. */
133   /* *INDENT-OFF* */
134   CLIB_PACKED (struct {
135     u64 checksum_data_64[2];
136     u32 checksum_data_64_32[1];
137   });
138   /* *INDENT-ON* */
139
140   /* For 32 bit machines. */
141   /* *INDENT-OFF* */
142   CLIB_PACKED (struct {
143     u32 checksum_data_32[5];
144   });
145   /* *INDENT-ON* */
146 } ip4_header_t;
147
148 /* Value of ip_version_and_header_length for packets w/o options. */
149 #define IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS \
150   ((4 << 4) | (sizeof (ip4_header_t) / sizeof (u32)))
151
152 #define IP4_ROUTER_ALERT_OPTION 20
153
154 always_inline u16
155 ip4_get_fragment_offset (const ip4_header_t * i)
156 {
157   return clib_net_to_host_u16 (i->flags_and_fragment_offset) & 0x1fff;
158 }
159
160 always_inline u16
161 ip4_get_fragment_more (const ip4_header_t * i)
162 {
163   return clib_net_to_host_u16 (i->flags_and_fragment_offset) &
164     IP4_HEADER_FLAG_MORE_FRAGMENTS;
165 }
166
167 always_inline int
168 ip4_is_fragment (const ip4_header_t * i)
169 {
170   return (i->flags_and_fragment_offset &
171           clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS));
172 }
173
174 always_inline int
175 ip4_is_first_fragment (const ip4_header_t * i)
176 {
177   return (i->flags_and_fragment_offset &
178           clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS)) ==
179     clib_net_to_host_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
180 }
181
182 /* Fragment offset in bytes. */
183 always_inline int
184 ip4_get_fragment_offset_bytes (const ip4_header_t * i)
185 {
186   return 8 * ip4_get_fragment_offset (i);
187 }
188
189 always_inline int
190 ip4_header_bytes (const ip4_header_t * i)
191 {
192   return sizeof (u32) * (i->ip_version_and_header_length & 0xf);
193 }
194
195 always_inline void *
196 ip4_next_header (ip4_header_t * i)
197 {
198   return (void *) i + ip4_header_bytes (i);
199 }
200
201 /* Turn off array bounds check due to ip4_header_t
202    option field operations. */
203
204 /* *INDENT-OFF* */
205 WARN_OFF(array-bounds)
206 /* *INDENT-ON* */
207
208 static_always_inline u16
209 ip4_header_checksum_inline (ip4_header_t * i, int with_checksum)
210 {
211   int option_len = (i->ip_version_and_header_length & 0xf) - 5;
212   uword sum = 0;
213 #if uword_bits == 64
214   u32 *iphdr = (u32 *) i;
215
216   sum += iphdr[0];
217   sum += iphdr[1];
218   sum += with_checksum ? iphdr[2] : *(u16 *) (iphdr + 2);
219   /* skip checksum */
220   sum += iphdr[3];
221   sum += iphdr[4];
222
223   if (PREDICT_FALSE (option_len > 0))
224     switch (option_len)
225       {
226       case 10:
227         sum += iphdr[14];
228       case 9:
229         sum += iphdr[13];
230       case 8:
231         sum += iphdr[12];
232       case 7:
233         sum += iphdr[11];
234       case 6:
235         sum += iphdr[10];
236       case 5:
237         sum += iphdr[9];
238       case 4:
239         sum += iphdr[8];
240       case 3:
241         sum += iphdr[7];
242       case 2:
243         sum += iphdr[6];
244       case 1:
245         sum += iphdr[5];
246       default:
247         break;
248       }
249
250   sum = ((u32) sum) + (sum >> 32);
251 #else
252   u16 *iphdr = (u16 *) i;
253
254   sum += iphdr[0];
255   sum += iphdr[1];
256   sum += iphdr[2];
257   sum += iphdr[3];
258   sum += iphdr[4];
259   if (with_checksum)
260     sum += iphdr[5];
261   sum += iphdr[6];
262   sum += iphdr[7];
263   sum += iphdr[8];
264   sum += iphdr[9];
265
266   if (PREDICT_FALSE (option_len > 0))
267     switch (option_len)
268       {
269       case 10:
270         sum += iphdr[28];
271         sum += iphdr[29];
272       case 9:
273         sum += iphdr[26];
274         sum += iphdr[27];
275       case 8:
276         sum += iphdr[24];
277         sum += iphdr[25];
278       case 7:
279         sum += iphdr[22];
280         sum += iphdr[23];
281       case 6:
282         sum += iphdr[20];
283         sum += iphdr[21];
284       case 5:
285         sum += iphdr[18];
286         sum += iphdr[19];
287       case 4:
288         sum += iphdr[16];
289         sum += iphdr[17];
290       case 3:
291         sum += iphdr[14];
292         sum += iphdr[15];
293       case 2:
294         sum += iphdr[12];
295         sum += iphdr[13];
296       case 1:
297         sum += iphdr[10];
298         sum += iphdr[11];
299       default:
300         break;
301       }
302 #endif
303
304   sum = ((u16) sum) + (sum >> 16);
305   sum = ((u16) sum) + (sum >> 16);
306   return ~((u16) sum);
307 }
308
309 /* *INDENT-OFF* */
310 WARN_ON(array-bounds)
311 /* *INDENT-ON* */
312
313 always_inline u16
314 ip4_header_checksum (ip4_header_t * i)
315 {
316   return ip4_header_checksum_inline (i, /* with_checksum */ 0);
317 }
318
319 always_inline void
320 ip4_header_set_dscp (ip4_header_t * ip4, ip_dscp_t dscp)
321 {
322   ip4->tos &= ~0xfc;
323   /* not masking the dscp value to save th instruction
324    * it shouldn't b necessary since the argument is an enum
325    * whose range is therefore constrained in the CP. in the
326    * DP it will have been taken from another packet, so again
327    * constrained in  value */
328   ip4->tos |= dscp << IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT;
329 }
330
331 always_inline void
332 ip4_header_set_ecn (ip4_header_t * ip4, ip_ecn_t ecn)
333 {
334   ip4->tos &= ~IP_PACKET_TC_FIELD_ECN_MASK;
335   ip4->tos |= ecn;
336 }
337
338 always_inline void
339 ip4_header_set_ecn_w_chksum (ip4_header_t * ip4, ip_ecn_t ecn)
340 {
341   ip_csum_t sum = ip4->checksum;
342   u8 old = ip4->tos;
343   u8 new = (old & ~IP_PACKET_TC_FIELD_ECN_MASK) | ecn;
344
345   sum = ip_csum_update (sum, old, new, ip4_header_t, tos);
346   ip4->checksum = ip_csum_fold (sum);
347   ip4->tos = new;
348 }
349
350 always_inline ip_dscp_t
351 ip4_header_get_dscp (const ip4_header_t * ip4)
352 {
353   return (ip4->tos >> IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT);
354 }
355
356 always_inline ip_ecn_t
357 ip4_header_get_ecn (const ip4_header_t * ip4)
358 {
359   return (ip4->tos & IP_PACKET_TC_FIELD_ECN_MASK);
360 }
361
362 always_inline u8
363 ip4_header_get_ttl (const ip4_header_t *ip4)
364 {
365   return (ip4->ttl);
366 }
367
368 always_inline void
369 ip4_header_set_ttl (ip4_header_t *ip4, u8 ttl)
370 {
371   ip4->ttl = ttl;
372 }
373
374 always_inline void
375 ip4_header_set_df (ip4_header_t * ip4)
376 {
377   ip4->flags_and_fragment_offset |=
378     clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
379 }
380
381 always_inline void
382 ip4_header_clear_df (ip4_header_t * ip4)
383 {
384   ip4->flags_and_fragment_offset &=
385     ~clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
386 }
387
388 always_inline u8
389 ip4_header_get_df (const ip4_header_t * ip4)
390 {
391   return (! !(ip4->flags_and_fragment_offset &
392               clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)));
393 }
394
395 static inline uword
396 ip4_header_checksum_is_valid (ip4_header_t * i)
397 {
398   return ip4_header_checksum_inline (i, /* with_checksum */ 1) == 0;
399 }
400
401 #define ip4_partial_header_checksum_x1(ip0,sum0)                        \
402 do {                                                                    \
403   if (BITS (ip_csum_t) > 32)                                            \
404     {                                                                   \
405       sum0 = ip0->checksum_data_64[0];                                  \
406       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]);       \
407       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]);    \
408     }                                                                   \
409   else                                                                  \
410     {                                                                   \
411       sum0 = ip0->checksum_data_32[0];                                  \
412       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]);       \
413       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]);       \
414       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]);       \
415       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]);       \
416     }                                                                   \
417 } while (0)
418
419 #define ip4_partial_header_checksum_x2(ip0,ip1,sum0,sum1)               \
420 do {                                                                    \
421   if (BITS (ip_csum_t) > 32)                                            \
422     {                                                                   \
423       sum0 = ip0->checksum_data_64[0];                                  \
424       sum1 = ip1->checksum_data_64[0];                                  \
425       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]);       \
426       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64[1]);       \
427       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]);    \
428       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64_32[0]);    \
429     }                                                                   \
430   else                                                                  \
431     {                                                                   \
432       sum0 = ip0->checksum_data_32[0];                                  \
433       sum1 = ip1->checksum_data_32[0];                                  \
434       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]);       \
435       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[1]);       \
436       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]);       \
437       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[2]);       \
438       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]);       \
439       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[3]);       \
440       sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]);       \
441       sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[4]);       \
442     }                                                                   \
443 } while (0)
444
445 always_inline uword
446 ip4_address_is_multicast (const ip4_address_t * a)
447 {
448   return (a->data[0] & 0xf0) == 0xe0;
449 }
450
451 always_inline uword
452 ip4_address_is_global_broadcast (const ip4_address_t * a)
453 {
454   return (a->as_u32) == 0xffffffff;
455 }
456
457 always_inline void
458 ip4_multicast_address_set_for_group (ip4_address_t * a,
459                                      ip_multicast_group_t g)
460 {
461   ASSERT ((u32) g < (1 << 28));
462   a->as_u32 = clib_host_to_net_u32 ((0xe << 28) + g);
463 }
464
465 always_inline void
466 ip4_multicast_ethernet_address (u8 * ethernet_address,
467                                 const ip4_address_t * a)
468 {
469   const u8 *d = a->as_u8;
470
471   ethernet_address[0] = 0x01;
472   ethernet_address[1] = 0x00;
473   ethernet_address[2] = 0x5e;
474   ethernet_address[3] = d[1] & 0x7f;
475   ethernet_address[4] = d[2];
476   ethernet_address[5] = d[3];
477 }
478
479 always_inline void
480 ip4_tcp_reply_x1 (ip4_header_t * ip0, tcp_header_t * tcp0)
481 {
482   u32 src0, dst0;
483
484   src0 = ip0->src_address.data_u32;
485   dst0 = ip0->dst_address.data_u32;
486   ip0->src_address.data_u32 = dst0;
487   ip0->dst_address.data_u32 = src0;
488
489   src0 = tcp0->src;
490   dst0 = tcp0->dst;
491   tcp0->src = dst0;
492   tcp0->dst = src0;
493 }
494
495 always_inline void
496 ip4_tcp_reply_x2 (ip4_header_t * ip0, ip4_header_t * ip1,
497                   tcp_header_t * tcp0, tcp_header_t * tcp1)
498 {
499   u32 src0, dst0, src1, dst1;
500
501   src0 = ip0->src_address.data_u32;
502   src1 = ip1->src_address.data_u32;
503   dst0 = ip0->dst_address.data_u32;
504   dst1 = ip1->dst_address.data_u32;
505   ip0->src_address.data_u32 = dst0;
506   ip1->src_address.data_u32 = dst1;
507   ip0->dst_address.data_u32 = src0;
508   ip1->dst_address.data_u32 = src1;
509
510   src0 = tcp0->src;
511   src1 = tcp1->src;
512   dst0 = tcp0->dst;
513   dst1 = tcp1->dst;
514   tcp0->src = dst0;
515   tcp1->src = dst1;
516   tcp0->dst = src0;
517   tcp1->dst = src1;
518 }
519
520 #endif /* included_ip4_packet_h */
521
522 /*
523  * fd.io coding-style-patch-verification: ON
524  *
525  * Local Variables:
526  * eval: (c-set-style "gnu")
527  * End:
528  */