FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
map.c
Go to the documentation of this file.
1 /*
2  * map.c : MAP support
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/fib/ip6_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/map/map_dpo.h>
22 
23 #include "map.h"
24 
25 #ifdef __SSE4_2__
26 static inline u32
27 crc_u32 (u32 data, u32 value)
28 {
29  __asm__ volatile ("crc32l %[data], %[value];":[value] "+r" (value):[data]
30  "rm" (data));
31  return value;
32 }
33 #else
34 #include <vppinfra/xxhash.h>
35 
36 static inline u32
37 crc_u32 (u32 data, u32 value)
38 {
39  u64 tmp = ((u64) data << 32) | (u64) value;
40  return (u32) clib_xxhash (tmp);
41 }
42 #endif
43 
44 /*
45  * This code supports the following MAP modes:
46  *
47  * Algorithmic Shared IPv4 address (ea_bits_len > 0):
48  * ea_bits_len + ip4_prefix > 32
49  * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
50  * Algorithmic Full IPv4 address (ea_bits_len > 0):
51  * ea_bits_len + ip4_prefix = 32
52  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
53  * Algorithmic IPv4 prefix (ea_bits_len > 0):
54  * ea_bits_len + ip4_prefix < 32
55  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
56  *
57  * Independent Shared IPv4 address (ea_bits_len = 0):
58  * ip4_prefix = 32
59  * psid_length > 0
60  * Rule IPv6 address = 128, Rule PSID Set
61  * Independent Full IPv4 address (ea_bits_len = 0):
62  * ip4_prefix = 32
63  * psid_length = 0, ip6_prefix = 128
64  * Independent IPv4 prefix (ea_bits_len = 0):
65  * ip4_prefix < 32
66  * psid_length = 0, ip6_prefix = 128
67  *
68  */
69 
70 /*
71  * This code supports MAP-T:
72  *
73  * With DMR prefix length equal to 96.
74  *
75  */
76 
77 
78 i32
79 ip4_get_port (ip4_header_t * ip, map_dir_e dir, u16 buffer_len)
80 {
81  //TODO: use buffer length
82  if (ip->ip_version_and_header_length != 0x45 ||
84  return -1;
85 
86  if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) ||
87  (ip->protocol == IP_PROTOCOL_UDP)))
88  {
89  udp_header_t *udp = (void *) (ip + 1);
90  return (dir == MAP_SENDER) ? udp->src_port : udp->dst_port;
91  }
92  else if (ip->protocol == IP_PROTOCOL_ICMP)
93  {
94  icmp46_header_t *icmp = (void *) (ip + 1);
95  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
96  {
97  return *((u16 *) (icmp + 1));
98  }
99  else if (clib_net_to_host_u16 (ip->length) >= 64)
100  {
101  ip = (ip4_header_t *) (icmp + 2);
102  if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) ||
103  (ip->protocol == IP_PROTOCOL_UDP)))
104  {
105  udp_header_t *udp = (void *) (ip + 1);
106  return (dir == MAP_SENDER) ? udp->dst_port : udp->src_port;
107  }
108  else if (ip->protocol == IP_PROTOCOL_ICMP)
109  {
110  icmp46_header_t *icmp = (void *) (ip + 1);
111  if (icmp->type == ICMP4_echo_request ||
112  icmp->type == ICMP4_echo_reply)
113  {
114  return *((u16 *) (icmp + 1));
115  }
116  }
117  }
118  }
119  return -1;
120 }
121 
122 i32
123 ip6_get_port (ip6_header_t * ip6, map_dir_e dir, u16 buffer_len)
124 {
125  u8 l4_protocol;
126  u16 l4_offset;
127  u16 frag_offset;
128  u8 *l4;
129 
130  if (ip6_parse (ip6, buffer_len, &l4_protocol, &l4_offset, &frag_offset))
131  return -1;
132 
133  //TODO: Use buffer length
134 
135  if (frag_offset &&
136  ip6_frag_hdr_offset (((ip6_frag_hdr_t *)
137  u8_ptr_add (ip6, frag_offset))))
138  return -1; //Can't deal with non-first fragment for now
139 
140  l4 = u8_ptr_add (ip6, l4_offset);
141  if (l4_protocol == IP_PROTOCOL_TCP || l4_protocol == IP_PROTOCOL_UDP)
142  {
143  return (dir ==
144  MAP_SENDER) ? ((udp_header_t *) (l4))->src_port : ((udp_header_t
145  *)
146  (l4))->dst_port;
147  }
148  else if (l4_protocol == IP_PROTOCOL_ICMP6)
149  {
150  icmp46_header_t *icmp = (icmp46_header_t *) (l4);
151  if (icmp->type == ICMP6_echo_request)
152  {
153  return (dir == MAP_SENDER) ? ((u16 *) (icmp))[2] : -1;
154  }
155  else if (icmp->type == ICMP6_echo_reply)
156  {
157  return (dir == MAP_SENDER) ? -1 : ((u16 *) (icmp))[2];
158  }
159  }
160  return -1;
161 }
162 
163 
164 int
166  u8 ip4_prefix_len,
167  ip6_address_t * ip6_prefix,
168  u8 ip6_prefix_len,
169  ip6_address_t * ip6_src,
170  u8 ip6_src_len,
171  u8 ea_bits_len,
172  u8 psid_offset,
173  u8 psid_length, u32 * map_domain_index, u16 mtu, u8 flags)
174 {
175  u8 suffix_len, suffix_shift;
176  map_main_t *mm = &map_main;
177  dpo_id_t dpo_v4 = DPO_INVALID;
178  dpo_id_t dpo_v6 = DPO_INVALID;
179  fib_node_index_t fei;
180  map_domain_t *d;
181 
182  /* Sanity check on the src prefix length */
183  if (flags & MAP_DOMAIN_TRANSLATION)
184  {
185  if (ip6_src_len != 96)
186  {
187  clib_warning ("MAP-T only supports ip6_src_len = 96 for now.");
188  return -1;
189  }
190  }
191  else
192  {
193  if (ip6_src_len != 128)
194  {
196  ("MAP-E requires a BR address, not a prefix (ip6_src_len should "
197  "be 128).");
198  return -1;
199  }
200  }
201 
202  /* How many, and which bits to grab from the IPv4 DA */
203  if (ip4_prefix_len + ea_bits_len < 32)
204  {
205  flags |= MAP_DOMAIN_PREFIX;
206  suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
207  suffix_len = ea_bits_len;
208  }
209  else
210  {
211  suffix_shift = 0;
212  suffix_len = 32 - ip4_prefix_len;
213  }
214 
215  /* EA bits must be within the first 64 bits */
216  if (ea_bits_len > 0 && ((ip6_prefix_len + ea_bits_len) > 64 ||
217  ip6_prefix_len + suffix_len + psid_length > 64))
218  {
220  ("Embedded Address bits must be within the first 64 bits of "
221  "the IPv6 prefix");
222  return -1;
223  }
224 
225  /* Get domain index */
227  memset (d, 0, sizeof (*d));
228  *map_domain_index = d - mm->domains;
229 
230  /* Init domain struct */
231  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
232  d->ip4_prefix_len = ip4_prefix_len;
233  d->ip6_prefix = *ip6_prefix;
234  d->ip6_prefix_len = ip6_prefix_len;
235  d->ip6_src = *ip6_src;
236  d->ip6_src_len = ip6_src_len;
237  d->ea_bits_len = ea_bits_len;
238  d->psid_offset = psid_offset;
239  d->psid_length = psid_length;
240  d->mtu = mtu;
241  d->flags = flags;
242  d->suffix_shift = suffix_shift;
243  d->suffix_mask = (1 << suffix_len) - 1;
244 
245  d->psid_shift = 16 - psid_length - psid_offset;
246  d->psid_mask = (1 << d->psid_length) - 1;
247  d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
248 
249  /* MAP data-plane object */
250  if (d->flags & MAP_DOMAIN_TRANSLATION)
251  map_t_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
252  else
253  map_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
254 
255  /* Create ip4 route */
256  fib_prefix_t pfx = {
258  .fp_len = d->ip4_prefix_len,
259  .fp_addr = {
260  .ip4 = d->ip4_prefix,
261  }
262  ,
263  };
266  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
267  dpo_reset (&dpo_v4);
268 
269  /*
270  * Multiple MAP domains may share same source IPv6 TEP.
271  * In this case the route will exist and be MAP sourced.
272  * Find the adj (if any) already contributed and modify it
273  */
274  fib_prefix_t pfx6 = {
276  .fp_len = d->ip6_src_len,
277  .fp_addr = {
278  .ip6 = d->ip6_src,
279  }
280  ,
281  };
282  fei = fib_table_lookup_exact_match (0, &pfx6);
283 
284  if (FIB_NODE_INDEX_INVALID != fei)
285  {
286  dpo_id_t dpo = DPO_INVALID;
287 
289  {
290  /*
291  * modify the existing MAP to indicate it's shared
292  * skip to route add.
293  */
294  const dpo_id_t *md_dpo;
295  map_dpo_t *md;
296 
298 
299  md_dpo = load_balance_get_bucket (dpo.dpoi_index, 0);
300  md = map_dpo_get (md_dpo->dpoi_index);
301 
302  md->md_domain = ~0;
303  dpo_copy (&dpo_v6, md_dpo);
304  dpo_reset (&dpo);
305 
306  goto route_add;
307  }
308  }
309 
310  if (d->flags & MAP_DOMAIN_TRANSLATION)
311  map_t_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
312  else
313  map_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
314 
315 route_add:
316  /*
317  * Create ip6 route. This is a reference counted add. If the prefix
318  * already exists and is MAP sourced, it is now MAP source n+1 times
319  * and will need to be removed n+1 times.
320  */
323  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v6);
324  dpo_reset (&dpo_v6);
325 
326  /* Validate packet/byte counters */
328  int i;
329  for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
330  {
332  *map_domain_index);
334  *map_domain_index);
335  }
336  for (i = 0; i < vec_len (mm->domain_counters); i++)
337  {
339  *map_domain_index);
340  vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
341  }
343 
344  return 0;
345 }
346 
347 /*
348  * map_delete_domain
349  */
350 int
351 map_delete_domain (u32 map_domain_index)
352 {
353  map_main_t *mm = &map_main;
354  map_domain_t *d;
355 
356  if (pool_is_free_index (mm->domains, map_domain_index))
357  {
358  clib_warning ("MAP domain delete: domain does not exist: %d",
359  map_domain_index);
360  return -1;
361  }
362 
363  d = pool_elt_at_index (mm->domains, map_domain_index);
364 
365  fib_prefix_t pfx = {
367  .fp_len = d->ip4_prefix_len,
368  .fp_addr = {
369  .ip4 = d->ip4_prefix,
370  }
371  ,
372  };
374 
375  fib_prefix_t pfx6 = {
377  .fp_len = d->ip6_src_len,
378  .fp_addr = {
379  .ip6 = d->ip6_src,
380  }
381  ,
382  };
384 
385  /* Deleting rules */
386  if (d->rules)
387  clib_mem_free (d->rules);
388 
389  pool_put (mm->domains, d);
390 
391  return 0;
392 }
393 
394 int
395 map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
396  u8 is_add)
397 {
398  map_domain_t *d;
399  map_main_t *mm = &map_main;
400 
401  if (pool_is_free_index (mm->domains, map_domain_index))
402  {
403  clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
404  return -1;
405  }
406  d = pool_elt_at_index (mm->domains, map_domain_index);
407 
408  /* Rules are only used in 1:1 independent case */
409  if (d->ea_bits_len > 0)
410  return (-1);
411 
412  if (!d->rules)
413  {
414  u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
416  if (!d->rules)
417  return -1;
418  memset (d->rules, 0, l);
419  }
420 
421  if (psid >= (0x1 << d->psid_length))
422  {
423  clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
424  0x1 << d->psid_length);
425  return -1;
426  }
427 
428  if (is_add)
429  {
430  d->rules[psid] = *tep;
431  }
432  else
433  {
434  memset (&d->rules[psid], 0, sizeof (ip6_address_t));
435  }
436  return 0;
437 }
438 
439 #ifdef MAP_SKIP_IP6_LOOKUP
440 static void
442 {
443  map_main_t *mm = &map_main;
444  ip6_main_t *im6 = &ip6_main;
445 
446  if (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0)
447  {
448  // FIXME NOT an ADJ
449  mm->adj6_index = ip6_fib_table_fwding_lookup (im6, 0, ip6);
450  clib_warning ("FIB lookup results in: %u", mm->adj6_index);
451  }
452  if (ip4->as_u32 != 0)
453  {
454  // FIXME NOT an ADJ
455  mm->adj4_index = ip4_fib_table_lookup_lb (0, ip4);
456  clib_warning ("FIB lookup results in: %u", mm->adj4_index);
457  }
458 }
459 #endif
460 
461 static clib_error_t *
463  unformat_input_t * input,
464  vlib_cli_command_t * cmd)
465 {
466  unformat_input_t _line_input, *line_input = &_line_input;
467  map_main_t *mm = &map_main;
468  /* Get a line of input. */
469  if (!unformat_user (input, unformat_line_input, line_input))
470  return 0;
471 
472  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
473  {
474  if (unformat (line_input, "off"))
475  mm->sec_check = false;
476  else if (unformat (line_input, "on"))
477  mm->sec_check = true;
478  else
479  return clib_error_return (0, "unknown input `%U'",
480  format_unformat_error, input);
481  }
482  unformat_free (line_input);
483  return 0;
484 }
485 
486 static clib_error_t *
488  unformat_input_t * input,
489  vlib_cli_command_t * cmd)
490 {
491  unformat_input_t _line_input, *line_input = &_line_input;
492  map_main_t *mm = &map_main;
493  /* Get a line of input. */
494  if (!unformat_user (input, unformat_line_input, line_input))
495  return 0;
496 
497  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
498  {
499  if (unformat (line_input, "off"))
500  mm->sec_check_frag = false;
501  else if (unformat (line_input, "on"))
502  mm->sec_check_frag = true;
503  else
504  return clib_error_return (0, "unknown input `%U'",
505  format_unformat_error, input);
506  }
507  unformat_free (line_input);
508  return 0;
509 }
510 
511 static clib_error_t *
513  unformat_input_t * input, vlib_cli_command_t * cmd)
514 {
515  unformat_input_t _line_input, *line_input = &_line_input;
516  ip4_address_t ip4_prefix;
517  ip6_address_t ip6_prefix;
518  ip6_address_t ip6_src;
519  u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
520  u32 num_m_args = 0;
521  /* Optional arguments */
522  u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
523  u32 mtu = 0;
524  u8 flags = 0;
525  ip6_src_len = 128;
526 
527  /* Get a line of input. */
528  if (!unformat_user (input, unformat_line_input, line_input))
529  return 0;
530 
531  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
532  {
533  if (unformat
534  (line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix,
535  &ip4_prefix_len))
536  num_m_args++;
537  else
538  if (unformat
539  (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix,
540  &ip6_prefix_len))
541  num_m_args++;
542  else
543  if (unformat
544  (line_input, "ip6-src %U/%d", unformat_ip6_address, &ip6_src,
545  &ip6_src_len))
546  num_m_args++;
547  else
548  if (unformat
549  (line_input, "ip6-src %U", unformat_ip6_address, &ip6_src))
550  num_m_args++;
551  else if (unformat (line_input, "ea-bits-len %d", &ea_bits_len))
552  num_m_args++;
553  else if (unformat (line_input, "psid-offset %d", &psid_offset))
554  num_m_args++;
555  else if (unformat (line_input, "psid-len %d", &psid_length))
556  num_m_args++;
557  else if (unformat (line_input, "mtu %d", &mtu))
558  num_m_args++;
559  else if (unformat (line_input, "map-t"))
560  flags |= MAP_DOMAIN_TRANSLATION;
561  else
562  return clib_error_return (0, "unknown input `%U'",
563  format_unformat_error, input);
564  }
565  unformat_free (line_input);
566 
567  if (num_m_args < 3)
568  return clib_error_return (0, "mandatory argument(s) missing");
569 
570  map_create_domain (&ip4_prefix, ip4_prefix_len,
571  &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
572  ea_bits_len, psid_offset, psid_length, &map_domain_index,
573  mtu, flags);
574 
575  return 0;
576 }
577 
578 static clib_error_t *
580  unformat_input_t * input, vlib_cli_command_t * cmd)
581 {
582  unformat_input_t _line_input, *line_input = &_line_input;
583  u32 num_m_args = 0;
584  u32 map_domain_index;
585 
586  /* Get a line of input. */
587  if (!unformat_user (input, unformat_line_input, line_input))
588  return 0;
589 
590  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
591  {
592  if (unformat (line_input, "index %d", &map_domain_index))
593  num_m_args++;
594  else
595  return clib_error_return (0, "unknown input `%U'",
596  format_unformat_error, input);
597  }
598  unformat_free (line_input);
599 
600  if (num_m_args != 1)
601  return clib_error_return (0, "mandatory argument(s) missing");
602 
603  map_delete_domain (map_domain_index);
604 
605  return 0;
606 }
607 
608 static clib_error_t *
610  unformat_input_t * input, vlib_cli_command_t * cmd)
611 {
612  unformat_input_t _line_input, *line_input = &_line_input;
613  ip6_address_t tep;
614  u32 num_m_args = 0;
615  u32 psid = 0, map_domain_index;
616 
617  /* Get a line of input. */
618  if (!unformat_user (input, unformat_line_input, line_input))
619  return 0;
620 
621  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
622  {
623  if (unformat (line_input, "index %d", &map_domain_index))
624  num_m_args++;
625  else if (unformat (line_input, "psid %d", &psid))
626  num_m_args++;
627  else
628  if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
629  num_m_args++;
630  else
631  return clib_error_return (0, "unknown input `%U'",
632  format_unformat_error, input);
633  }
634  unformat_free (line_input);
635 
636  if (num_m_args != 3)
637  return clib_error_return (0, "mandatory argument(s) missing");
638 
639  if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
640  {
641  return clib_error_return (0, "Failing to add Mapping Rule");
642  }
643  return 0;
644 }
645 
646 #if MAP_SKIP_IP6_LOOKUP
647 static clib_error_t *
649  unformat_input_t * input,
650  vlib_cli_command_t * cmd)
651 {
652  unformat_input_t _line_input, *line_input = &_line_input;
653  ip4_address_t ip4nh;
654  ip6_address_t ip6nh;
655  map_main_t *mm = &map_main;
656 
657  memset (&ip4nh, 0, sizeof (ip4nh));
658  memset (&ip6nh, 0, sizeof (ip6nh));
659 
660  /* Get a line of input. */
661  if (!unformat_user (input, unformat_line_input, line_input))
662  return 0;
663 
664  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
665  {
666  if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
667  mm->preresolve_ip4 = ip4nh;
668  else
669  if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
670  mm->preresolve_ip6 = ip6nh;
671  else
672  return clib_error_return (0, "unknown input `%U'",
673  format_unformat_error, input);
674  }
675  unformat_free (line_input);
676 
677  map_pre_resolve (&ip4nh, &ip6nh);
678 
679  return 0;
680 }
681 #endif
682 
683 static clib_error_t *
685  unformat_input_t * input,
686  vlib_cli_command_t * cmd)
687 {
688  unformat_input_t _line_input, *line_input = &_line_input;
689  ip4_address_t icmp_src_address;
690  map_main_t *mm = &map_main;
691 
692  mm->icmp4_src_address.as_u32 = 0;
693 
694  /* Get a line of input. */
695  if (!unformat_user (input, unformat_line_input, line_input))
696  return 0;
697 
698  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
699  {
700  if (unformat
701  (line_input, "%U", unformat_ip4_address, &icmp_src_address))
702  mm->icmp4_src_address = icmp_src_address;
703  else
704  return clib_error_return (0, "unknown input `%U'",
705  format_unformat_error, input);
706  }
707  unformat_free (line_input);
708 
709  return 0;
710 }
711 
712 static clib_error_t *
714  unformat_input_t * input,
715  vlib_cli_command_t * cmd)
716 {
717  unformat_input_t _line_input, *line_input = &_line_input;
718  map_main_t *mm = &map_main;
719  int num_m_args = 0;
720 
721  /* Get a line of input. */
722  if (!unformat_user (input, unformat_line_input, line_input))
723  return 0;
724 
725  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
726  {
727  num_m_args++;
728  if (unformat (line_input, "on"))
729  mm->icmp6_enabled = true;
730  else if (unformat (line_input, "off"))
731  mm->icmp6_enabled = false;
732  else
733  return clib_error_return (0, "unknown input `%U'",
734  format_unformat_error, input);
735  }
736  unformat_free (line_input);
737 
738 
739  if (num_m_args != 1)
740  return clib_error_return (0, "mandatory argument(s) missing");
741 
742  return 0;
743 }
744 
745 static clib_error_t *
747  unformat_input_t * input, vlib_cli_command_t * cmd)
748 {
749  unformat_input_t _line_input, *line_input = &_line_input;
750  map_main_t *mm = &map_main;
751 
752  /* Get a line of input. */
753  if (!unformat_user (input, unformat_line_input, line_input))
754  return 0;
755 
756  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
757  {
758  if (unformat (line_input, "inner"))
759  mm->frag_inner = true;
760  else if (unformat (line_input, "outer"))
761  mm->frag_inner = false;
762  else
763  return clib_error_return (0, "unknown input `%U'",
764  format_unformat_error, input);
765  }
766  unformat_free (line_input);
767 
768  return 0;
769 }
770 
771 static clib_error_t *
773  unformat_input_t * input,
774  vlib_cli_command_t * cmd)
775 {
776  unformat_input_t _line_input, *line_input = &_line_input;
777  map_main_t *mm = &map_main;
778 
779  /* Get a line of input. */
780  if (!unformat_user (input, unformat_line_input, line_input))
781  return 0;
782 
783  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
784  {
785  if (unformat (line_input, "on"))
786  mm->frag_ignore_df = true;
787  else if (unformat (line_input, "off"))
788  mm->frag_ignore_df = false;
789  else
790  return clib_error_return (0, "unknown input `%U'",
791  format_unformat_error, input);
792  }
793  unformat_free (line_input);
794 
795  return 0;
796 }
797 
798 static clib_error_t *
800  unformat_input_t * input,
801  vlib_cli_command_t * cmd)
802 {
803  unformat_input_t _line_input, *line_input = &_line_input;
804  map_main_t *mm = &map_main;
805  u32 tc = 0;
806 
807  mm->tc_copy = false;
808 
809  /* Get a line of input. */
810  if (!unformat_user (input, unformat_line_input, line_input))
811  return 0;
812 
813  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
814  {
815  if (unformat (line_input, "copy"))
816  mm->tc_copy = true;
817  else if (unformat (line_input, "%x", &tc))
818  mm->tc = tc & 0xff;
819  else
820  return clib_error_return (0, "unknown input `%U'",
821  format_unformat_error, input);
822  }
823  unformat_free (line_input);
824 
825  return 0;
826 }
827 
828 static u8 *
829 format_map_domain (u8 * s, va_list * args)
830 {
831  map_domain_t *d = va_arg (*args, map_domain_t *);
832  bool counters = va_arg (*args, int);
833  map_main_t *mm = &map_main;
834  ip6_address_t ip6_prefix;
835 
836  if (d->rules)
837  memset (&ip6_prefix, 0, sizeof (ip6_prefix));
838  else
839  ip6_prefix = d->ip6_prefix;
840 
841  s = format (s,
842  "[%d] ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d ea_bits_len %d psid-offset %d psid-len %d mtu %d %s",
843  d - mm->domains,
845  format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
847  d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
848  (d->flags & MAP_DOMAIN_TRANSLATION) ? "map-t" : "");
849 
850  if (counters)
851  {
855  d - mm->domains, &v);
856  s = format (s, " TX: %lld/%lld", v.packets, v.bytes);
858  d - mm->domains, &v);
859  s = format (s, " RX: %lld/%lld", v.packets, v.bytes);
861  }
862  s = format (s, "\n");
863 
864  if (d->rules)
865  {
866  int i;
867  ip6_address_t dst;
868  for (i = 0; i < (0x1 << d->psid_length); i++)
869  {
870  dst = d->rules[i];
871  if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
872  continue;
873  s = format (s,
874  " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
875  &dst);
876  }
877  }
878  return s;
879 }
880 
881 static u8 *
882 format_map_ip4_reass (u8 * s, va_list * args)
883 {
884  map_main_t *mm = &map_main;
885  map_ip4_reass_t *r = va_arg (*args, map_ip4_reass_t *);
886  map_ip4_reass_key_t *k = &r->key;
887  f64 now = vlib_time_now (mm->vlib_main);
888  f64 lifetime = (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000);
889  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
890  s = format (s,
891  "ip4-reass src=%U dst=%U protocol=%d identifier=%d port=%d lifetime=%.3lf\n",
892  format_ip4_address, &k->src.as_u8, format_ip4_address,
893  &k->dst.as_u8, k->protocol,
894  clib_net_to_host_u16 (k->fragment_id),
895  (r->port >= 0) ? clib_net_to_host_u16 (r->port) : -1, dt);
896  return s;
897 }
898 
899 static u8 *
900 format_map_ip6_reass (u8 * s, va_list * args)
901 {
902  map_main_t *mm = &map_main;
903  map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
904  map_ip6_reass_key_t *k = &r->key;
905  f64 now = vlib_time_now (mm->vlib_main);
906  f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
907  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
908  s = format (s,
909  "ip6-reass src=%U dst=%U protocol=%d identifier=%d lifetime=%.3lf\n",
910  format_ip6_address, &k->src.as_u8, format_ip6_address,
911  &k->dst.as_u8, k->protocol,
912  clib_net_to_host_u32 (k->fragment_id), dt);
913  return s;
914 }
915 
916 static clib_error_t *
918  vlib_cli_command_t * cmd)
919 {
920  unformat_input_t _line_input, *line_input = &_line_input;
921  map_main_t *mm = &map_main;
922  map_domain_t *d;
923  bool counters = false;
924  u32 map_domain_index = ~0;
925 
926  /* Get a line of input. */
927  if (!unformat_user (input, unformat_line_input, line_input))
928  return 0;
929 
930  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
931  {
932  if (unformat (line_input, "counters"))
933  counters = true;
934  else if (unformat (line_input, "index %d", &map_domain_index))
935  ;
936  else
937  return clib_error_return (0, "unknown input `%U'",
938  format_unformat_error, input);
939  }
940  unformat_free (line_input);
941 
942  if (pool_elts (mm->domains) == 0)
943  vlib_cli_output (vm, "No MAP domains are configured...");
944 
945  if (map_domain_index == ~0)
946  {
947  /* *INDENT-OFF* */
948  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
949  /* *INDENT-ON* */
950  }
951  else
952  {
953  if (pool_is_free_index (mm->domains, map_domain_index))
954  {
955  return clib_error_return (0, "MAP domain does not exists %d",
956  map_domain_index);
957  }
958 
959  d = pool_elt_at_index (mm->domains, map_domain_index);
960  vlib_cli_output (vm, "%U", format_map_domain, d, counters);
961  }
962 
963  return 0;
964 }
965 
966 static clib_error_t *
968  vlib_cli_command_t * cmd)
969 {
970  map_main_t *mm = &map_main;
971  map_ip4_reass_t *f4;
972  map_ip6_reass_t *f6;
973 
974  /* *INDENT-OFF* */
975  pool_foreach(f4, mm->ip4_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip4_reass, f4);}));
976  /* *INDENT-ON* */
977  /* *INDENT-OFF* */
978  pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
979  /* *INDENT-ON* */
980  return (0);
981 }
982 
983 u64
984 map_error_counter_get (u32 node_index, map_error_t map_error)
985 {
986  vlib_main_t *vm = vlib_get_main ();
987  vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
988  vlib_error_main_t *em = &vm->error_main;
989  vlib_error_t e = error_node->errors[map_error];
990  vlib_node_t *n = vlib_get_node (vm, node_index);
991  u32 ci;
992 
993  ci = vlib_error_get_code (e);
994  ASSERT (ci < n->n_errors);
995  ci += n->error_heap_index;
996 
997  return (em->counters[ci]);
998 }
999 
1000 static clib_error_t *
1002  vlib_cli_command_t * cmd)
1003 {
1004  map_main_t *mm = &map_main;
1005  map_domain_t *d;
1006  int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1007  if (pool_elts (mm->domains) == 0)
1008  vlib_cli_output (vm, "No MAP domains are configured...");
1009 
1010  /* *INDENT-OFF* */
1011  pool_foreach(d, mm->domains, ({
1012  if (d->rules) {
1013  rulecount+= 0x1 << d->psid_length;
1014  rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1015  }
1016  domains += sizeof(*d);
1017  domaincount++;
1018  }));
1019  /* *INDENT-ON* */
1020 
1021  vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1022  vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1023  vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1024  vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1025 
1026 #if MAP_SKIP_IP6_LOOKUP
1027  vlib_cli_output (vm,
1028  "MAP pre-resolve: IP6 next-hop: %U (%u), IP4 next-hop: %U (%u)\n",
1029  format_ip6_address, &mm->preresolve_ip6, mm->adj6_index,
1030  format_ip4_address, &mm->preresolve_ip4, mm->adj4_index);
1031 #endif
1032 
1033  if (mm->tc_copy)
1034  vlib_cli_output (vm, "MAP traffic-class: copy");
1035  else
1036  vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1037 
1038  vlib_cli_output (vm,
1039  "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1040  mm->sec_check ? "enabled" : "disabled",
1041  mm->sec_check_frag ? "enabled" : "disabled");
1042 
1043  vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1044  format_ip4_address, &mm->icmp4_src_address);
1045  vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1046  mm->icmp6_enabled ? "enabled" : "disabled");
1047  vlib_cli_output (vm, "Inner fragmentation: %s\n",
1048  mm->frag_inner ? "enabled" : "disabled");
1049  vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1050  mm->frag_ignore_df ? "enabled" : "disabled");
1051 
1052  /*
1053  * Counters
1054  */
1055  vlib_combined_counter_main_t *cm = mm->domain_counters;
1056  u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1057  u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1058  int which, i;
1059  vlib_counter_t v;
1060 
1061  memset (total_pkts, 0, sizeof (total_pkts));
1062  memset (total_bytes, 0, sizeof (total_bytes));
1063 
1065  vec_foreach (cm, mm->domain_counters)
1066  {
1067  which = cm - mm->domain_counters;
1068 
1069  for (i = 0; i < vec_len (cm->maxi); i++)
1070  {
1071  vlib_get_combined_counter (cm, i, &v);
1072  total_pkts[which] += v.packets;
1073  total_bytes[which] += v.bytes;
1074  }
1075  }
1077 
1078  vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1079  total_pkts[MAP_DOMAIN_COUNTER_TX],
1080  total_bytes[MAP_DOMAIN_COUNTER_TX]);
1081  vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1082  total_pkts[MAP_DOMAIN_COUNTER_RX],
1083  total_bytes[MAP_DOMAIN_COUNTER_RX]);
1084 
1085  vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1086  vlib_get_simple_counter (&mm->icmp_relayed, 0));
1087 
1088  return 0;
1089 }
1090 
1091 static clib_error_t *
1093  vlib_cli_command_t * cmd)
1094 {
1095  unformat_input_t _line_input, *line_input = &_line_input;
1096  u32 lifetime = ~0;
1097  f64 ht_ratio = (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1);
1098  u32 pool_size = ~0;
1099  u64 buffers = ~(0ull);
1100  u8 ip4 = 0, ip6 = 0;
1101 
1102  if (!unformat_user (input, unformat_line_input, line_input))
1103  return 0;
1104 
1105  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1106  {
1107  if (unformat (line_input, "lifetime %u", &lifetime))
1108  ;
1109  else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1110  ;
1111  else if (unformat (line_input, "pool-size %u", &pool_size))
1112  ;
1113  else if (unformat (line_input, "buffers %llu", &buffers))
1114  ;
1115  else if (unformat (line_input, "ip4"))
1116  ip4 = 1;
1117  else if (unformat (line_input, "ip6"))
1118  ip6 = 1;
1119  else
1120  {
1121  unformat_free (line_input);
1122  return clib_error_return (0, "invalid input");
1123  }
1124  }
1125  unformat_free (line_input);
1126 
1127  if (!ip4 && !ip6)
1128  return clib_error_return (0, "must specify ip4 and/or ip6");
1129 
1130  if (ip4)
1131  {
1132  if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1133  return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1135  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1136  && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1137  return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1139  if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1140  return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1142  if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1143  return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1145  }
1146 
1147  if (ip6)
1148  {
1149  if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1150  return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1152  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1153  && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1154  return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1156  if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1157  return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1159  if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1160  return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1162  }
1163 
1164  if (ip4)
1165  {
1166  u32 reass = 0, packets = 0;
1167  if (pool_size != ~0)
1168  {
1169  if (map_ip4_reass_conf_pool_size (pool_size, &reass, &packets))
1170  {
1171  vlib_cli_output (vm, "Could not set ip4-reass pool-size");
1172  }
1173  else
1174  {
1175  vlib_cli_output (vm,
1176  "Setting ip4-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1177  reass, packets);
1178  }
1179  }
1180  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1181  {
1182  if (map_ip4_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1183  {
1184  vlib_cli_output (vm, "Could not set ip4-reass ht-log2len");
1185  }
1186  else
1187  {
1188  vlib_cli_output (vm,
1189  "Setting ip4-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1190  reass, packets);
1191  }
1192  }
1193  if (lifetime != ~0)
1194  {
1195  if (map_ip4_reass_conf_lifetime (lifetime))
1196  vlib_cli_output (vm, "Could not set ip4-reass lifetime");
1197  else
1198  vlib_cli_output (vm, "Setting ip4-reass lifetime");
1199  }
1200  if (buffers != ~(0ull))
1201  {
1202  if (map_ip4_reass_conf_buffers (buffers))
1203  vlib_cli_output (vm, "Could not set ip4-reass buffers");
1204  else
1205  vlib_cli_output (vm, "Setting ip4-reass buffers");
1206  }
1207 
1211  {
1212  vlib_cli_output (vm,
1213  "Note: 'ip4-reass buffers' > pool-size * max-fragments-per-reassembly.");
1214  }
1215  }
1216 
1217  if (ip6)
1218  {
1219  u32 reass = 0, packets = 0;
1220  if (pool_size != ~0)
1221  {
1222  if (map_ip6_reass_conf_pool_size (pool_size, &reass, &packets))
1223  {
1224  vlib_cli_output (vm, "Could not set ip6-reass pool-size");
1225  }
1226  else
1227  {
1228  vlib_cli_output (vm,
1229  "Setting ip6-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1230  reass, packets);
1231  }
1232  }
1233  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1234  {
1235  if (map_ip6_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1236  {
1237  vlib_cli_output (vm, "Could not set ip6-reass ht-log2len");
1238  }
1239  else
1240  {
1241  vlib_cli_output (vm,
1242  "Setting ip6-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1243  reass, packets);
1244  }
1245  }
1246  if (lifetime != ~0)
1247  {
1248  if (map_ip6_reass_conf_lifetime (lifetime))
1249  vlib_cli_output (vm, "Could not set ip6-reass lifetime");
1250  else
1251  vlib_cli_output (vm, "Setting ip6-reass lifetime");
1252  }
1253  if (buffers != ~(0ull))
1254  {
1255  if (map_ip6_reass_conf_buffers (buffers))
1256  vlib_cli_output (vm, "Could not set ip6-reass buffers");
1257  else
1258  vlib_cli_output (vm, "Setting ip6-reass buffers");
1259  }
1260 
1264  {
1265  vlib_cli_output (vm,
1266  "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1267  }
1268  }
1269 
1270  return 0;
1271 }
1272 
1273 
1274 /*
1275  * packet trace format function
1276  */
1277 u8 *
1278 format_map_trace (u8 * s, va_list * args)
1279 {
1280  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1281  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1282  map_trace_t *t = va_arg (*args, map_trace_t *);
1283  u32 map_domain_index = t->map_domain_index;
1284  u16 port = t->port;
1285 
1286  s =
1287  format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1288  clib_net_to_host_u16 (port));
1289 
1290  return s;
1291 }
1292 
1295 {
1296  map_main_t *mm = &map_main;
1297  u32 ri = mm->ip4_reass_hash_table[bucket];
1298  while (ri != MAP_REASS_INDEX_NONE)
1299  {
1301  if (r->key.as_u64[0] == k->as_u64[0] &&
1302  r->key.as_u64[1] == k->as_u64[1] &&
1303  now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1304  {
1305  return r;
1306  }
1307  ri = r->bucket_next;
1308  }
1309  return NULL;
1310 }
1311 
1312 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1313 
1314 void
1316 {
1317  map_main_t *mm = &map_main;
1318  map_ip4_reass_get_fragments (r, pi_to_drop);
1319 
1320  // Unlink in hash bucket
1321  map_ip4_reass_t *r2 = NULL;
1322  u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1323  while (r2i != map_ip4_reass_pool_index (r))
1324  {
1325  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1326  r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1327  r2i = r2->bucket_next;
1328  }
1329  if (r2)
1330  {
1331  r2->bucket_next = r->bucket_next;
1332  }
1333  else
1334  {
1336  }
1337 
1338  // Unlink in list
1339  if (r->fifo_next == map_ip4_reass_pool_index (r))
1340  {
1342  }
1343  else
1344  {
1346  mm->ip4_reass_fifo_last = r->fifo_prev;
1347  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1348  r->fifo_next;
1349  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1350  r->fifo_prev;
1351  }
1352 
1353  pool_put (mm->ip4_reass_pool, r);
1354  mm->ip4_reass_allocated--;
1355 }
1356 
1358 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1359  u8 protocol, u32 ** pi_to_drop)
1360 {
1361  map_ip4_reass_t *r;
1362  map_main_t *mm = &map_main;
1363  map_ip4_reass_key_t k = {.src.data_u32 = src,
1364  .dst.data_u32 = dst,
1365  .fragment_id = fragment_id,
1366  .protocol = protocol
1367  };
1368 
1369  u32 h = 0;
1370  h = crc_u32 (k.as_u32[0], h);
1371  h = crc_u32 (k.as_u32[1], h);
1372  h = crc_u32 (k.as_u32[2], h);
1373  h = crc_u32 (k.as_u32[3], h);
1374  h = h >> (32 - mm->ip4_reass_ht_log2len);
1375 
1376  f64 now = vlib_time_now (mm->vlib_main);
1377 
1378  //Cache garbage collection
1380  {
1383  if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1384  map_ip4_reass_free (last, pi_to_drop);
1385  else
1386  break;
1387  }
1388 
1389  if ((r = map_ip4_reass_lookup (&k, h, now)))
1390  return r;
1391 
1393  return NULL;
1394 
1395  pool_get (mm->ip4_reass_pool, r);
1396  mm->ip4_reass_allocated++;
1397  int i;
1398  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1399  r->fragments[i] = ~0;
1400 
1401  u32 ri = map_ip4_reass_pool_index (r);
1402 
1403  //Link in new bucket
1404  r->bucket = h;
1405  r->bucket_next = mm->ip4_reass_hash_table[h];
1406  mm->ip4_reass_hash_table[h] = ri;
1407 
1408  //Link in fifo
1410  {
1411  r->fifo_next =
1413  mm->ip4_reass_fifo_last)->fifo_next;
1414  r->fifo_prev = mm->ip4_reass_fifo_last;
1415  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1416  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1417  }
1418  else
1419  {
1420  r->fifo_next = r->fifo_prev = ri;
1421  mm->ip4_reass_fifo_last = ri;
1422  }
1423 
1424  //Set other fields
1425  r->ts = now;
1426  r->key = k;
1427  r->port = -1;
1428 #ifdef MAP_IP4_REASS_COUNT_BYTES
1429  r->expected_total = 0xffff;
1430  r->forwarded = 0;
1431 #endif
1432 
1433  return r;
1434 }
1435 
1436 int
1438 {
1440  return -1;
1441 
1442  int i;
1443  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1444  if (r->fragments[i] == ~0)
1445  {
1446  r->fragments[i] = pi;
1448  return 0;
1449  }
1450  return -1;
1451 }
1452 
1455 {
1456  map_main_t *mm = &map_main;
1457  u32 ri = mm->ip6_reass_hash_table[bucket];
1458  while (ri != MAP_REASS_INDEX_NONE)
1459  {
1461  if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1462  r->key.as_u64[0] == k->as_u64[0] &&
1463  r->key.as_u64[1] == k->as_u64[1] &&
1464  r->key.as_u64[2] == k->as_u64[2] &&
1465  r->key.as_u64[3] == k->as_u64[3] &&
1466  r->key.as_u64[4] == k->as_u64[4])
1467  return r;
1468  ri = r->bucket_next;
1469  }
1470  return NULL;
1471 }
1472 
1473 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1474 
1475 void
1477 {
1478  map_main_t *mm = &map_main;
1479  int i;
1480  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1481  if (r->fragments[i].pi != ~0)
1482  {
1483  vec_add1 (*pi_to_drop, r->fragments[i].pi);
1484  r->fragments[i].pi = ~0;
1486  }
1487 
1488  // Unlink in hash bucket
1489  map_ip6_reass_t *r2 = NULL;
1490  u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1491  while (r2i != map_ip6_reass_pool_index (r))
1492  {
1493  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1494  r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1495  r2i = r2->bucket_next;
1496  }
1497  if (r2)
1498  {
1499  r2->bucket_next = r->bucket_next;
1500  }
1501  else
1502  {
1504  }
1505 
1506  // Unlink in list
1507  if (r->fifo_next == map_ip6_reass_pool_index (r))
1508  {
1509  //Single element in the list, list is now empty
1511  }
1512  else
1513  {
1514  if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r)) //First element
1515  mm->ip6_reass_fifo_last = r->fifo_prev;
1516  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1517  r->fifo_next;
1518  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1519  r->fifo_prev;
1520  }
1521 
1522  // Free from pool if necessary
1523  pool_put (mm->ip6_reass_pool, r);
1524  mm->ip6_reass_allocated--;
1525 }
1526 
1529  u8 protocol, u32 ** pi_to_drop)
1530 {
1531  map_ip6_reass_t *r;
1532  map_main_t *mm = &map_main;
1533  map_ip6_reass_key_t k = {
1534  .src = *src,
1535  .dst = *dst,
1536  .fragment_id = fragment_id,
1537  .protocol = protocol
1538  };
1539 
1540  u32 h = 0;
1541  int i;
1542  for (i = 0; i < 10; i++)
1543  h = crc_u32 (k.as_u32[i], h);
1544  h = h >> (32 - mm->ip6_reass_ht_log2len);
1545 
1546  f64 now = vlib_time_now (mm->vlib_main);
1547 
1548  //Cache garbage collection
1550  {
1553  if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1554  map_ip6_reass_free (last, pi_to_drop);
1555  else
1556  break;
1557  }
1558 
1559  if ((r = map_ip6_reass_lookup (&k, h, now)))
1560  return r;
1561 
1563  return NULL;
1564 
1565  pool_get (mm->ip6_reass_pool, r);
1566  mm->ip6_reass_allocated++;
1567  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1568  {
1569  r->fragments[i].pi = ~0;
1570  r->fragments[i].next_data_len = 0;
1571  r->fragments[i].next_data_offset = 0;
1572  }
1573 
1574  u32 ri = map_ip6_reass_pool_index (r);
1575 
1576  //Link in new bucket
1577  r->bucket = h;
1578  r->bucket_next = mm->ip6_reass_hash_table[h];
1579  mm->ip6_reass_hash_table[h] = ri;
1580 
1581  //Link in fifo
1583  {
1584  r->fifo_next =
1586  mm->ip6_reass_fifo_last)->fifo_next;
1587  r->fifo_prev = mm->ip6_reass_fifo_last;
1588  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1589  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1590  }
1591  else
1592  {
1593  r->fifo_next = r->fifo_prev = ri;
1594  mm->ip6_reass_fifo_last = ri;
1595  }
1596 
1597  //Set other fields
1598  r->ts = now;
1599  r->key = k;
1601 #ifdef MAP_IP6_REASS_COUNT_BYTES
1602  r->expected_total = 0xffff;
1603  r->forwarded = 0;
1604 #endif
1605  return r;
1606 }
1607 
1608 int
1610  u16 data_offset, u16 next_data_offset,
1611  u8 * data_start, u16 data_len)
1612 {
1613  map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1614  u16 copied_len = (data_len > 20) ? 20 : data_len;
1615 
1617  return -1;
1618 
1619  //Lookup for fragments for the current buffer
1620  //and the one before that
1621  int i;
1622  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1623  {
1624  if (data_offset && r->fragments[i].next_data_offset == data_offset)
1625  {
1626  prev_f = &r->fragments[i]; // This is buffer for previous packet
1627  }
1628  else if (r->fragments[i].next_data_offset == next_data_offset)
1629  {
1630  f = &r->fragments[i]; // This is a buffer for the current packet
1631  }
1632  else if (r->fragments[i].next_data_offset == 0)
1633  { //Available
1634  if (f == NULL)
1635  f = &r->fragments[i];
1636  else if (prev_f == NULL)
1637  prev_f = &r->fragments[i];
1638  }
1639  }
1640 
1641  if (!f || f->pi != ~0)
1642  return -1;
1643 
1644  if (data_offset)
1645  {
1646  if (!prev_f)
1647  return -1;
1648 
1649  clib_memcpy (prev_f->next_data, data_start, copied_len);
1650  prev_f->next_data_len = copied_len;
1651  prev_f->next_data_offset = data_offset;
1652  }
1653  else
1654  {
1655  if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1656  return -1;
1657 
1659  clib_memcpy (&r->ip4_header, data_start, sizeof (ip4_header_t));
1660  }
1661 
1662  if (data_len > 20)
1663  {
1664  f->next_data_offset = next_data_offset;
1665  f->pi = pi;
1667  }
1668  return 0;
1669 }
1670 
1671 void
1672 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1673 {
1674  map_main_t *mm = &map_main;
1675  int i;
1676 
1677  if (dropped_packets)
1678  *dropped_packets = mm->ip4_reass_buffered_counter;
1679  if (trashed_reass)
1680  *trashed_reass = mm->ip4_reass_allocated;
1682  {
1683  u16 ri = mm->ip4_reass_fifo_last;
1684  do
1685  {
1687  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1688  if (r->fragments[i] != ~0)
1689  map_ip4_drop_pi (r->fragments[i]);
1690 
1691  ri = r->fifo_next;
1692  pool_put (mm->ip4_reass_pool, r);
1693  }
1694  while (ri != mm->ip4_reass_fifo_last);
1695  }
1696 
1699  for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1701  pool_free (mm->ip4_reass_pool);
1703 
1704  mm->ip4_reass_allocated = 0;
1707 }
1708 
1709 u8
1710 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1711 {
1712  u32 desired_size = (u32) (pool_size * ht_ratio);
1713  u8 i;
1714  for (i = 1; i < 31; i++)
1715  if ((1 << i) >= desired_size)
1716  return i;
1717  return 4;
1718 }
1719 
1720 int
1721 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1722  u32 * dropped_packets)
1723 {
1724  map_main_t *mm = &map_main;
1725  if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1726  return -1;
1727 
1728  map_ip4_reass_lock ();
1729  mm->ip4_reass_conf_ht_ratio = ht_ratio;
1730  mm->ip4_reass_ht_log2len =
1732  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1734  return 0;
1735 }
1736 
1737 int
1738 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1739  u32 * dropped_packets)
1740 {
1741  map_main_t *mm = &map_main;
1742  if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1743  return -1;
1744 
1745  map_ip4_reass_lock ();
1746  mm->ip4_reass_conf_pool_size = pool_size;
1747  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1749  return 0;
1750 }
1751 
1752 int
1754 {
1755  map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1756  return 0;
1757 }
1758 
1759 int
1761 {
1762  map_main.ip4_reass_conf_buffers = buffers;
1763  return 0;
1764 }
1765 
1766 void
1767 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1768 {
1769  map_main_t *mm = &map_main;
1770  if (dropped_packets)
1771  *dropped_packets = mm->ip6_reass_buffered_counter;
1772  if (trashed_reass)
1773  *trashed_reass = mm->ip6_reass_allocated;
1774  int i;
1776  {
1777  u16 ri = mm->ip6_reass_fifo_last;
1778  do
1779  {
1781  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1782  if (r->fragments[i].pi != ~0)
1783  map_ip6_drop_pi (r->fragments[i].pi);
1784 
1785  ri = r->fifo_next;
1786  pool_put (mm->ip6_reass_pool, r);
1787  }
1788  while (ri != mm->ip6_reass_fifo_last);
1790  }
1791 
1794  for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1796  pool_free (mm->ip6_reass_pool);
1798 
1799  mm->ip6_reass_allocated = 0;
1801 }
1802 
1803 int
1804 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1805  u32 * dropped_packets)
1806 {
1807  map_main_t *mm = &map_main;
1808  if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1809  return -1;
1810 
1811  map_ip6_reass_lock ();
1812  mm->ip6_reass_conf_ht_ratio = ht_ratio;
1813  mm->ip6_reass_ht_log2len =
1815  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1817  return 0;
1818 }
1819 
1820 int
1821 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1822  u32 * dropped_packets)
1823 {
1824  map_main_t *mm = &map_main;
1825  if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1826  return -1;
1827 
1828  map_ip6_reass_lock ();
1829  mm->ip6_reass_conf_pool_size = pool_size;
1830  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1832  return 0;
1833 }
1834 
1835 int
1837 {
1838  map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1839  return 0;
1840 }
1841 
1842 int
1844 {
1845  map_main.ip6_reass_conf_buffers = buffers;
1846  return 0;
1847 }
1848 
1849 /* *INDENT-OFF* */
1850 
1851 /*?
1852  * Configure MAP reassembly behaviour
1853  *
1854  * @cliexpar
1855  * @cliexstart{map params reassembly}
1856  * @cliexend
1857  ?*/
1858 VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
1859  .path = "map params reassembly",
1860  .short_help = "map params reassembly [ip4 | ip6] [lifetime <lifetime-ms>] "
1861  "[pool-size <pool-size>] [buffers <buffers>] "
1862  "[ht-ratio <ht-ratio>]",
1863  .function = map_params_reass_command_fn,
1864 };
1865 
1866 /*?
1867  * Set or copy the IP TOS/Traffic Class field
1868  *
1869  * @cliexpar
1870  * @cliexstart{map params traffic-class}
1871  *
1872  * This command is used to set the traffic-class field in translated
1873  * or encapsulated packets. If copy is specifed (the default) then the
1874  * traffic-class/TOS field is copied from the original packet to the
1875  * translated / encapsulating header.
1876  * @cliexend
1877  ?*/
1878 VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
1879  .path = "map params traffic-class",
1880  .short_help = "map params traffic-class {0x0-0xff | copy}",
1881  .function = map_traffic_class_command_fn,
1882 };
1883 
1884 /*?
1885  * Bypass IP4/IP6 lookup
1886  *
1887  * @cliexpar
1888  * @cliexstart{map params pre-resolve}
1889  *
1890  * Bypass a second FIB lookup of the translated or encapsulated
1891  * packet, and forward the packet directly to the specified
1892  * next-hop. This optimization trades forwarding flexibility for
1893  * performance.
1894  * @cliexend
1895  ?*/
1896 VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
1897  .path = "map params pre-resolve",
1898  .short_help = " map params pre-resolve {ip4-nh <address>} "
1899  "| {ip6-nh <address>}",
1900  .function = map_pre_resolve_command_fn,
1901 };
1902 
1903 /*?
1904  * Enable or disable the MAP-E inbound security check
1905  *
1906  * @cliexpar
1907  * @cliexstart{map params security-check}
1908  *
1909  * By default, a decapsulated packet's IPv4 source address will be
1910  * verified against the outer header's IPv6 source address. Disabling
1911  * this feature will allow IPv4 source address spoofing.
1912  * @cliexend
1913  ?*/
1914 VLIB_CLI_COMMAND(map_security_check_command, static) = {
1915  .path = "map params security-check",
1916  .short_help = "map params security-check on|off",
1917  .function = map_security_check_command_fn,
1918 };
1919 
1920 /*?
1921  * Specifiy the IPv4 source address used for relayed ICMP error messages
1922  *
1923  * @cliexpar
1924  * @cliexstart{map params icmp source-address}
1925  *
1926  * This command specifies which IPv4 source address (must be local to
1927  * the system), that is used for relayed received IPv6 ICMP error
1928  * messages.
1929  * @cliexend
1930  ?*/
1931 VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
1932  .path = "map params icmp source-address",
1933  .short_help = "map params icmp source-address <ip4-address>",
1935 };
1936 
1937 /*?
1938  * Send IPv6 ICMP unreachables
1939  *
1940  * @cliexpar
1941  * @cliexstart{map params icmp6 unreachables}
1942  *
1943  * Send IPv6 ICMP unreachable messages back if security check fails or
1944  * no MAP domain exists.
1945  * @cliexend
1946  ?*/
1947 VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
1948  .path = "map params icmp6 unreachables",
1949  .short_help = "map params icmp6 unreachables {on|off}",
1951 };
1952 
1953 /*?
1954  * Configure MAP fragmentation behaviour
1955  *
1956  * @cliexpar
1957  * @cliexstart{map params fragment}
1958  * @cliexend
1959  ?*/
1960 VLIB_CLI_COMMAND(map_fragment_command, static) = {
1961  .path = "map params fragment",
1962  .short_help = "map params fragment inner|outer",
1963  .function = map_fragment_command_fn,
1964 };
1965 
1966 /*?
1967  * Ignore the IPv4 Don't fragment bit
1968  *
1969  * @cliexpar
1970  * @cliexstart{map params fragment ignore-df}
1971  *
1972  * Allows fragmentation of the IPv4 packet even if the DF bit is
1973  * set. The choice between inner or outer fragmentation of tunnel
1974  * packets is complicated. The benefit of inner fragmentation is that
1975  * the ultimate endpoint must reassemble, instead of the tunnel
1976  * endpoint.
1977  * @cliexend
1978  ?*/
1979 VLIB_CLI_COMMAND(map_fragment_df_command, static) = {
1980  .path = "map params fragment ignore-df",
1981  .short_help = "map params fragment ignore-df on|off",
1982  .function = map_fragment_df_command_fn,
1983 };
1984 
1985 /*?
1986  * Specifiy if the inbound security check should be done on fragments
1987  *
1988  * @cliexpar
1989  * @cliexstart{map params security-check fragments}
1990  *
1991  * Typically the inbound on-decapsulation security check is only done
1992  * on the first packet. The packet that contains the L4
1993  * information. While a security check on every fragment is possible,
1994  * it has a cost. State must be created on the first fragment.
1995  * @cliexend
1996  ?*/
1997 VLIB_CLI_COMMAND(map_security_check_frag_command, static) = {
1998  .path = "map params security-check fragments",
1999  .short_help = "map params security-check fragments on|off",
2001 };
2002 
2003 /*?
2004  * Add MAP domain
2005  *
2006  * @cliexpar
2007  * @cliexstart{map add domain}
2008  * @cliexend
2009  ?*/
2010 VLIB_CLI_COMMAND(map_add_domain_command, static) = {
2011  .path = "map add domain",
2012  .short_help = "map add domain ip4-pfx <ip4-pfx> ip6-pfx <ip6-pfx> "
2013  "ip6-src <ip6-pfx> ea-bits-len <n> psid-offset <n> psid-len <n> "
2014  "[map-t] [mtu <mtu>]",
2015  .function = map_add_domain_command_fn,
2016 };
2017 
2018 /*?
2019  * Add MAP rule to a domain
2020  *
2021  * @cliexpar
2022  * @cliexstart{map add rule}
2023  * @cliexend
2024  ?*/
2025 VLIB_CLI_COMMAND(map_add_rule_command, static) = {
2026  .path = "map add rule",
2027  .short_help = "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
2028  .function = map_add_rule_command_fn,
2029 };
2030 
2031 /*?
2032  * Delete MAP domain
2033  *
2034  * @cliexpar
2035  * @cliexstart{map del domain}
2036  * @cliexend
2037  ?*/
2038 VLIB_CLI_COMMAND(map_del_command, static) = {
2039  .path = "map del domain",
2040  .short_help = "map del domain index <domain>",
2041  .function = map_del_domain_command_fn,
2042 };
2043 
2044 /*?
2045  * Show MAP domains
2046  *
2047  * @cliexpar
2048  * @cliexstart{show map domain}
2049  * @cliexend
2050  ?*/
2051 VLIB_CLI_COMMAND(show_map_domain_command, static) = {
2052  .path = "show map domain",
2053  .short_help = "show map domain index <n> [counters]",
2054  .function = show_map_domain_command_fn,
2055 };
2056 
2057 /*?
2058  * Show MAP statistics
2059  *
2060  * @cliexpar
2061  * @cliexstart{show map stats}
2062  * @cliexend
2063  ?*/
2064 VLIB_CLI_COMMAND(show_map_stats_command, static) = {
2065  .path = "show map stats",
2066  .short_help = "show map stats",
2067  .function = show_map_stats_command_fn,
2068 };
2069 
2070 /*?
2071  * Show MAP fragmentation information
2072  *
2073  * @cliexpar
2074  * @cliexstart{show map fragments}
2075  * @cliexend
2076  ?*/
2077 VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
2078  .path = "show map fragments",
2079  .short_help = "show map fragments",
2080  .function = show_map_fragments_command_fn,
2081 };
2082 /* *INDENT-ON* */
2083 
2084 /*
2085  * map_init
2086  */
2087 clib_error_t *
2089 {
2090  map_main_t *mm = &map_main;
2091  mm->vnet_main = vnet_get_main ();
2092  mm->vlib_main = vm;
2093 
2094 #ifdef MAP_SKIP_IP6_LOOKUP
2095  memset (&mm->preresolve_ip4, 0, sizeof (mm->preresolve_ip4));
2096  memset (&mm->preresolve_ip6, 0, sizeof (mm->preresolve_ip6));
2097  mm->adj4_index = 0;
2098  mm->adj6_index = 0;
2099 #endif
2100 
2101  /* traffic class */
2102  mm->tc = 0;
2103  mm->tc_copy = true;
2104 
2105  /* Inbound security check */
2106  mm->sec_check = true;
2107  mm->sec_check_frag = false;
2108 
2109  /* ICMP6 Type 1, Code 5 for security check failure */
2110  mm->icmp6_enabled = false;
2111 
2112  /* Inner or outer fragmentation */
2113  mm->frag_inner = false;
2114  mm->frag_ignore_df = false;
2115 
2119 
2122 
2123  /* IP4 virtual reassembly */
2124  mm->ip4_reass_hash_table = 0;
2125  mm->ip4_reass_pool = 0;
2126  mm->ip4_reass_lock =
2132  mm->ip4_reass_ht_log2len =
2137 
2138  /* IP6 virtual reassembly */
2139  mm->ip6_reass_hash_table = 0;
2140  mm->ip6_reass_pool = 0;
2141  mm->ip6_reass_lock =
2147  mm->ip6_reass_ht_log2len =
2152 
2154 
2155  return 0;
2156 }
2157 
2159 
2160 /*
2161  * fd.io coding-style-patch-verification: ON
2162  *
2163  * Local Variables:
2164  * eval: (c-set-style "gnu")
2165  * End:
2166  */
static map_dpo_t * map_dpo_get(index_t index)
Definition: map_dpo.h:60
u16 forwarded
Definition: map.h:191
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:154
#define map_ip4_reass_lock()
Definition: map.h:449
u8 psid_length
Definition: map.h:102
map_ip4_reass_t * ip4_reass_pool
Definition: map.h:243
u64 packets
packet counter
Definition: counter.h:166
u32 ip4_reass_conf_buffers
Definition: map.h:240
u32 error_heap_index
Definition: node.h:278
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static clib_error_t * map_fragment_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:746
#define CLIB_UNUSED(x)
Definition: clib.h:79
#define MAP_IP6_REASS_CONF_BUFFERS_MAX
Definition: map.h:501
u32 as_u32[4]
Definition: map.h:130
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
int map_delete_domain(u32 map_domain_index)
Definition: map.c:351
#define MAP_IP6_REASS_BUFFERS_DEFAULT
Definition: map.h:75
map_domain_flags_e flags
Definition: map.h:97
u16 fifo_prev
Definition: map.h:195
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:110
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
u16 ip4_reass_allocated
Definition: map.h:245
volatile u32 * ip6_reass_lock
Definition: map.h:271
format_function_t format_ip6_address
Definition: format.h:95
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 ip4_reass_ht_log2len
Definition: map.h:244
u32 fragments[MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:147
#define MAP_IP6_REASS_LIFETIME_DEFAULT
Definition: map.h:72
static_always_inline map_ip6_reass_t * map_ip6_reass_lookup(map_ip6_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1454
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:247
u16 bucket_next
Definition: map.h:194
#define PREDICT_TRUE(x)
Definition: clib.h:98
u64 as_u64[2]
Definition: ip6_packet.h:51
map_error_t
Definition: map.h:300
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define NULL
Definition: clib.h:55
vlib_counter_t * maxi
Shared wide counter pairs.
Definition: counter.h:215
static u8 * format_map_domain(u8 *s, va_list *args)
Definition: map.c:829
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
static clib_error_t * show_map_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:917
void map_ip4_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1672
static clib_error_t * map_security_check_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:462
u64 map_error_counter_get(u32 node_index, map_error_t map_error)
Definition: map.c:984
static_always_inline int ip6_parse(const ip6_header_t *ip6, u32 buff_len, u8 *l4_protocol, u16 *l4_offset, u16 *frag_hdr_offset)
Definition: map.h:504
static clib_error_t * map_fragment_df_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:772
vlib_main_t * vlib_main
Definition: map.h:230
u8 tc
Definition: map.h:218
static clib_error_t * show_map_fragments_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:967
i32 ip6_get_port(ip6_header_t *ip6, map_dir_e dir, u16 buffer_len)
Definition: map.c:123
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:221
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
static void map_domain_counter_unlock(map_main_t *mm)
Definition: map.h:552
Combined counter to hold both packets and byte differences.
Definition: counter.h:164
static u64 clib_xxhash(u64 key)
Definition: xxhash.h:58
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
u32 suffix_mask
Definition: map.h:93
bool sec_check_frag
Definition: map.h:222
u32 ip4_reass_buffered_counter
Definition: map.h:251
static u8 * format_map_ip4_reass(u8 *s, va_list *args)
Definition: map.c:882
ip6_address_t preresolve_ip6
Definition: map.h:214
static u32 crc_u32(u32 data, u32 value)
Definition: map.c:37
vlib_error_t * errors
Definition: node.h:419
u16 ip4_reass_fifo_last
Definition: map.h:247
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
format_function_t format_ip4_address
Definition: format.h:79
int map_ip6_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1804
#define MAP_IP6_REASS_CONF_LIFETIME_MAX
Definition: map.h:499
u64 as_u64[5]
Definition: map.h:174
map_ip6_reass_t * ip6_reass_pool
Definition: map.h:266
map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:198
u16 port
Definition: map.h:311
ip4_address_t preresolve_ip4
Definition: map.h:213
#define map_ip6_reass_unlock()
Definition: map.h:473
float f32
Definition: types.h:143
IPv[46] Mapping.
Definition: fib_entry.h:74
void map_dpo_create(dpo_proto_t dproto, u32 domain_index, dpo_id_t *dpo)
Definition: map_dpo.c:48
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:70
bool tc_copy
Definition: map.h:219
#define static_always_inline
Definition: clib.h:85
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
static clib_error_t * map_pre_resolve_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:648
#define MAP_REASS_INDEX_NONE
Definition: map.h:116
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
map_ip4_reass_key_t key
Definition: map.h:136
static clib_error_t * map_icmp_unreachables_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:713
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:399
u16 bucket
Definition: map.h:193
vlib_combined_counter_main_t * domain_counters
Definition: map.h:207
static int ip4_get_fragment_offset(ip4_header_t *i)
Definition: ip4_packet.h:191
ip4_address_t icmp4_src_address
Definition: map.h:226
static clib_error_t * map_add_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:512
int i32
Definition: types.h:81
Aggregrate type for a prefix.
Definition: fib_types.h:145
u16 fifo_next
Definition: map.h:146
vlib_simple_counter_main_t icmp_relayed
Definition: map.h:227
int map_ip4_reass_add_fragment(map_ip4_reass_t *r, u32 pi)
Definition: map.c:1437
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
ip6_address_t * rules
Definition: map.h:92
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
u8 map_get_ht_log2len(f32 ht_ratio, u16 pool_size)
Definition: map.c:1710
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:201
u8 ea_bits_len
Definition: map.h:100
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
u8 ip6_prefix_len
Definition: map.h:98
#define MAP_IP4_REASS_CONF_LIFETIME_MAX
Definition: map.h:487
static_always_inline map_ip4_reass_t * map_ip4_reass_lookup(map_ip4_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1294
u16 ip6_reass_allocated
Definition: map.h:268
int map_add_del_psid(u32 map_domain_index, u16 psid, ip6_address_t *tep, u8 is_add)
Definition: map.c:395
const int fib_entry_get_dpo_for_source(fib_node_index_t fib_entry_index, fib_source_t source, dpo_id_t *dpo)
unformat_function_t unformat_ip4_address
Definition: format.h:76
#define MAP_IP6_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:497
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:138
Definition: fib_entry.h:220
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread u16 counters, and the shared vlib_counter_t...
Definition: counter.h:321
int map_ip6_reass_conf_buffers(u32 buffers)
Definition: map.c:1843
u32 vlib_error_t
Definition: error.h:44
#define map_ip4_reass_pool_index(r)
Definition: map.c:1312
static clib_error_t * map_add_rule_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:609
int map_ip4_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1753
vlib_error_main_t error_main
Definition: main.h:124
static u32 vlib_error_get_code(vlib_error_t e)
Definition: error.h:53
dpo_type_t dpoi_type
the type
Definition: dpo.h:142
#define MAP_IP4_REASS_BUFFERS_DEFAULT
Definition: map.h:68
#define MAP_IP4_REASS_CONF_HT_RATIO_MAX
Definition: map.h:483
static u8 * format_map_ip6_reass(u8 *s, va_list *args)
Definition: map.c:900
bool frag_ignore_df
Definition: map.h:254
volatile u32 * ip4_reass_lock
Definition: map.h:248
#define v
Definition: acl.c:314
u16 ip4_reass_conf_pool_size
Definition: map.h:238
map_domain_t * domains
Definition: map.h:203
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:102
u16 bucket
Definition: map.h:143
int map_ip4_reass_conf_buffers(u32 buffers)
Definition: map.c:1760
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
void map_t_dpo_create(dpo_proto_t dproto, u32 domain_index, dpo_id_t *dpo)
Definition: map_dpo.c:65
void map_dpo_module_init(void)
Definition: map_dpo.c:187
int map_ip6_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1836
map_ip4_reass_t * map_ip4_reass_get(u32 src, u32 dst, u16 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1358
static void vlib_get_combined_counter(vlib_combined_counter_main_t *cm, u32 index, vlib_counter_t *result)
Get the value of a combined counter, never called in the speed path Scrapes the entire set of mini co...
Definition: counter.h:287
int map_ip4_reass_conf_pool_size(u16 pool_size, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1738
u16 * ip6_reass_hash_table
Definition: map.h:269
u16 * ip4_reass_hash_table
Definition: map.h:246
map_main_t map_main
Definition: map.h:314
i32 ip4_get_port(ip4_header_t *ip, map_dir_e dir, u16 buffer_len)
Definition: map.c:79
#define MAP_IP4_REASS_HT_RATIO_DEFAULT
Definition: map.h:66
u8 ip6_src_len
Definition: map.h:99
u8 psid_shift
Definition: map.h:105
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
const dpo_id_t * load_balance_get_bucket(index_t lbi, u32 bucket)
Definition: load_balance.c:271
u16 expected_total
Definition: map.h:139
unformat_function_t unformat_ip6_address
Definition: format.h:94
u8 suffix_shift
Definition: map.h:106
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
void map_ip4_drop_pi(u32 pi)
Definition: ip6_map.c:667
u8 ip6_reass_ht_log2len
Definition: map.h:267
u32 ip6_fib_table_fwding_lookup(ip6_main_t *im, u32 fib_index, const ip6_address_t *dst)
Definition: ip6_fib.c:392
u16 ip6_reass_fifo_last
Definition: map.h:270
#define pool_free(p)
Free a pool.
Definition: pool.h:263
void map_ip4_reass_free(map_ip4_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1315
u64 * counters
Definition: error.h:78
static clib_error_t * map_params_reass_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1092
u16 ip6_reass_conf_pool_size
Definition: map.h:261
map_dir_e
Definition: map.h:28
u8 next_data_len
Definition: map.h:182
ip4_address_t ip4_prefix
Definition: map.h:94
u16 next_data_offset
Definition: map.h:181
static_always_inline void map_ip4_reass_get_fragments(map_ip4_reass_t *r, u32 **pi)
Definition: map.h:453
map_ip6_reass_t * map_ip6_reass_get(ip6_address_t *src, ip6_address_t *dst, u32 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1528
#define MAP_IP6_REASS_POOL_SIZE_DEFAULT
Definition: map.h:74
u32 as_u32[10]
Definition: map.h:175
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
int map_create_domain(ip4_address_t *ip4_prefix, u8 ip4_prefix_len, ip6_address_t *ip6_prefix, u8 ip6_prefix_len, ip6_address_t *ip6_src, u8 ip6_src_len, u8 ea_bits_len, u8 psid_offset, u8 psid_length, u32 *map_domain_index, u16 mtu, u8 flags)
Definition: map.c:165
u64 bytes
byte counter
Definition: counter.h:167
u8 psid_offset
Definition: map.h:101
static clib_error_t * map_icmp_relay_source_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:684
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:88
u16 forwarded
Definition: map.h:140
#define clib_memcpy(a, b, c)
Definition: string.h:69
bool icmp6_enabled
Definition: map.h:223
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
map_ip6_reass_key_t key
Definition: map.h:187
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
ip6_address_t ip6_src
Definition: map.h:90
u32 adj4_index
Definition: map.h:212
int map_ip4_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1721
static clib_error_t * map_del_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:579
static void map_domain_counter_lock(map_main_t *mm)
Definition: map.h:545
f32 ip4_reass_conf_ht_ratio
Definition: map.h:237
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
A representation of a MAP DPO.
Definition: map_dpo.h:25
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:288
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:98
#define ip6_frag_hdr_offset(hdr)
Definition: ip6_packet.h:482
int map_ip6_reass_conf_pool_size(u16 pool_size, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1821
#define ASSERT(truth)
#define u8_ptr_add(ptr, index)
Definition: map.h:522
unsigned int u32
Definition: types.h:88
bool sec_check
Definition: map.h:221
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip6_main_t ip6_main
Definition: ip6_forward.c:2828
bool frag_inner
Definition: map.h:253
u16 psid_mask
Definition: map.h:95
void map_ip6_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1767
static void clib_mem_free(void *p)
Definition: mem.h:176
ip4_header_t ip4_header
Definition: map.h:197
#define map_ip4_reass_unlock()
Definition: map.h:450
static void vlib_zero_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Clear a simple counter Clears the set of per-thread u16 counters, and the u64 counter.
Definition: counter.h:143
u8 * format_map_trace(u8 *s, va_list *args)
Definition: map.c:1278
#define MAP_IP6_REASS_HT_RATIO_DEFAULT
Definition: map.h:73
u8 ea_shift
Definition: map.h:107
ip6_address_t ip6_prefix
Definition: map.h:91
f32 ip6_reass_conf_ht_ratio
Definition: map.h:260
static clib_error_t * map_traffic_class_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:799
vnet_main_t * vnet_main
Definition: map.h:231
unsigned short u16
Definition: types.h:57
u16 mtu
Definition: map.h:96
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:154
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
u16 ip6_reass_conf_lifetime_ms
Definition: map.h:262
unsigned char u8
Definition: types.h:56
#define map_ip6_reass_lock()
Definition: map.h:472
u32 adj6_index
Definition: map.h:212
i32 port
Definition: map.h:142
#define MAP_IP4_REASS_POOL_SIZE_DEFAULT
Definition: map.h:67
#define MAP_IP6_REASS_CONF_HT_RATIO_MAX
Definition: map.h:495
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:165
char * name
The counter collection&#39;s name.
Definition: counter.h:219
A collection of combined counters.
Definition: counter.h:212
#define MAP_IP4_REASS_LIFETIME_DEFAULT
IP4 reassembly logic: One virtually reassembled flow requires a map_ip4_reass_t structure in order to...
Definition: map.h:65
u16 bucket_next
Definition: map.h:144
#define MAP_IP4_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:485
static u64 vlib_get_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Get the value of a simple counter Scrapes the entire set of mini counters.
Definition: counter.h:108
u8 ip4_prefix_len
Definition: map.h:110
void map_ip6_reass_free(map_ip6_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1476
vlib_simple_counter_main_t * simple_domain_counters
Definition: map.h:206
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:77
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:191
u16 ip4_reass_conf_lifetime_ms
Definition: map.h:239
#define vec_foreach(var, vec)
Vector iterator.
index_t ip4_fib_table_lookup_lb(ip4_fib_t *fib, const ip4_address_t *addr)
Definition: ip4_fib.c:261
static clib_error_t * map_security_check_frag_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:487
u32 map_domain_index
Definition: map.h:310
#define MAP_IP4_REASS_CONF_BUFFERS_MAX
Definition: map.h:489
u64 as_u64[2]
Definition: map.h:129
#define clib_error_return(e, args...)
Definition: error.h:111
u8 ip_version_and_header_length
Definition: ip4_packet.h:131
u16 fifo_prev
Definition: map.h:145
struct _unformat_input_t unformat_input_t
Definition: map.h:30
u32 flags
Definition: vhost-user.h:75
u32 ip6_reass_buffered_counter
Definition: map.h:274
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
int map_ip6_reass_add_fragment(map_ip6_reass_t *r, u32 pi, u16 data_offset, u16 next_data_offset, u8 *data_start, u16 data_len)
Definition: map.c:1609
static void map_pre_resolve(ip4_address_t *ip4, ip6_address_t *ip6)
Definition: map.c:441
u16 expected_total
Definition: map.h:190
clib_error_t * map_init(vlib_main_t *vm)
Definition: map.c:2088
unformat_function_t unformat_line_input
Definition: format.h:281
u16 fifo_next
Definition: map.h:196
static clib_error_t * show_map_stats_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1001
void map_ip6_drop_pi(u32 pi)
Definition: ip6_map.c:658
#define map_ip6_reass_pool_index(r)
Definition: map.c:1473
u32 ip6_reass_conf_buffers
Definition: map.h:263
u32 md_domain
the MAP domain index
Definition: map_dpo.h:35
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109