nat: use SVR
[vpp.git] / src / vnet / ip / ip6_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  * ip6/packet.h: ip6 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_ip6_packet_h
41 #define included_ip6_packet_h
42
43 #include <vnet/tcp/tcp_packet.h>
44 #include <vnet/ip/ip4_packet.h>
45
46 typedef union
47 {
48   u8 as_u8[16];
49   u16 as_u16[8];
50   u32 as_u32[4];
51   u64 as_u64[2];
52   uword as_uword[16 / sizeof (uword)];
53 }
54 ip6_address_t;
55
56 typedef struct
57 {
58   ip6_address_t addr, mask;
59 } ip6_address_and_mask_t;
60
61 /* Packed so that the mhash key doesn't include uninitialized pad bytes */
62 /* *INDENT-OFF* */
63 typedef CLIB_PACKED (struct {
64   /* IP address must be first for ip_interface_address_get_address() to work */
65   ip6_address_t ip6_addr;
66   u32 fib_index;
67 }) ip6_address_fib_t;
68 /* *INDENT-ON* */
69
70 always_inline void
71 ip6_addr_fib_init (ip6_address_fib_t * addr_fib,
72                    const ip6_address_t * address, u32 fib_index)
73 {
74   addr_fib->ip6_addr = *address;
75   addr_fib->fib_index = fib_index;
76 }
77
78 /* Special addresses:
79    unspecified          ::/128
80    loopback             ::1/128
81    global unicast       2000::/3
82    unique local unicast fc00::/7
83    link local unicast   fe80::/10
84    multicast            ff00::/8
85    ietf reserved        everything else. */
86
87 #define foreach_ip6_multicast_address_scope     \
88   _ (loopback, 0x1)                             \
89   _ (link_local, 0x2)                           \
90   _ (admin_local, 0x4)                          \
91   _ (site_local, 0x5)                           \
92   _ (organization_local, 0x8)                   \
93   _ (global, 0xe)
94
95 #define foreach_ip6_multicast_link_local_group_id       \
96   _ (all_hosts, 0x1)                                    \
97   _ (all_routers, 0x2)                                  \
98   _ (rip_routers, 0x9)                                  \
99   _ (eigrp_routers, 0xa)                                \
100   _ (pim_routers, 0xd)                            \
101  _ (mldv2_routers, 0x16)
102
103 typedef enum
104 {
105 #define _(f,n) IP6_MULTICAST_SCOPE_##f = n,
106   foreach_ip6_multicast_address_scope
107 #undef _
108 } ip6_multicast_address_scope_t;
109
110 typedef enum
111 {
112 #define _(f,n) IP6_MULTICAST_GROUP_ID_##f = n,
113   foreach_ip6_multicast_link_local_group_id
114 #undef _
115 } ip6_multicast_link_local_group_id_t;
116
117 always_inline uword
118 ip6_address_is_multicast (const ip6_address_t * a)
119 {
120   return a->as_u8[0] == 0xff;
121 }
122
123 always_inline void
124 ip6_address_copy (ip6_address_t * dst, const ip6_address_t * src)
125 {
126   dst->as_u64[0] = src->as_u64[0];
127   dst->as_u64[1] = src->as_u64[1];
128 }
129
130 always_inline void
131 ip6_set_reserved_multicast_address (ip6_address_t * a,
132                                     ip6_multicast_address_scope_t scope,
133                                     u16 id)
134 {
135   a->as_u64[0] = a->as_u64[1] = 0;
136   a->as_u16[0] = clib_host_to_net_u16 (0xff00 | scope);
137   a->as_u16[7] = clib_host_to_net_u16 (id);
138 }
139
140 always_inline void
141 ip6_set_solicited_node_multicast_address (ip6_address_t * a, u32 id)
142 {
143   /* 0xff02::1:ffXX:XXXX. */
144   a->as_u64[0] = a->as_u64[1] = 0;
145   a->as_u16[0] = clib_host_to_net_u16 (0xff02);
146   a->as_u8[11] = 1;
147   ASSERT ((id >> 24) == 0);
148   id |= 0xff << 24;
149   a->as_u32[3] = clib_host_to_net_u32 (id);
150 }
151
152 always_inline void
153 ip6_multicast_ethernet_address (u8 * ethernet_address, u32 group_id)
154 {
155   ethernet_address[0] = 0x33;
156   ethernet_address[1] = 0x33;
157   ethernet_address[2] = ((group_id >> 24) & 0xff);
158   ethernet_address[3] = ((group_id >> 16) & 0xff);
159   ethernet_address[4] = ((group_id >> 8) & 0xff);
160   ethernet_address[5] = ((group_id >> 0) & 0xff);
161 }
162
163 always_inline uword
164 ip6_address_is_equal (const ip6_address_t * a, const ip6_address_t * b)
165 {
166   int i;
167   for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
168     if (a->as_uword[i] != b->as_uword[i])
169       return 0;
170   return 1;
171 }
172
173 always_inline uword
174 ip6_address_is_equal_masked (const ip6_address_t * a,
175                              const ip6_address_t * b,
176                              const ip6_address_t * mask)
177 {
178   int i;
179   for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
180     {
181       uword a_masked, b_masked;
182       a_masked = a->as_uword[i] & mask->as_uword[i];
183       b_masked = b->as_uword[i] & mask->as_uword[i];
184
185       if (a_masked != b_masked)
186         return 0;
187     }
188   return 1;
189 }
190
191 always_inline void
192 ip6_address_mask (ip6_address_t * a, const ip6_address_t * mask)
193 {
194   int i;
195   for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
196     a->as_uword[i] &= mask->as_uword[i];
197 }
198
199 always_inline void
200 ip6_address_set_zero (ip6_address_t * a)
201 {
202   int i;
203   for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
204     a->as_uword[i] = 0;
205 }
206
207 always_inline void
208 ip6_address_mask_from_width (ip6_address_t * a, u32 width)
209 {
210   int i, byte, bit, bitnum;
211   ASSERT (width <= 128);
212   clib_memset (a, 0, sizeof (a[0]));
213   for (i = 0; i < width; i++)
214     {
215       bitnum = (7 - (i & 7));
216       byte = i / 8;
217       bit = 1 << bitnum;
218       a->as_u8[byte] |= bit;
219     }
220 }
221
222 always_inline uword
223 ip6_address_is_zero (const ip6_address_t * a)
224 {
225   int i;
226   for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
227     if (a->as_uword[i] != 0)
228       return 0;
229   return 1;
230 }
231
232 /* Check for unspecified address ::0 */
233 always_inline uword
234 ip6_address_is_unspecified (const ip6_address_t * a)
235 {
236   return ip6_address_is_zero (a);
237 }
238
239 /* Check for loopback address ::1 */
240 always_inline uword
241 ip6_address_is_loopback (const ip6_address_t * a)
242 {
243   return (a->as_u64[0] == 0 &&
244           a->as_u32[2] == 0 &&
245           a->as_u16[6] == 0 && a->as_u8[14] == 0 && a->as_u8[15] == 1);
246 }
247
248 /* Check for link local unicast fe80::/10. */
249 always_inline uword
250 ip6_address_is_link_local_unicast (const ip6_address_t * a)
251 {
252   return a->as_u8[0] == 0xfe && (a->as_u8[1] & 0xc0) == 0x80;
253 }
254
255 /* Check for unique local unicast fc00::/7. */
256 always_inline uword
257 ip6_address_is_local_unicast (const ip6_address_t * a)
258 {
259   return (a->as_u8[0] & 0xfe) == 0xfc;
260 }
261
262 /* Check for unique global unicast 2000::/3. */
263 always_inline uword
264 ip6_address_is_global_unicast (const ip6_address_t * a)
265 {
266   return (a->as_u8[0] & 0xe0) == 0x20;
267 }
268
269 /* Check for solicited node multicast 0xff02::1:ff00:0/104 */
270 always_inline uword
271 ip6_is_solicited_node_multicast_address (const ip6_address_t * a)
272 {
273   return (a->as_u32[0] == clib_host_to_net_u32 (0xff020000)
274           && a->as_u32[1] == 0
275           && a->as_u32[2] == clib_host_to_net_u32 (1)
276           && a->as_u8[12] == 0xff);
277 }
278
279 always_inline u32
280 ip6_address_hash_to_u32 (const ip6_address_t * a)
281 {
282   return (a->as_u32[0] ^ a->as_u32[1] ^ a->as_u32[2] ^ a->as_u32[3]);
283 }
284
285 always_inline u64
286 ip6_address_hash_to_u64 (const ip6_address_t * a)
287 {
288   return (a->as_u64[0] ^ a->as_u64[1]);
289 }
290
291 typedef struct
292 {
293   /* 4 bit version, 8 bit traffic class and 20 bit flow label. */
294   u32 ip_version_traffic_class_and_flow_label;
295
296   /* Total packet length not including this header (but including
297      any extension headers if present). */
298   u16 payload_length;
299
300   /* Protocol for next header. */
301   u8 protocol;
302
303   /* Hop limit decremented by router at each hop. */
304   u8 hop_limit;
305
306   /* Source and destination address. */
307   ip6_address_t src_address, dst_address;
308 } ip6_header_t;
309
310 always_inline ip_dscp_t
311 ip6_traffic_class (const ip6_header_t * i)
312 {
313   return (i->ip_version_traffic_class_and_flow_label & 0x0FF00000) >> 20;
314 }
315
316 static_always_inline ip_dscp_t
317 ip6_traffic_class_network_order (const ip6_header_t * ip6)
318 {
319   return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
320           & 0x0ff00000) >> 20;
321 }
322
323 static_always_inline ip_dscp_t
324 ip6_dscp_network_order (const ip6_header_t * ip6)
325 {
326   return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
327           & 0x0fc00000) >> 22;
328 }
329
330 static_always_inline ip_ecn_t
331 ip6_ecn_network_order (const ip6_header_t * ip6)
332 {
333   return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
334           & 0x00300000) >> 20;
335 }
336
337 static_always_inline void
338 ip6_set_traffic_class_network_order (ip6_header_t * ip6, ip_dscp_t dscp)
339 {
340   u32 tmp =
341     clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
342   tmp &= 0xf00fffff;
343   tmp |= (dscp << 20);
344   ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
345 }
346
347 static_always_inline void
348 ip6_set_dscp_network_order (ip6_header_t * ip6, ip_dscp_t dscp)
349 {
350   u32 tmp =
351     clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
352   tmp &= 0xf03fffff;
353   tmp |= (dscp << 22);
354   ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
355 }
356
357 static_always_inline void
358 ip6_set_ecn_network_order (ip6_header_t * ip6, ip_ecn_t ecn)
359 {
360   u32 tmp =
361     clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
362   tmp &= 0xffcfffff;
363   tmp |= (ecn << 20);
364   ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
365 }
366
367 always_inline void *
368 ip6_next_header (ip6_header_t * i)
369 {
370   return (void *) (i + 1);
371 }
372
373 always_inline void
374 ip6_copy_header (ip6_header_t * dst, const ip6_header_t * src)
375 {
376   dst->ip_version_traffic_class_and_flow_label =
377     src->ip_version_traffic_class_and_flow_label;
378   dst->payload_length = src->payload_length;
379   dst->protocol = src->protocol;
380   dst->hop_limit = src->hop_limit;
381
382   dst->src_address.as_uword[0] = src->src_address.as_uword[0];
383   dst->src_address.as_uword[1] = src->src_address.as_uword[1];
384   dst->dst_address.as_uword[0] = src->dst_address.as_uword[0];
385   dst->dst_address.as_uword[1] = src->dst_address.as_uword[1];
386 }
387
388 always_inline void
389 ip6_tcp_reply_x1 (ip6_header_t * ip0, tcp_header_t * tcp0)
390 {
391   {
392     ip6_address_t src0, dst0;
393
394     src0 = ip0->src_address;
395     dst0 = ip0->dst_address;
396     ip0->src_address = dst0;
397     ip0->dst_address = src0;
398   }
399
400   {
401     u16 src0, dst0;
402
403     src0 = tcp0->src;
404     dst0 = tcp0->dst;
405     tcp0->src = dst0;
406     tcp0->dst = src0;
407   }
408 }
409
410 always_inline void
411 ip6_tcp_reply_x2 (ip6_header_t * ip0, ip6_header_t * ip1,
412                   tcp_header_t * tcp0, tcp_header_t * tcp1)
413 {
414   {
415     ip6_address_t src0, dst0, src1, dst1;
416
417     src0 = ip0->src_address;
418     src1 = ip1->src_address;
419     dst0 = ip0->dst_address;
420     dst1 = ip1->dst_address;
421     ip0->src_address = dst0;
422     ip1->src_address = dst1;
423     ip0->dst_address = src0;
424     ip1->dst_address = src1;
425   }
426
427   {
428     u16 src0, dst0, src1, dst1;
429
430     src0 = tcp0->src;
431     src1 = tcp1->src;
432     dst0 = tcp0->dst;
433     dst1 = tcp1->dst;
434     tcp0->src = dst0;
435     tcp1->src = dst1;
436     tcp0->dst = src0;
437     tcp1->dst = src1;
438   }
439 }
440
441
442 /* *INDENT-OFF* */
443 typedef CLIB_PACKED (struct {
444   u8 data;
445 }) ip6_pad1_option_t;
446 /* *INDENT-ON* */
447
448 /* *INDENT-OFF* */
449 typedef CLIB_PACKED (struct {
450   u8 type;
451   u8 len;
452   u8 data[0];
453 }) ip6_padN_option_t;
454 /* *INDENT-ON* */
455
456 /* *INDENT-OFF* */
457 typedef CLIB_PACKED (struct {
458 #define IP6_MLDP_ALERT_TYPE  0x5
459   u8 type;
460   u8 len;
461   u16 value;
462 }) ip6_router_alert_option_t;
463 /* *INDENT-ON* */
464
465 /* *INDENT-OFF* */
466 typedef CLIB_PACKED (struct {
467   u8 next_hdr;
468   /* Length of this header plus option data in 8 byte units. */
469   u8 n_data_u64s;
470 }) ip6_ext_header_t;
471 /* *INDENT-ON* */
472
473 #define foreach_ext_hdr_type \
474   _(IP6_HOP_BY_HOP_OPTIONS) \
475   _(IPV6_ROUTE) \
476   _(IPV6_FRAGMENTATION) \
477   _(IPSEC_ESP) \
478   _(IPSEC_AH) \
479   _(IP6_DESTINATION_OPTIONS) \
480   _(MOBILITY) \
481   _(HIP) \
482   _(SHIM6)
483
484 always_inline u8
485 ip6_ext_hdr (u8 nexthdr)
486 {
487 #ifdef CLIB_HAVE_VEC128
488   static const u8x16 ext_hdr_types = {
489 #define _(x) IP_PROTOCOL_##x,
490     foreach_ext_hdr_type
491 #undef _
492   };
493
494   return !u8x16_is_all_zero (ext_hdr_types == u8x16_splat (nexthdr));
495 #else
496   /*
497    * find out if nexthdr is an extension header or a protocol
498    */
499   return 0
500 #define _(x) || (nexthdr == IP_PROTOCOL_##x)
501     foreach_ext_hdr_type;
502 #undef _
503 #endif
504 }
505
506 #define ip6_ext_header_len(p)  ((((ip6_ext_header_t *)(p))->n_data_u64s+1) << 3)
507 #define ip6_ext_authhdr_len(p) ((((ip6_ext_header_t *)(p))->n_data_u64s+2) << 2)
508
509 always_inline void *
510 ip6_ext_next_header (ip6_ext_header_t * ext_hdr)
511 {
512   return (void *) ((u8 *) ext_hdr + ip6_ext_header_len (ext_hdr));
513 }
514
515 always_inline int
516 vlib_object_within_buffer_data (vlib_main_t * vm, vlib_buffer_t * b,
517                                 void *obj, size_t len)
518 {
519   u8 *o = obj;
520   if (o < b->data ||
521       o + len > b->data + vlib_buffer_get_default_data_size (vm))
522     return 0;
523   return 1;
524 }
525
526 /*
527  * find ipv6 extension header within ipv6 header within buffer b
528  *
529  * @param vm
530  * @param b buffer to limit search to
531  * @param ip6_header ipv6 header
532  * @param header_type extension header type to search for
533  * @param[out] prev_ext_header address of header preceding found header
534  */
535 always_inline void *
536 ip6_ext_header_find (vlib_main_t * vm, vlib_buffer_t * b,
537                      ip6_header_t * ip6_header, u8 header_type,
538                      ip6_ext_header_t ** prev_ext_header)
539 {
540   ip6_ext_header_t *prev = NULL;
541   ip6_ext_header_t *result = NULL;
542   if ((ip6_header)->protocol == header_type)
543     {
544       result = (void *) (ip6_header + 1);
545       if (!vlib_object_within_buffer_data (vm, b, result,
546                                            ip6_ext_header_len (result)))
547         {
548           result = NULL;
549         }
550     }
551   else
552     {
553       result = NULL;
554       prev = (void *) (ip6_header + 1);
555       while (ip6_ext_hdr (prev->next_hdr) && prev->next_hdr != header_type)
556         {
557           prev = ip6_ext_next_header (prev);
558           if (!vlib_object_within_buffer_data (vm, b, prev,
559                                                ip6_ext_header_len (prev)))
560             {
561               prev = NULL;
562               break;
563             }
564         }
565       if (prev && (prev->next_hdr == header_type))
566         {
567           result = ip6_ext_next_header (prev);
568           if (!vlib_object_within_buffer_data (vm, b, result,
569                                                ip6_ext_header_len (result)))
570             {
571               result = NULL;
572             }
573         }
574     }
575   if (prev_ext_header)
576     {
577       *prev_ext_header = prev;
578     }
579   return result;
580 }
581
582 /*
583  * walk extension headers, looking for a specific extension header and last
584  * extension header, calculating length of all extension headers
585  *
586  * @param vm
587  * @param b buffer to limit search to
588  * @param ip6_header ipv6 header
589  * @param find_hdr extension header to look for (ignored if ext_hdr is NULL)
590  * @param length[out] length of all extension headers
591  * @param ext_hdr[out] extension header of type find_hdr (may be NULL)
592  * @param last_ext_hdr[out] last extension header (may be NULL)
593  *
594  * @return 0 on success, -1 on failure (ext headers crossing buffer boundary)
595  */
596 always_inline int
597 ip6_walk_ext_hdr (vlib_main_t * vm, vlib_buffer_t * b,
598                   const ip6_header_t * ip6_header, u8 find_hdr, u32 * length,
599                   ip6_ext_header_t ** ext_hdr,
600                   ip6_ext_header_t ** last_ext_hdr)
601 {
602   if (!ip6_ext_hdr (ip6_header->protocol))
603     {
604       *length = 0;
605       *ext_hdr = NULL;
606       *last_ext_hdr = NULL;
607       return 0;
608     }
609   *length = 0;
610   ip6_ext_header_t *h = (void *) (ip6_header + 1);
611   if (!vlib_object_within_buffer_data (vm, b, h, ip6_ext_header_len (h)))
612     {
613       return -1;
614     }
615   *length += ip6_ext_header_len (h);
616   *last_ext_hdr = h;
617   *ext_hdr = NULL;
618   if (ip6_header->protocol == find_hdr)
619     {
620       *ext_hdr = h;
621     }
622   while (ip6_ext_hdr (h->next_hdr))
623     {
624       if (h->next_hdr == find_hdr)
625         {
626           h = ip6_ext_next_header (h);
627           *ext_hdr = h;
628         }
629       else
630         {
631           h = ip6_ext_next_header (h);
632         }
633       if (!vlib_object_within_buffer_data (vm, b, h, ip6_ext_header_len (h)))
634         {
635           return -1;
636         }
637       *length += ip6_ext_header_len (h);
638       *last_ext_hdr = h;
639     }
640   return 0;
641 }
642
643 /* *INDENT-OFF* */
644 typedef CLIB_PACKED (struct {
645   u8 next_hdr;
646   /* Length of this header plus option data in 8 byte units. */
647   u8 n_data_u64s;
648   u8 data[0];
649 }) ip6_hop_by_hop_ext_t;
650 /* *INDENT-ON* */
651
652 /* *INDENT-OFF* */
653 typedef CLIB_PACKED (struct {
654   u8 next_hdr;
655   u8 rsv;
656   u16 fragment_offset_and_more;
657   u32 identification;
658 }) ip6_frag_hdr_t;
659 /* *INDENT-ON* */
660
661 #define ip6_frag_hdr_offset(hdr) \
662   (clib_net_to_host_u16((hdr)->fragment_offset_and_more) >> 3)
663
664 #define ip6_frag_hdr_offset_bytes(hdr) \
665   (8 * ip6_frag_hdr_offset(hdr))
666
667 #define ip6_frag_hdr_more(hdr) \
668   (clib_net_to_host_u16((hdr)->fragment_offset_and_more) & 0x1)
669
670 #define ip6_frag_hdr_offset_and_more(offset, more) \
671   clib_host_to_net_u16(((offset) << 3) + !!(more))
672
673 #endif /* included_ip6_packet_h */
674
675 /*
676  * fd.io coding-style-patch-verification: ON
677  *
678  * Local Variables:
679  * eval: (c-set-style "gnu")
680  * End:
681  */