FD.io VPP  v16.09
Vector Packet Processing
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 "map.h"
19 
20 #ifndef __SSE4_2__
21 #include <vppinfra/xxhash.h>
22 
23 static inline u32
24 crc_u32 (u32 data, u32 value)
25 {
26  u64 tmp = ((u64) data << 32) | (u64) value;
27  return (u32) clib_xxhash (tmp);
28 }
29 #endif
30 
31 /*
32  * This code supports the following MAP modes:
33  *
34  * Algorithmic Shared IPv4 address (ea_bits_len > 0):
35  * ea_bits_len + ip4_prefix > 32
36  * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
37  * Algorithmic Full IPv4 address (ea_bits_len > 0):
38  * ea_bits_len + ip4_prefix = 32
39  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
40  * Algorithmic IPv4 prefix (ea_bits_len > 0):
41  * ea_bits_len + ip4_prefix < 32
42  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
43  *
44  * Independent Shared IPv4 address (ea_bits_len = 0):
45  * ip4_prefix = 32
46  * psid_length > 0
47  * Rule IPv6 address = 128, Rule PSID Set
48  * Independent Full IPv4 address (ea_bits_len = 0):
49  * ip4_prefix = 32
50  * psid_length = 0, ip6_prefix = 128
51  * Independent IPv4 prefix (ea_bits_len = 0):
52  * ip4_prefix < 32
53  * psid_length = 0, ip6_prefix = 128
54  *
55  */
56 
57 /*
58  * This code supports MAP-T:
59  *
60  * With DMR prefix length equal to 96.
61  *
62  */
63 
64 
65 i32
66 ip4_get_port (ip4_header_t * ip, map_dir_e dir, u16 buffer_len)
67 {
68  //TODO: use buffer length
69  if (ip->ip_version_and_header_length != 0x45 ||
71  return -1;
72 
73  if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) ||
74  (ip->protocol == IP_PROTOCOL_UDP)))
75  {
76  udp_header_t *udp = (void *) (ip + 1);
77  return (dir == MAP_SENDER) ? udp->src_port : udp->dst_port;
78  }
79  else if (ip->protocol == IP_PROTOCOL_ICMP)
80  {
81  icmp46_header_t *icmp = (void *) (ip + 1);
82  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
83  {
84  return *((u16 *) (icmp + 1));
85  }
86  else if (clib_net_to_host_u16 (ip->length) >= 64)
87  {
88  ip = (ip4_header_t *) (icmp + 2);
89  if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) ||
90  (ip->protocol == IP_PROTOCOL_UDP)))
91  {
92  udp_header_t *udp = (void *) (ip + 1);
93  return (dir == MAP_SENDER) ? udp->dst_port : udp->src_port;
94  }
95  else if (ip->protocol == IP_PROTOCOL_ICMP)
96  {
97  icmp46_header_t *icmp = (void *) (ip + 1);
98  if (icmp->type == ICMP4_echo_request ||
99  icmp->type == ICMP4_echo_reply)
100  {
101  return *((u16 *) (icmp + 1));
102  }
103  }
104  }
105  }
106  return -1;
107 }
108 
109 i32
110 ip6_get_port (ip6_header_t * ip6, map_dir_e dir, u16 buffer_len)
111 {
112  u8 l4_protocol;
113  u16 l4_offset;
114  u16 frag_offset;
115  u8 *l4;
116 
117  if (ip6_parse (ip6, buffer_len, &l4_protocol, &l4_offset, &frag_offset))
118  return -1;
119 
120  //TODO: Use buffer length
121 
122  if (frag_offset &&
123  ip6_frag_hdr_offset (((ip6_frag_hdr_t *)
124  u8_ptr_add (ip6, frag_offset))))
125  return -1; //Can't deal with non-first fragment for now
126 
127  l4 = u8_ptr_add (ip6, l4_offset);
128  if (l4_protocol == IP_PROTOCOL_TCP || l4_protocol == IP_PROTOCOL_UDP)
129  {
130  return (dir ==
131  MAP_SENDER) ? ((udp_header_t *) (l4))->src_port : ((udp_header_t
132  *)
133  (l4))->dst_port;
134  }
135  else if (l4_protocol == IP_PROTOCOL_ICMP6)
136  {
137  icmp46_header_t *icmp = (icmp46_header_t *) (l4);
138  if (icmp->type == ICMP6_echo_request)
139  {
140  return (dir == MAP_SENDER) ? ((u16 *) (icmp))[2] : -1;
141  }
142  else if (icmp->type == ICMP6_echo_reply)
143  {
144  return (dir == MAP_SENDER) ? -1 : ((u16 *) (icmp))[2];
145  }
146  }
147  return -1;
148 }
149 
150 
151 int
153  u8 ip4_prefix_len,
154  ip6_address_t * ip6_prefix,
155  u8 ip6_prefix_len,
156  ip6_address_t * ip6_src,
157  u8 ip6_src_len,
158  u8 ea_bits_len,
159  u8 psid_offset,
160  u8 psid_length, u32 * map_domain_index, u16 mtu, u8 flags)
161 {
162  map_main_t *mm = &map_main;
163  ip4_main_t *im4 = &ip4_main;
164  ip6_main_t *im6 = &ip6_main;
165  map_domain_t *d;
166  ip_adjacency_t adj;
169  u8 suffix_len;
170  uword *p;
171 
172  /* EA bits must be within the first 64 bits */
173  if (ea_bits_len > 0 && (ip6_prefix_len + ea_bits_len) > 64)
174  return -1;
175 
176  /* Sanity check on the src prefix length */
177  if (flags & MAP_DOMAIN_TRANSLATION)
178  {
179  if (ip6_src_len != 96)
180  {
181  clib_warning ("MAP-T only supports ip6_src_len = 96 for now.");
182  return -1;
183  }
184  }
185  else
186  {
187  if (ip6_src_len != 128)
188  {
190  ("MAP-E requires a BR address, not a prefix (ip6_src_len should be 128).");
191  return -1;
192  }
193  }
194 
195  /* Get domain index */
197  memset (d, 0, sizeof (*d));
198  *map_domain_index = d - mm->domains;
199 
200  /* Init domain struct */
201  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
202  d->ip4_prefix_len = ip4_prefix_len;
203  d->ip6_prefix = *ip6_prefix;
204  d->ip6_prefix_len = ip6_prefix_len;
205  d->ip6_src = *ip6_src;
206  d->ip6_src_len = ip6_src_len;
207  d->ea_bits_len = ea_bits_len;
208  d->psid_offset = psid_offset;
209  d->psid_length = psid_length;
210  d->mtu = mtu;
211  d->flags = flags;
212 
213  /* How many, and which bits to grab from the IPv4 DA */
214  if (ip4_prefix_len + ea_bits_len < 32)
215  {
216  d->flags |= MAP_DOMAIN_PREFIX;
217  suffix_len = d->suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
218  }
219  else
220  {
221  d->suffix_shift = 0;
222  suffix_len = 32 - ip4_prefix_len;
223  }
224  d->suffix_mask = (1 << suffix_len) - 1;
225 
226  d->psid_shift = 16 - psid_length - psid_offset;
227  d->psid_mask = (1 << d->psid_length) - 1;
228  d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
229 
230  /* Init IP adjacency */
231  memset (&adj, 0, sizeof (adj));
232  adj.explicit_fib_index = ~0;
233  adj.lookup_next_index =
236  p = (uword *) & adj.rewrite_data[0];
237  *p = (uword) (*map_domain_index);
238 
239  if (ip4_get_route (im4, 0, 0, (u8 *) ip4_prefix, ip4_prefix_len))
240  {
241  clib_warning ("IPv4 route already defined: %U/%d", format_ip4_address,
242  ip4_prefix, ip4_prefix_len);
243  pool_put (mm->domains, d);
244  return -1;
245  }
246 
247  /* Create ip4 adjacency */
248  memset (&args4, 0, sizeof (args4));
249  args4.table_index_or_table_id = 0;
250  args4.flags = IP4_ROUTE_FLAG_ADD;
251  args4.dst_address.as_u32 = ip4_prefix->as_u32;
252  args4.dst_address_length = ip4_prefix_len;
253 
254  args4.adj_index = ~0;
255  args4.add_adj = &adj;
256  args4.n_add_adj = 1;
257  ip4_add_del_route (im4, &args4);
258 
259  /* Multiple MAP domains may share same source IPv6 TEP */
260  u32 ai = ip6_get_route (im6, 0, 0, ip6_src, ip6_src_len);
261  if (ai > 0)
262  {
264  ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
265  if (adj6->lookup_next_index != IP_LOOKUP_NEXT_MAP &&
267  {
268  clib_warning ("BR source address already assigned: %U",
269  format_ip6_address, ip6_src);
270  pool_put (mm->domains, d);
271  return -1;
272  }
273  /* Shared source */
274  p = (uword *) & adj6->rewrite_data[0];
275  p[0] = ~0;
276 
277  /* Add refcount, so we don't accidentially delete the route underneath someone */
278  p[1]++;
279  }
280  else
281  {
282  /* Create ip6 adjacency. */
283  memset (&args6, 0, sizeof (args6));
284  args6.table_index_or_table_id = 0;
285  args6.flags = IP6_ROUTE_FLAG_ADD;
286  args6.dst_address.as_u64[0] = ip6_src->as_u64[0];
287  args6.dst_address.as_u64[1] = ip6_src->as_u64[1];
288  args6.dst_address_length = ip6_src_len;
289  args6.adj_index = ~0;
290  args6.add_adj = &adj;
291  args6.n_add_adj = 1;
292  ip6_add_del_route (im6, &args6);
293  }
294 
295  /* Validate packet/byte counters */
297  int i;
298  for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
299  {
301  *map_domain_index);
303  *map_domain_index);
304  }
305  for (i = 0; i < vec_len (mm->domain_counters); i++)
306  {
308  *map_domain_index);
309  vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
310  }
312 
313  return 0;
314 }
315 
316 /*
317  * map_delete_domain
318  */
319 int
320 map_delete_domain (u32 map_domain_index)
321 {
322  map_main_t *mm = &map_main;
323  ip4_main_t *im4 = &ip4_main;
324  ip6_main_t *im6 = &ip6_main;
325  map_domain_t *d;
326  ip_adjacency_t adj;
329 
330  if (pool_is_free_index (mm->domains, map_domain_index))
331  {
332  clib_warning ("MAP domain delete: domain does not exist: %d",
333  map_domain_index);
334  return -1;
335  }
336 
337  d = pool_elt_at_index (mm->domains, map_domain_index);
338 
339  memset (&adj, 0, sizeof (adj));
340  adj.explicit_fib_index = ~0;
341  adj.lookup_next_index =
344 
345  /* Delete ip4 adjacency */
346  memset (&args4, 0, sizeof (args4));
347  args4.table_index_or_table_id = 0;
348  args4.flags = IP4_ROUTE_FLAG_DEL;
349  args4.dst_address.as_u32 = d->ip4_prefix.as_u32;
351  args4.adj_index = 0;
352  args4.add_adj = &adj;
353  args4.n_add_adj = 0;
354  ip4_add_del_route (im4, &args4);
355 
356  /* Delete ip6 adjacency */
357  u32 ai = ip6_get_route (im6, 0, 0, &d->ip6_src, d->ip6_src_len);
358  if (ai > 0)
359  {
361  ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
362 
363  uword *p = (uword *) & adj6->rewrite_data[0];
364  /* Delete route when no other domains use this source */
365  if (p[1] == 0)
366  {
367  memset (&args6, 0, sizeof (args6));
368  args6.table_index_or_table_id = 0;
369  args6.flags = IP6_ROUTE_FLAG_DEL;
370  args6.dst_address.as_u64[0] = d->ip6_src.as_u64[0];
371  args6.dst_address.as_u64[1] = d->ip6_src.as_u64[1];
372  args6.dst_address_length = d->ip6_src_len;
373  args6.adj_index = 0;
374  args6.add_adj = &adj;
375  args6.n_add_adj = 0;
376  ip6_add_del_route (im6, &args6);
377  }
378  p[1]--;
379  }
380  /* Deleting rules */
381  if (d->rules)
382  clib_mem_free (d->rules);
383 
384  pool_put (mm->domains, d);
385 
386  return 0;
387 }
388 
389 int
390 map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
391  u8 is_add)
392 {
393  map_domain_t *d;
394  map_main_t *mm = &map_main;
395 
396  if (pool_is_free_index (mm->domains, map_domain_index))
397  {
398  clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
399  return -1;
400  }
401  d = pool_elt_at_index (mm->domains, map_domain_index);
402 
403  /* Rules are only used in 1:1 independent case */
404  if (d->ea_bits_len > 0)
405  return (-1);
406 
407  if (!d->rules)
408  {
409  u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
411  if (!d->rules)
412  return -1;
413  memset (d->rules, 0, l);
414  }
415 
416  if (psid >= (0x1 << d->psid_length))
417  {
418  clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
419  0x1 << d->psid_length);
420  return -1;
421  }
422 
423  if (is_add)
424  {
425  d->rules[psid] = *tep;
426  }
427  else
428  {
429  memset (&d->rules[psid], 0, sizeof (ip6_address_t));
430  }
431  return 0;
432 }
433 
434 #ifdef MAP_SKIP_IP6_LOOKUP
435 static void
437 {
438  map_main_t *mm = &map_main;
439  ip4_main_t *im4 = &ip4_main;
440  ip6_main_t *im6 = &ip6_main;
441 
442  if (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0)
443  {
444  mm->adj6_index = ip6_fib_lookup_with_table (im6, 0, ip6);
445  clib_warning ("FIB lookup results in: %u", mm->adj6_index);
446  }
447  if (ip4->as_u32 != 0)
448  {
449  mm->adj4_index = ip4_fib_lookup_with_table (im4, 0, ip4, 0);
450  clib_warning ("FIB lookup results in: %u", mm->adj4_index);
451  }
452 }
453 #endif
454 
455 static clib_error_t *
457  unformat_input_t * input,
458  vlib_cli_command_t * cmd)
459 {
460  unformat_input_t _line_input, *line_input = &_line_input;
461  map_main_t *mm = &map_main;
462  /* Get a line of input. */
463  if (!unformat_user (input, unformat_line_input, line_input))
464  return 0;
465 
466  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
467  {
468  if (unformat (line_input, "off"))
469  mm->sec_check = false;
470  else if (unformat (line_input, "on"))
471  mm->sec_check = true;
472  else
473  return clib_error_return (0, "unknown input `%U'",
474  format_unformat_error, input);
475  }
476  unformat_free (line_input);
477  return 0;
478 }
479 
480 static clib_error_t *
482  unformat_input_t * input,
483  vlib_cli_command_t * cmd)
484 {
485  unformat_input_t _line_input, *line_input = &_line_input;
486  map_main_t *mm = &map_main;
487  /* Get a line of input. */
488  if (!unformat_user (input, unformat_line_input, line_input))
489  return 0;
490 
491  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
492  {
493  if (unformat (line_input, "off"))
494  mm->sec_check_frag = false;
495  else if (unformat (line_input, "on"))
496  mm->sec_check_frag = true;
497  else
498  return clib_error_return (0, "unknown input `%U'",
499  format_unformat_error, input);
500  }
501  unformat_free (line_input);
502  return 0;
503 }
504 
505 static clib_error_t *
507  unformat_input_t * input, vlib_cli_command_t * cmd)
508 {
509  unformat_input_t _line_input, *line_input = &_line_input;
510  ip4_address_t ip4_prefix;
511  ip6_address_t ip6_prefix;
512  ip6_address_t ip6_src;
513  u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
514  u32 num_m_args = 0;
515  /* Optional arguments */
516  u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
517  u32 mtu = 0;
518  u8 flags = 0;
519  ip6_src_len = 128;
520 
521  /* Get a line of input. */
522  if (!unformat_user (input, unformat_line_input, line_input))
523  return 0;
524 
525  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
526  {
527  if (unformat
528  (line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix,
529  &ip4_prefix_len))
530  num_m_args++;
531  else
532  if (unformat
533  (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix,
534  &ip6_prefix_len))
535  num_m_args++;
536  else
537  if (unformat
538  (line_input, "ip6-src %U/%d", unformat_ip6_address, &ip6_src,
539  &ip6_src_len))
540  num_m_args++;
541  else
542  if (unformat
543  (line_input, "ip6-src %U", unformat_ip6_address, &ip6_src))
544  num_m_args++;
545  else if (unformat (line_input, "ea-bits-len %d", &ea_bits_len))
546  num_m_args++;
547  else if (unformat (line_input, "psid-offset %d", &psid_offset))
548  num_m_args++;
549  else if (unformat (line_input, "psid-len %d", &psid_length))
550  num_m_args++;
551  else if (unformat (line_input, "mtu %d", &mtu))
552  num_m_args++;
553  else if (unformat (line_input, "map-t"))
554  flags |= MAP_DOMAIN_TRANSLATION;
555  else
556  return clib_error_return (0, "unknown input `%U'",
557  format_unformat_error, input);
558  }
559  unformat_free (line_input);
560 
561  if (num_m_args < 3)
562  return clib_error_return (0, "mandatory argument(s) missing");
563 
564  map_create_domain (&ip4_prefix, ip4_prefix_len,
565  &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
566  ea_bits_len, psid_offset, psid_length, &map_domain_index,
567  mtu, flags);
568 
569  return 0;
570 }
571 
572 static clib_error_t *
574  unformat_input_t * input, vlib_cli_command_t * cmd)
575 {
576  unformat_input_t _line_input, *line_input = &_line_input;
577  u32 num_m_args = 0;
578  u32 map_domain_index;
579 
580  /* Get a line of input. */
581  if (!unformat_user (input, unformat_line_input, line_input))
582  return 0;
583 
584  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
585  {
586  if (unformat (line_input, "index %d", &map_domain_index))
587  num_m_args++;
588  else
589  return clib_error_return (0, "unknown input `%U'",
590  format_unformat_error, input);
591  }
592  unformat_free (line_input);
593 
594  if (num_m_args != 1)
595  return clib_error_return (0, "mandatory argument(s) missing");
596 
597  map_delete_domain (map_domain_index);
598 
599  return 0;
600 }
601 
602 static clib_error_t *
604  unformat_input_t * input, vlib_cli_command_t * cmd)
605 {
606  unformat_input_t _line_input, *line_input = &_line_input;
607  ip6_address_t tep;
608  u32 num_m_args = 0;
609  u32 psid = 0, map_domain_index;
610 
611  /* Get a line of input. */
612  if (!unformat_user (input, unformat_line_input, line_input))
613  return 0;
614 
615  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
616  {
617  if (unformat (line_input, "index %d", &map_domain_index))
618  num_m_args++;
619  else if (unformat (line_input, "psid %d", &psid))
620  num_m_args++;
621  else
622  if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
623  num_m_args++;
624  else
625  return clib_error_return (0, "unknown input `%U'",
626  format_unformat_error, input);
627  }
628  unformat_free (line_input);
629 
630  if (num_m_args != 3)
631  return clib_error_return (0, "mandatory argument(s) missing");
632 
633  if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
634  {
635  return clib_error_return (0, "Failing to add Mapping Rule");
636  }
637  return 0;
638 }
639 
640 #if MAP_SKIP_IP6_LOOKUP
641 static clib_error_t *
643  unformat_input_t * input,
644  vlib_cli_command_t * cmd)
645 {
646  unformat_input_t _line_input, *line_input = &_line_input;
647  ip4_address_t ip4nh;
648  ip6_address_t ip6nh;
649  map_main_t *mm = &map_main;
650 
651  memset (&ip4nh, 0, sizeof (ip4nh));
652  memset (&ip6nh, 0, sizeof (ip6nh));
653 
654  /* Get a line of input. */
655  if (!unformat_user (input, unformat_line_input, line_input))
656  return 0;
657 
658  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
659  {
660  if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
661  mm->preresolve_ip4 = ip4nh;
662  else
663  if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
664  mm->preresolve_ip6 = ip6nh;
665  else
666  return clib_error_return (0, "unknown input `%U'",
667  format_unformat_error, input);
668  }
669  unformat_free (line_input);
670 
671  map_pre_resolve (&ip4nh, &ip6nh);
672 
673  return 0;
674 }
675 #endif
676 
677 static clib_error_t *
679  unformat_input_t * input,
680  vlib_cli_command_t * cmd)
681 {
682  unformat_input_t _line_input, *line_input = &_line_input;
683  ip4_address_t icmp_src_address;
684  map_main_t *mm = &map_main;
685 
686  mm->icmp4_src_address.as_u32 = 0;
687 
688  /* Get a line of input. */
689  if (!unformat_user (input, unformat_line_input, line_input))
690  return 0;
691 
692  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
693  {
694  if (unformat
695  (line_input, "%U", unformat_ip4_address, &icmp_src_address))
696  mm->icmp4_src_address = icmp_src_address;
697  else
698  return clib_error_return (0, "unknown input `%U'",
699  format_unformat_error, input);
700  }
701  unformat_free (line_input);
702 
703  return 0;
704 }
705 
706 static clib_error_t *
708  unformat_input_t * input,
709  vlib_cli_command_t * cmd)
710 {
711  unformat_input_t _line_input, *line_input = &_line_input;
712  map_main_t *mm = &map_main;
713  int num_m_args = 0;
714 
715  /* Get a line of input. */
716  if (!unformat_user (input, unformat_line_input, line_input))
717  return 0;
718 
719  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
720  {
721  num_m_args++;
722  if (unformat (line_input, "on"))
723  mm->icmp6_enabled = true;
724  else if (unformat (line_input, "off"))
725  mm->icmp6_enabled = false;
726  else
727  return clib_error_return (0, "unknown input `%U'",
728  format_unformat_error, input);
729  }
730  unformat_free (line_input);
731 
732 
733  if (num_m_args != 1)
734  return clib_error_return (0, "mandatory argument(s) missing");
735 
736  return 0;
737 }
738 
739 static clib_error_t *
741  unformat_input_t * input, vlib_cli_command_t * cmd)
742 {
743  unformat_input_t _line_input, *line_input = &_line_input;
744  map_main_t *mm = &map_main;
745 
746  /* Get a line of input. */
747  if (!unformat_user (input, unformat_line_input, line_input))
748  return 0;
749 
750  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
751  {
752  if (unformat (line_input, "inner"))
753  mm->frag_inner = true;
754  else if (unformat (line_input, "outer"))
755  mm->frag_inner = false;
756  else
757  return clib_error_return (0, "unknown input `%U'",
758  format_unformat_error, input);
759  }
760  unformat_free (line_input);
761 
762  return 0;
763 }
764 
765 static clib_error_t *
767  unformat_input_t * input,
768  vlib_cli_command_t * cmd)
769 {
770  unformat_input_t _line_input, *line_input = &_line_input;
771  map_main_t *mm = &map_main;
772 
773  /* Get a line of input. */
774  if (!unformat_user (input, unformat_line_input, line_input))
775  return 0;
776 
777  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
778  {
779  if (unformat (line_input, "on"))
780  mm->frag_ignore_df = true;
781  else if (unformat (line_input, "off"))
782  mm->frag_ignore_df = false;
783  else
784  return clib_error_return (0, "unknown input `%U'",
785  format_unformat_error, input);
786  }
787  unformat_free (line_input);
788 
789  return 0;
790 }
791 
792 static clib_error_t *
794  unformat_input_t * input,
795  vlib_cli_command_t * cmd)
796 {
797  unformat_input_t _line_input, *line_input = &_line_input;
798  map_main_t *mm = &map_main;
799  u32 tc = 0;
800 
801  mm->tc_copy = false;
802 
803  /* Get a line of input. */
804  if (!unformat_user (input, unformat_line_input, line_input))
805  return 0;
806 
807  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
808  {
809  if (unformat (line_input, "copy"))
810  mm->tc_copy = true;
811  else if (unformat (line_input, "%x", &tc))
812  mm->tc = tc & 0xff;
813  else
814  return clib_error_return (0, "unknown input `%U'",
815  format_unformat_error, input);
816  }
817  unformat_free (line_input);
818 
819  return 0;
820 }
821 
822 static u8 *
823 format_map_domain (u8 * s, va_list * args)
824 {
825  map_domain_t *d = va_arg (*args, map_domain_t *);
826  bool counters = va_arg (*args, int);
827  map_main_t *mm = &map_main;
828  ip6_address_t ip6_prefix;
829 
830  if (d->rules)
831  memset (&ip6_prefix, 0, sizeof (ip6_prefix));
832  else
833  ip6_prefix = d->ip6_prefix;
834 
835  s = format (s,
836  "[%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",
837  d - mm->domains,
839  format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
841  d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
842  (d->flags & MAP_DOMAIN_TRANSLATION) ? "map-t" : "");
843 
844  if (counters)
845  {
847  vlib_counter_t v;
849  d - mm->domains, &v);
850  s = format (s, " TX: %lld/%lld", v.packets, v.bytes);
852  d - mm->domains, &v);
853  s = format (s, " RX: %lld/%lld", v.packets, v.bytes);
855  }
856  s = format (s, "\n");
857 
858  if (d->rules)
859  {
860  int i;
861  ip6_address_t dst;
862  for (i = 0; i < (0x1 << d->psid_length); i++)
863  {
864  dst = d->rules[i];
865  if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
866  continue;
867  s = format (s,
868  " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
869  &dst);
870  }
871  }
872  return s;
873 }
874 
875 static u8 *
876 format_map_ip4_reass (u8 * s, va_list * args)
877 {
878  map_main_t *mm = &map_main;
879  map_ip4_reass_t *r = va_arg (*args, map_ip4_reass_t *);
880  map_ip4_reass_key_t *k = &r->key;
881  f64 now = vlib_time_now (mm->vlib_main);
882  f64 lifetime = (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000);
883  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
884  s = format (s,
885  "ip4-reass src=%U dst=%U protocol=%d identifier=%d port=%d lifetime=%.3lf\n",
886  format_ip4_address, &k->src.as_u8, format_ip4_address,
887  &k->dst.as_u8, k->protocol,
888  clib_net_to_host_u16 (k->fragment_id),
889  (r->port >= 0) ? clib_net_to_host_u16 (r->port) : -1, dt);
890  return s;
891 }
892 
893 static u8 *
894 format_map_ip6_reass (u8 * s, va_list * args)
895 {
896  map_main_t *mm = &map_main;
897  map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
898  map_ip6_reass_key_t *k = &r->key;
899  f64 now = vlib_time_now (mm->vlib_main);
900  f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
901  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
902  s = format (s,
903  "ip6-reass src=%U dst=%U protocol=%d identifier=%d lifetime=%.3lf\n",
904  format_ip6_address, &k->src.as_u8, format_ip6_address,
905  &k->dst.as_u8, k->protocol,
906  clib_net_to_host_u32 (k->fragment_id), dt);
907  return s;
908 }
909 
910 static clib_error_t *
912  vlib_cli_command_t * cmd)
913 {
914  unformat_input_t _line_input, *line_input = &_line_input;
915  map_main_t *mm = &map_main;
916  map_domain_t *d;
917  bool counters = false;
918  u32 map_domain_index = ~0;
919 
920  /* Get a line of input. */
921  if (!unformat_user (input, unformat_line_input, line_input))
922  return 0;
923 
924  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
925  {
926  if (unformat (line_input, "counters"))
927  counters = true;
928  else if (unformat (line_input, "index %d", &map_domain_index))
929  ;
930  else
931  return clib_error_return (0, "unknown input `%U'",
932  format_unformat_error, input);
933  }
934  unformat_free (line_input);
935 
936  if (pool_elts (mm->domains) == 0)
937  vlib_cli_output (vm, "No MAP domains are configured...");
938 
939  if (map_domain_index == ~0)
940  {
941  /* *INDENT-OFF* */
942  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
943  /* *INDENT-ON* */
944  }
945  else
946  {
947  if (pool_is_free_index (mm->domains, map_domain_index))
948  {
949  return clib_error_return (0, "MAP domain does not exists %d",
950  map_domain_index);
951  }
952 
953  d = pool_elt_at_index (mm->domains, map_domain_index);
954  vlib_cli_output (vm, "%U", format_map_domain, d, counters);
955  }
956 
957  return 0;
958 }
959 
960 static clib_error_t *
962  vlib_cli_command_t * cmd)
963 {
964  map_main_t *mm = &map_main;
965  map_ip4_reass_t *f4;
966  map_ip6_reass_t *f6;
967 
968  /* *INDENT-OFF* */
969  pool_foreach(f4, mm->ip4_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip4_reass, f4);}));
970  /* *INDENT-ON* */
971  /* *INDENT-OFF* */
972  pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
973  /* *INDENT-ON* */
974  return (0);
975 }
976 
977 u64
978 map_error_counter_get (u32 node_index, map_error_t map_error)
979 {
980  vlib_main_t *vm = vlib_get_main ();
981  vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
982  vlib_error_main_t *em = &vm->error_main;
983  vlib_error_t e = error_node->errors[map_error];
984  vlib_node_t *n = vlib_get_node (vm, node_index);
985  u32 ci;
986 
987  ci = vlib_error_get_code (e);
988  ASSERT (ci < n->n_errors);
989  ci += n->error_heap_index;
990 
991  return (em->counters[ci]);
992 }
993 
994 static clib_error_t *
996  vlib_cli_command_t * cmd)
997 {
998  map_main_t *mm = &map_main;
999  map_domain_t *d;
1000  int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1001  if (pool_elts (mm->domains) == 0)
1002  vlib_cli_output (vm, "No MAP domains are configured...");
1003 
1004  /* *INDENT-OFF* */
1005  pool_foreach(d, mm->domains, ({
1006  if (d->rules) {
1007  rulecount+= 0x1 << d->psid_length;
1008  rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1009  }
1010  domains += sizeof(*d);
1011  domaincount++;
1012  }));
1013  /* *INDENT-ON* */
1014 
1015  vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1016  vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1017  vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1018  vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1019 
1020 #if MAP_SKIP_IP6_LOOKUP
1021  vlib_cli_output (vm,
1022  "MAP pre-resolve: IP6 next-hop: %U (%u), IP4 next-hop: %U (%u)\n",
1023  format_ip6_address, &mm->preresolve_ip6, mm->adj6_index,
1024  format_ip4_address, &mm->preresolve_ip4, mm->adj4_index);
1025 #endif
1026 
1027  if (mm->tc_copy)
1028  vlib_cli_output (vm, "MAP traffic-class: copy");
1029  else
1030  vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1031 
1032  vlib_cli_output (vm,
1033  "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1034  mm->sec_check ? "enabled" : "disabled",
1035  mm->sec_check_frag ? "enabled" : "disabled");
1036 
1037  vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1038  format_ip4_address, &mm->icmp4_src_address);
1039  vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1040  mm->icmp6_enabled ? "enabled" : "disabled");
1041  vlib_cli_output (vm, "Inner fragmentation: %s\n",
1042  mm->frag_inner ? "enabled" : "disabled");
1043  vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1044  mm->frag_ignore_df ? "enabled" : "disabled");
1045 
1046  /*
1047  * Counters
1048  */
1049  vlib_combined_counter_main_t *cm = mm->domain_counters;
1050  u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1051  u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1052  int which, i;
1053  vlib_counter_t v;
1054 
1055  memset (total_pkts, 0, sizeof (total_pkts));
1056  memset (total_bytes, 0, sizeof (total_bytes));
1057 
1059  vec_foreach (cm, mm->domain_counters)
1060  {
1061  which = cm - mm->domain_counters;
1062 
1063  for (i = 0; i < vec_len (cm->maxi); i++)
1064  {
1065  vlib_get_combined_counter (cm, i, &v);
1066  total_pkts[which] += v.packets;
1067  total_bytes[which] += v.bytes;
1068  }
1069  }
1071 
1072  vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1073  total_pkts[MAP_DOMAIN_COUNTER_TX],
1074  total_bytes[MAP_DOMAIN_COUNTER_TX]);
1075  vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1076  total_pkts[MAP_DOMAIN_COUNTER_RX],
1077  total_bytes[MAP_DOMAIN_COUNTER_RX]);
1078 
1079  vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1080  vlib_get_simple_counter (&mm->icmp_relayed, 0));
1081 
1082  return 0;
1083 }
1084 
1085 static clib_error_t *
1087  vlib_cli_command_t * cmd)
1088 {
1089  unformat_input_t _line_input, *line_input = &_line_input;
1090  u32 lifetime = ~0;
1091  f64 ht_ratio = (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1);
1092  u32 pool_size = ~0;
1093  u64 buffers = ~(0ull);
1094  u8 ip4 = 0, ip6 = 0;
1095 
1096  if (!unformat_user (input, unformat_line_input, line_input))
1097  return 0;
1098 
1099  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1100  {
1101  if (unformat (line_input, "lifetime %u", &lifetime))
1102  ;
1103  else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1104  ;
1105  else if (unformat (line_input, "pool-size %u", &pool_size))
1106  ;
1107  else if (unformat (line_input, "buffers %llu", &buffers))
1108  ;
1109  else if (unformat (line_input, "ip4"))
1110  ip4 = 1;
1111  else if (unformat (line_input, "ip6"))
1112  ip6 = 1;
1113  else
1114  {
1115  unformat_free (line_input);
1116  return clib_error_return (0, "invalid input");
1117  }
1118  }
1119  unformat_free (line_input);
1120 
1121  if (!ip4 && !ip6)
1122  return clib_error_return (0, "must specify ip4 and/or ip6");
1123 
1124  if (ip4)
1125  {
1126  if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1127  return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1129  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1130  && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1131  return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1133  if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1134  return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1136  if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1137  return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1139  }
1140 
1141  if (ip6)
1142  {
1143  if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1144  return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1146  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1147  && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1148  return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1150  if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1151  return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1153  if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1154  return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1156  }
1157 
1158  if (ip4)
1159  {
1160  u32 reass = 0, packets = 0;
1161  if (pool_size != ~0)
1162  {
1163  if (map_ip4_reass_conf_pool_size (pool_size, &reass, &packets))
1164  {
1165  vlib_cli_output (vm, "Could not set ip4-reass pool-size");
1166  }
1167  else
1168  {
1169  vlib_cli_output (vm,
1170  "Setting ip4-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1171  reass, packets);
1172  }
1173  }
1174  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1175  {
1176  if (map_ip4_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1177  {
1178  vlib_cli_output (vm, "Could not set ip4-reass ht-log2len");
1179  }
1180  else
1181  {
1182  vlib_cli_output (vm,
1183  "Setting ip4-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1184  reass, packets);
1185  }
1186  }
1187  if (lifetime != ~0)
1188  {
1189  if (map_ip4_reass_conf_lifetime (lifetime))
1190  vlib_cli_output (vm, "Could not set ip4-reass lifetime");
1191  else
1192  vlib_cli_output (vm, "Setting ip4-reass lifetime");
1193  }
1194  if (buffers != ~(0ull))
1195  {
1196  if (map_ip4_reass_conf_buffers (buffers))
1197  vlib_cli_output (vm, "Could not set ip4-reass buffers");
1198  else
1199  vlib_cli_output (vm, "Setting ip4-reass buffers");
1200  }
1201 
1205  {
1206  vlib_cli_output (vm,
1207  "Note: 'ip4-reass buffers' > pool-size * max-fragments-per-reassembly.");
1208  }
1209  }
1210 
1211  if (ip6)
1212  {
1213  u32 reass = 0, packets = 0;
1214  if (pool_size != ~0)
1215  {
1216  if (map_ip6_reass_conf_pool_size (pool_size, &reass, &packets))
1217  {
1218  vlib_cli_output (vm, "Could not set ip6-reass pool-size");
1219  }
1220  else
1221  {
1222  vlib_cli_output (vm,
1223  "Setting ip6-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1224  reass, packets);
1225  }
1226  }
1227  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1228  {
1229  if (map_ip6_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1230  {
1231  vlib_cli_output (vm, "Could not set ip6-reass ht-log2len");
1232  }
1233  else
1234  {
1235  vlib_cli_output (vm,
1236  "Setting ip6-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1237  reass, packets);
1238  }
1239  }
1240  if (lifetime != ~0)
1241  {
1242  if (map_ip6_reass_conf_lifetime (lifetime))
1243  vlib_cli_output (vm, "Could not set ip6-reass lifetime");
1244  else
1245  vlib_cli_output (vm, "Setting ip6-reass lifetime");
1246  }
1247  if (buffers != ~(0ull))
1248  {
1249  if (map_ip6_reass_conf_buffers (buffers))
1250  vlib_cli_output (vm, "Could not set ip6-reass buffers");
1251  else
1252  vlib_cli_output (vm, "Setting ip6-reass buffers");
1253  }
1254 
1258  {
1259  vlib_cli_output (vm,
1260  "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1261  }
1262  }
1263 
1264  return 0;
1265 }
1266 
1267 
1268 /*
1269  * packet trace format function
1270  */
1271 u8 *
1272 format_map_trace (u8 * s, va_list * args)
1273 {
1274  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1275  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1276  map_trace_t *t = va_arg (*args, map_trace_t *);
1277  u32 map_domain_index = t->map_domain_index;
1278  u16 port = t->port;
1279 
1280  s =
1281  format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1282  clib_net_to_host_u16 (port));
1283 
1284  return s;
1285 }
1286 
1289 {
1290  map_main_t *mm = &map_main;
1291  u32 ri = mm->ip4_reass_hash_table[bucket];
1292  while (ri != MAP_REASS_INDEX_NONE)
1293  {
1295  if (r->key.as_u64[0] == k->as_u64[0] &&
1296  r->key.as_u64[1] == k->as_u64[1] &&
1297  now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1298  {
1299  return r;
1300  }
1301  ri = r->bucket_next;
1302  }
1303  return NULL;
1304 }
1305 
1306 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1307 
1308 void
1310 {
1311  map_main_t *mm = &map_main;
1312  map_ip4_reass_get_fragments (r, pi_to_drop);
1313 
1314  // Unlink in hash bucket
1315  map_ip4_reass_t *r2 = NULL;
1316  u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1317  while (r2i != map_ip4_reass_pool_index (r))
1318  {
1319  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1320  r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1321  r2i = r2->bucket_next;
1322  }
1323  if (r2)
1324  {
1325  r2->bucket_next = r->bucket_next;
1326  }
1327  else
1328  {
1330  }
1331 
1332  // Unlink in list
1333  if (r->fifo_next == map_ip4_reass_pool_index (r))
1334  {
1336  }
1337  else
1338  {
1340  mm->ip4_reass_fifo_last = r->fifo_prev;
1341  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1342  r->fifo_next;
1343  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1344  r->fifo_prev;
1345  }
1346 
1347  pool_put (mm->ip4_reass_pool, r);
1348  mm->ip4_reass_allocated--;
1349 }
1350 
1352 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1353  u8 protocol, u32 ** pi_to_drop)
1354 {
1355  map_ip4_reass_t *r;
1356  map_main_t *mm = &map_main;
1357  map_ip4_reass_key_t k = {.src.data_u32 = src,
1358  .dst.data_u32 = dst,
1359  .fragment_id = fragment_id,
1360  .protocol = protocol
1361  };
1362 
1363  u32 h = 0;
1364  h = crc_u32 (k.as_u32[0], h);
1365  h = crc_u32 (k.as_u32[1], h);
1366  h = crc_u32 (k.as_u32[2], h);
1367  h = crc_u32 (k.as_u32[3], h);
1368  h = h >> (32 - mm->ip4_reass_ht_log2len);
1369 
1370  f64 now = vlib_time_now (mm->vlib_main);
1371 
1372  //Cache garbage collection
1374  {
1377  if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1378  map_ip4_reass_free (last, pi_to_drop);
1379  else
1380  break;
1381  }
1382 
1383  if ((r = map_ip4_reass_lookup (&k, h, now)))
1384  return r;
1385 
1387  return NULL;
1388 
1389  pool_get (mm->ip4_reass_pool, r);
1390  mm->ip4_reass_allocated++;
1391  int i;
1392  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1393  r->fragments[i] = ~0;
1394 
1395  u32 ri = map_ip4_reass_pool_index (r);
1396 
1397  //Link in new bucket
1398  r->bucket = h;
1399  r->bucket_next = mm->ip4_reass_hash_table[h];
1400  mm->ip4_reass_hash_table[h] = ri;
1401 
1402  //Link in fifo
1404  {
1405  r->fifo_next =
1407  mm->ip4_reass_fifo_last)->fifo_next;
1408  r->fifo_prev = mm->ip4_reass_fifo_last;
1409  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1410  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1411  }
1412  else
1413  {
1414  r->fifo_next = r->fifo_prev = ri;
1415  mm->ip4_reass_fifo_last = ri;
1416  }
1417 
1418  //Set other fields
1419  r->ts = now;
1420  r->key = k;
1421  r->port = -1;
1422 #ifdef MAP_IP4_REASS_COUNT_BYTES
1423  r->expected_total = 0xffff;
1424  r->forwarded = 0;
1425 #endif
1426 
1427  return r;
1428 }
1429 
1430 int
1432 {
1434  return -1;
1435 
1436  int i;
1437  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1438  if (r->fragments[i] == ~0)
1439  {
1440  r->fragments[i] = pi;
1442  return 0;
1443  }
1444  return -1;
1445 }
1446 
1449 {
1450  map_main_t *mm = &map_main;
1451  u32 ri = mm->ip6_reass_hash_table[bucket];
1452  while (ri != MAP_REASS_INDEX_NONE)
1453  {
1455  if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1456  r->key.as_u64[0] == k->as_u64[0] &&
1457  r->key.as_u64[1] == k->as_u64[1] &&
1458  r->key.as_u64[2] == k->as_u64[2] &&
1459  r->key.as_u64[3] == k->as_u64[3] &&
1460  r->key.as_u64[4] == k->as_u64[4])
1461  return r;
1462  ri = r->bucket_next;
1463  }
1464  return NULL;
1465 }
1466 
1467 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1468 
1469 void
1471 {
1472  map_main_t *mm = &map_main;
1473  int i;
1474  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1475  if (r->fragments[i].pi != ~0)
1476  {
1477  vec_add1 (*pi_to_drop, r->fragments[i].pi);
1478  r->fragments[i].pi = ~0;
1480  }
1481 
1482  // Unlink in hash bucket
1483  map_ip6_reass_t *r2 = NULL;
1484  u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1485  while (r2i != map_ip6_reass_pool_index (r))
1486  {
1487  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1488  r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1489  r2i = r2->bucket_next;
1490  }
1491  if (r2)
1492  {
1493  r2->bucket_next = r->bucket_next;
1494  }
1495  else
1496  {
1498  }
1499 
1500  // Unlink in list
1501  if (r->fifo_next == map_ip6_reass_pool_index (r))
1502  {
1503  //Single element in the list, list is now empty
1505  }
1506  else
1507  {
1508  if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r)) //First element
1509  mm->ip6_reass_fifo_last = r->fifo_prev;
1510  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1511  r->fifo_next;
1512  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1513  r->fifo_prev;
1514  }
1515 
1516  // Free from pool if necessary
1517  pool_put (mm->ip6_reass_pool, r);
1518  mm->ip6_reass_allocated--;
1519 }
1520 
1523  u8 protocol, u32 ** pi_to_drop)
1524 {
1525  map_ip6_reass_t *r;
1526  map_main_t *mm = &map_main;
1527  map_ip6_reass_key_t k = {
1528  .src = *src,
1529  .dst = *dst,
1530  .fragment_id = fragment_id,
1531  .protocol = protocol
1532  };
1533 
1534  u32 h = 0;
1535  int i;
1536  for (i = 0; i < 10; i++)
1537  h = crc_u32 (k.as_u32[i], h);
1538  h = h >> (32 - mm->ip6_reass_ht_log2len);
1539 
1540  f64 now = vlib_time_now (mm->vlib_main);
1541 
1542  //Cache garbage collection
1544  {
1547  if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1548  map_ip6_reass_free (last, pi_to_drop);
1549  else
1550  break;
1551  }
1552 
1553  if ((r = map_ip6_reass_lookup (&k, h, now)))
1554  return r;
1555 
1557  return NULL;
1558 
1559  pool_get (mm->ip6_reass_pool, r);
1560  mm->ip6_reass_allocated++;
1561  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1562  {
1563  r->fragments[i].pi = ~0;
1564  r->fragments[i].next_data_len = 0;
1565  r->fragments[i].next_data_offset = 0;
1566  }
1567 
1568  u32 ri = map_ip6_reass_pool_index (r);
1569 
1570  //Link in new bucket
1571  r->bucket = h;
1572  r->bucket_next = mm->ip6_reass_hash_table[h];
1573  mm->ip6_reass_hash_table[h] = ri;
1574 
1575  //Link in fifo
1577  {
1578  r->fifo_next =
1580  mm->ip6_reass_fifo_last)->fifo_next;
1581  r->fifo_prev = mm->ip6_reass_fifo_last;
1582  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1583  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1584  }
1585  else
1586  {
1587  r->fifo_next = r->fifo_prev = ri;
1588  mm->ip6_reass_fifo_last = ri;
1589  }
1590 
1591  //Set other fields
1592  r->ts = now;
1593  r->key = k;
1595 #ifdef MAP_IP6_REASS_COUNT_BYTES
1596  r->expected_total = 0xffff;
1597  r->forwarded = 0;
1598 #endif
1599  return r;
1600 }
1601 
1602 int
1604  u16 data_offset, u16 next_data_offset,
1605  u8 * data_start, u16 data_len)
1606 {
1607  map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1608  u16 copied_len = (data_len > 20) ? 20 : data_len;
1609 
1611  return -1;
1612 
1613  //Lookup for fragments for the current buffer
1614  //and the one before that
1615  int i;
1616  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1617  {
1618  if (data_offset && r->fragments[i].next_data_offset == data_offset)
1619  {
1620  prev_f = &r->fragments[i]; // This is buffer for previous packet
1621  }
1622  else if (r->fragments[i].next_data_offset == next_data_offset)
1623  {
1624  f = &r->fragments[i]; // This is a buffer for the current packet
1625  }
1626  else if (r->fragments[i].next_data_offset == 0)
1627  { //Available
1628  if (f == NULL)
1629  f = &r->fragments[i];
1630  else if (prev_f == NULL)
1631  prev_f = &r->fragments[i];
1632  }
1633  }
1634 
1635  if (!f || f->pi != ~0)
1636  return -1;
1637 
1638  if (data_offset)
1639  {
1640  if (!prev_f)
1641  return -1;
1642 
1643  clib_memcpy (prev_f->next_data, data_start, copied_len);
1644  prev_f->next_data_len = copied_len;
1645  prev_f->next_data_offset = data_offset;
1646  }
1647  else
1648  {
1649  if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1650  return -1;
1651 
1653  clib_memcpy (&r->ip4_header, data_start, sizeof (ip4_header_t));
1654  }
1655 
1656  if (data_len > 20)
1657  {
1658  f->next_data_offset = next_data_offset;
1659  f->pi = pi;
1661  }
1662  return 0;
1663 }
1664 
1665 void
1666 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1667 {
1668  map_main_t *mm = &map_main;
1669  int i;
1670 
1671  if (dropped_packets)
1672  *dropped_packets = mm->ip4_reass_buffered_counter;
1673  if (trashed_reass)
1674  *trashed_reass = mm->ip4_reass_allocated;
1676  {
1677  u16 ri = mm->ip4_reass_fifo_last;
1678  do
1679  {
1681  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1682  if (r->fragments[i] != ~0)
1683  map_ip4_drop_pi (r->fragments[i]);
1684 
1685  ri = r->fifo_next;
1686  pool_put (mm->ip4_reass_pool, r);
1687  }
1688  while (ri != mm->ip4_reass_fifo_last);
1689  }
1690 
1693  for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1695  pool_free (mm->ip4_reass_pool);
1697 
1698  mm->ip4_reass_allocated = 0;
1701 }
1702 
1703 u8
1704 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1705 {
1706  u32 desired_size = (u32) (pool_size * ht_ratio);
1707  u8 i;
1708  for (i = 1; i < 31; i++)
1709  if ((1 << i) >= desired_size)
1710  return i;
1711  return 4;
1712 }
1713 
1714 int
1715 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1716  u32 * dropped_packets)
1717 {
1718  map_main_t *mm = &map_main;
1719  if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1720  return -1;
1721 
1722  map_ip4_reass_lock ();
1723  mm->ip4_reass_conf_ht_ratio = ht_ratio;
1724  mm->ip4_reass_ht_log2len =
1726  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1728  return 0;
1729 }
1730 
1731 int
1732 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1733  u32 * dropped_packets)
1734 {
1735  map_main_t *mm = &map_main;
1736  if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1737  return -1;
1738 
1739  map_ip4_reass_lock ();
1740  mm->ip4_reass_conf_pool_size = pool_size;
1741  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1743  return 0;
1744 }
1745 
1746 int
1748 {
1749  map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1750  return 0;
1751 }
1752 
1753 int
1755 {
1756  map_main.ip4_reass_conf_buffers = buffers;
1757  return 0;
1758 }
1759 
1760 void
1761 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1762 {
1763  map_main_t *mm = &map_main;
1764  if (dropped_packets)
1765  *dropped_packets = mm->ip6_reass_buffered_counter;
1766  if (trashed_reass)
1767  *trashed_reass = mm->ip6_reass_allocated;
1768  int i;
1770  {
1771  u16 ri = mm->ip6_reass_fifo_last;
1772  do
1773  {
1775  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1776  if (r->fragments[i].pi != ~0)
1777  map_ip6_drop_pi (r->fragments[i].pi);
1778 
1779  ri = r->fifo_next;
1780  pool_put (mm->ip6_reass_pool, r);
1781  }
1782  while (ri != mm->ip6_reass_fifo_last);
1784  }
1785 
1788  for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1790  pool_free (mm->ip6_reass_pool);
1792 
1793  mm->ip6_reass_allocated = 0;
1795 }
1796 
1797 int
1798 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1799  u32 * dropped_packets)
1800 {
1801  map_main_t *mm = &map_main;
1802  if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1803  return -1;
1804 
1805  map_ip6_reass_lock ();
1806  mm->ip6_reass_conf_ht_ratio = ht_ratio;
1807  mm->ip6_reass_ht_log2len =
1809  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1811  return 0;
1812 }
1813 
1814 int
1815 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1816  u32 * dropped_packets)
1817 {
1818  map_main_t *mm = &map_main;
1819  if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1820  return -1;
1821 
1822  map_ip6_reass_lock ();
1823  mm->ip6_reass_conf_pool_size = pool_size;
1824  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1826  return 0;
1827 }
1828 
1829 int
1831 {
1832  map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1833  return 0;
1834 }
1835 
1836 int
1838 {
1839  map_main.ip6_reass_conf_buffers = buffers;
1840  return 0;
1841 }
1842 
1843 /* *INDENT-OFF* */
1845  .path = "map params reassembly",
1846  .short_help = "[ip4 | ip6] [lifetime <lifetime-ms>] [pool-size <pool-size>] [buffers <buffers>] [ht-ratio <ht-ratio>]",
1847  .function = map_params_reass_command_fn,
1848 };
1849 /* *INDENT-ON* */
1850 
1851 /* *INDENT-OFF* */
1853  .path = "map params traffic-class",
1854  .short_help =
1855  "traffic-class {0x0-0xff | copy}",
1856  .function = map_traffic_class_command_fn,
1857 };
1858 /* *INDENT-ON* */
1859 
1860 /* *INDENT-OFF* */
1862  .path = "map params pre-resolve",
1863  .short_help =
1864  "pre-resolve {ip4-nh <address>} | {ip6-nh <address>}",
1865  .function = map_pre_resolve_command_fn,
1866 };
1867 /* *INDENT-ON* */
1868 
1869 /* *INDENT-OFF* */
1871  .path = "map params security-check",
1872  .short_help =
1873  "security-check on|off",
1874  .function = map_security_check_command_fn,
1875 };
1876 /* *INDENT-ON* */
1877 
1878 /* *INDENT-OFF* */
1880  .path = "map params icmp source-address",
1881  .short_help = "source-address <ip4-address>",
1883 };
1884 /* *INDENT-ON* */
1885 
1886 /* *INDENT-OFF* */
1888  .path = "map params icmp6 unreachables",
1889  .short_help = "unreachables {on|off}",
1891 };
1892 /* *INDENT-ON* */
1893 
1894 /* *INDENT-OFF* */
1896  .path = "map params fragment",
1897  .short_help = "[inner|outer] [ignore-df [on|off]]",
1898  .function = map_fragment_command_fn,
1899 };
1900 /* *INDENT-ON* */
1901 
1902 /* *INDENT-OFF* */
1904  .path = "map params fragment ignore-df",
1905  .short_help = "on|off",
1906  .function = map_fragment_df_command_fn,
1907 };
1908 /* *INDENT-ON* */
1909 
1910 /* *INDENT-OFF* */
1912  .path = "map params security-check fragments",
1913  .short_help =
1914  "fragments on|off",
1916 };
1917 /* *INDENT-ON* */
1918 
1919 /* *INDENT-OFF* */
1921  .path = "map add domain",
1922  .short_help =
1923  "map add domain ip4-pfx <ip4-pfx> ip6-pfx <ip6-pfx> ip6-src <ip6-pfx> "
1924  "ea-bits-len <n> psid-offset <n> psid-len <n> [map-t] [mtu <mtu>]",
1925  .function = map_add_domain_command_fn,
1926 };
1927 /* *INDENT-ON* */
1928 
1929 /* *INDENT-OFF* */
1931  .path = "map add rule",
1932  .short_help =
1933  "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
1934  .function = map_add_rule_command_fn,
1935 };
1936 /* *INDENT-ON* */
1937 
1938 /* *INDENT-OFF* */
1940  .path = "map del domain",
1941  .short_help =
1942  "map del domain index <domain>",
1943  .function = map_del_domain_command_fn,
1944 };
1945 /* *INDENT-ON* */
1946 
1947 /* *INDENT-OFF* */
1949  .path = "show map domain",
1950  .function = show_map_domain_command_fn,
1951 };
1952 /* *INDENT-ON* */
1953 
1954 /* *INDENT-OFF* */
1956  .path = "show map stats",
1957  .function = show_map_stats_command_fn,
1958 };
1959 /* *INDENT-ON* */
1960 
1961 /* *INDENT-OFF* */
1963  .path = "show map fragments",
1964  .function = show_map_fragments_command_fn,
1965 };
1966 /* *INDENT-ON* */
1967 
1968 /*
1969  * map_init
1970  */
1971 clib_error_t *
1973 {
1974  map_main_t *mm = &map_main;
1975  mm->vnet_main = vnet_get_main ();
1976  mm->vlib_main = vm;
1977 
1978 #ifdef MAP_SKIP_IP6_LOOKUP
1979  memset (&mm->preresolve_ip4, 0, sizeof (mm->preresolve_ip4));
1980  memset (&mm->preresolve_ip6, 0, sizeof (mm->preresolve_ip6));
1981  mm->adj4_index = 0;
1982  mm->adj6_index = 0;
1983 #endif
1984 
1985  /* traffic class */
1986  mm->tc = 0;
1987  mm->tc_copy = true;
1988 
1989  /* Inbound security check */
1990  mm->sec_check = true;
1991  mm->sec_check_frag = false;
1992 
1993  /* ICMP6 Type 1, Code 5 for security check failure */
1994  mm->icmp6_enabled = false;
1995 
1996  /* Inner or outer fragmentation */
1997  mm->frag_inner = false;
1998  mm->frag_ignore_df = false;
1999 
2003 
2006 
2007  /* IP4 virtual reassembly */
2008  mm->ip4_reass_hash_table = 0;
2009  mm->ip4_reass_pool = 0;
2010  mm->ip4_reass_lock =
2016  mm->ip4_reass_ht_log2len =
2021 
2022  /* IP6 virtual reassembly */
2023  mm->ip6_reass_hash_table = 0;
2024  mm->ip6_reass_pool = 0;
2025  mm->ip6_reass_lock =
2031  mm->ip6_reass_ht_log2len =
2036 
2037  return 0;
2038 }
2039 
2041 
2042 /*
2043  * fd.io coding-style-patch-verification: ON
2044  *
2045  * Local Variables:
2046  * eval: (c-set-style "gnu")
2047  * End:
2048  */
u16 forwarded
Definition: map.h:183
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
#define map_ip4_reass_lock()
Definition: map.h:442
u8 psid_length
Definition: map.h:97
static vlib_cli_command_t map_ip4_reass_lifetime_command
(constructor) VLIB_CLI_COMMAND (map_ip4_reass_lifetime_command)
Definition: map.c:1844
map_ip4_reass_t * ip4_reass_pool
Definition: map.h:235
u64 packets
packet counter
Definition: counter.h:166
u32 ip4_reass_conf_buffers
Definition: map.h:232
static vlib_cli_command_t map_icmp_relay_source_address_command
(constructor) VLIB_CLI_COMMAND (map_icmp_relay_source_address_command)
Definition: map.c:1879
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:740
#define CLIB_UNUSED(x)
Definition: clib.h:79
#define MAP_IP6_REASS_CONF_BUFFERS_MAX
Definition: map.h:494
u32 as_u32[4]
Definition: map.h:122
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
int map_delete_domain(u32 map_domain_index)
Definition: map.c:320
#define MAP_IP6_REASS_BUFFERS_DEFAULT
Definition: map.h:70
map_domain_flags_e flags
Definition: map.h:92
u16 fifo_prev
Definition: map.h:187
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:110
u16 ip4_reass_allocated
Definition: map.h:237
volatile u32 * ip6_reass_lock
Definition: map.h:263
format_function_t format_ip6_address
Definition: format.h:87
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 ip4_reass_ht_log2len
Definition: map.h:236
u32 fragments[MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:139
#define MAP_IP6_REASS_LIFETIME_DEFAULT
Definition: map.h:67
static_always_inline map_ip6_reass_t * map_ip6_reass_lookup(map_ip6_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1448
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:247
u16 bucket_next
Definition: map.h:186
ip_lookup_next_t lookup_next_index
Definition: lookup.h:180
#define PREDICT_TRUE(x)
Definition: clib.h:98
u64 as_u64[2]
Definition: ip6_packet.h:50
IP unicast adjacency.
Definition: lookup.h:164
map_error_t
Definition: map.h:292
#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:823
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:911
void map_ip4_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1666
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:456
u64 map_error_counter_get(u32 node_index, map_error_t map_error)
Definition: map.c:978
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:497
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:766
vlib_main_t * vlib_main
Definition: map.h:222
u8 tc
Definition: map.h:210
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:961
i32 ip6_get_port(ip6_header_t *ip6, map_dir_e dir, u16 buffer_len)
Definition: map.c:110
#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:545
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:88
bool sec_check_frag
Definition: map.h:214
u32 ip4_reass_buffered_counter
Definition: map.h:243
static u8 * format_map_ip4_reass(u8 *s, va_list *args)
Definition: map.c:876
ip6_address_t preresolve_ip6
Definition: map.h:206
static u32 crc_u32(u32 data, u32 value)
Definition: map.c:24
vlib_error_t * errors
Definition: node.h:418
u16 ip4_reass_fifo_last
Definition: map.h:239
#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:71
static vlib_cli_command_t show_map_domain_command
(constructor) VLIB_CLI_COMMAND (show_map_domain_command)
Definition: map.c:1948
int map_ip6_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1798
#define MAP_IP6_REASS_CONF_LIFETIME_MAX
Definition: map.h:492
u64 as_u64[5]
Definition: map.h:166
map_ip6_reass_t * ip6_reass_pool
Definition: map.h:258
map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:190
u16 port
Definition: map.h:303
ip4_address_t preresolve_ip4
Definition: map.h:205
#define map_ip6_reass_unlock()
Definition: map.h:466
float f32
Definition: types.h:143
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:65
bool tc_copy
Definition: map.h:211
#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:642
#define MAP_REASS_INDEX_NONE
Definition: map.h:108
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
map_ip4_reass_key_t key
Definition: map.h:128
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:707
u16 bucket
Definition: map.h:185
vlib_combined_counter_main_t * domain_counters
Definition: map.h:199
static vlib_cli_command_t show_map_fragments_command
(constructor) VLIB_CLI_COMMAND (show_map_fragments_command)
Definition: map.c:1962
static int ip4_get_fragment_offset(ip4_header_t *i)
Definition: ip4_packet.h:162
ip4_address_t icmp4_src_address
Definition: map.h:218
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:506
int i32
Definition: types.h:81
static vlib_cli_command_t map_del_command
(constructor) VLIB_CLI_COMMAND (map_del_command)
Definition: map.c:1939
u16 fifo_next
Definition: map.h:138
u32 ip4_fib_lookup_with_table(ip4_main_t *im, u32 fib_index, ip4_address_t *dst, u32 disable_default_route)
Definition: ip4_forward.c:58
vlib_simple_counter_main_t icmp_relayed
Definition: map.h:219
int map_ip4_reass_add_fragment(map_ip4_reass_t *r, u32 pi)
Definition: map.c:1431
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
ip6_address_t * rules
Definition: map.h:87
#define clib_warning(format, args...)
Definition: error.h:59
u32 table_index_or_table_id
Definition: ip6.h:367
unsigned long u64
Definition: types.h:89
u8 map_get_ht_log2len(f32 ht_ratio, u16 pool_size)
Definition: map.c:1704
#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:95
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
u8 ip6_prefix_len
Definition: map.h:93
#define MAP_IP4_REASS_CONF_LIFETIME_MAX
Definition: map.h:480
void ip6_add_del_route(ip6_main_t *im, ip6_add_del_route_args_t *args)
Definition: ip6_forward.c:208
static_always_inline map_ip4_reass_t * map_ip4_reass_lookup(map_ip4_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1288
u16 ip6_reass_allocated
Definition: map.h:260
int map_add_del_psid(u32 map_domain_index, u16 psid, ip6_address_t *tep, u8 is_add)
Definition: map.c:390
unformat_function_t unformat_ip4_address
Definition: format.h:68
#define MAP_IP6_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:490
ip6_address_t dst_address
Definition: ip6.h:370
#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:1837
u32 vlib_error_t
Definition: error.h:44
#define map_ip4_reass_pool_index(r)
Definition: map.c:1306
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:603
int map_ip4_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1747
vlib_error_main_t error_main
Definition: main.h:124
static u32 vlib_error_get_code(vlib_error_t e)
Definition: error.h:53
#define MAP_IP4_REASS_BUFFERS_DEFAULT
Definition: map.h:63
void * ip4_get_route(ip4_main_t *im, u32 fib_index_or_table_id, u32 flags, u8 *address, u32 address_length)
Definition: ip4_forward.c:537
#define MAP_IP4_REASS_CONF_HT_RATIO_MAX
Definition: map.h:476
static u8 * format_map_ip6_reass(u8 *s, va_list *args)
Definition: map.c:894
bool frag_ignore_df
Definition: map.h:246
volatile u32 * ip4_reass_lock
Definition: map.h:240
u16 ip4_reass_conf_pool_size
Definition: map.h:230
map_domain_t * domains
Definition: map.h:195
u16 bucket
Definition: map.h:135
ip_adjacency_t * add_adj
Definition: ip6.h:379
This packet needs to go to MAP - RFC7596, RFC7597.
Definition: lookup.h:84
static vlib_cli_command_t map_add_domain_command
(constructor) VLIB_CLI_COMMAND (map_add_domain_command)
Definition: map.c:1920
int map_ip4_reass_conf_buffers(u32 buffers)
Definition: map.c:1754
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
int map_ip6_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1830
map_ip4_reass_t * map_ip4_reass_get(u32 src, u32 dst, u16 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1352
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:1732
u16 * ip6_reass_hash_table
Definition: map.h:261
u16 * ip4_reass_hash_table
Definition: map.h:238
u32 ip6_get_route(ip6_main_t *im, u32 fib_index_or_table_id, u32 flags, ip6_address_t *address, u32 address_length)
Definition: ip6_forward.c:572
static vlib_cli_command_t map_fragment_command
(constructor) VLIB_CLI_COMMAND (map_fragment_command)
Definition: map.c:1895
map_main_t map_main
Definition: map.h:306
i32 ip4_get_port(ip4_header_t *ip, map_dir_e dir, u16 buffer_len)
Definition: map.c:66
#define MAP_IP4_REASS_HT_RATIO_DEFAULT
Definition: map.h:61
u8 ip6_src_len
Definition: map.h:94
u8 psid_shift
Definition: map.h:100
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
u16 expected_total
Definition: map.h:131
unformat_function_t unformat_ip6_address
Definition: format.h:86
ip_adjacency_t * add_adj
Definition: ip4.h:337
u8 suffix_shift
Definition: map.h:101
#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:259
u16 ip6_reass_fifo_last
Definition: map.h:262
#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:1309
u64 * counters
Definition: error.h:78
static vlib_cli_command_t map_icmp_unreachables_command
(constructor) VLIB_CLI_COMMAND (map_icmp_unreachables_command)
Definition: map.c:1887
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:1086
static vlib_cli_command_t map_pre_resolve_command
(constructor) VLIB_CLI_COMMAND (map_pre_resolve_command)
Definition: map.c:1861
u16 ip6_reass_conf_pool_size
Definition: map.h:253
map_dir_e
Definition: map.h:23
u8 next_data_len
Definition: map.h:174
ip4_address_t ip4_prefix
Definition: map.h:89
u16 next_data_offset
Definition: map.h:173
static_always_inline void map_ip4_reass_get_fragments(map_ip4_reass_t *r, u32 **pi)
Definition: map.h:446
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:1522
#define MAP_IP6_REASS_POOL_SIZE_DEFAULT
Definition: map.h:69
u32 as_u32[10]
Definition: map.h:167
#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:152
u64 bytes
byte counter
Definition: counter.h:167
u8 psid_offset
Definition: map.h:96
static vlib_cli_command_t map_security_check_frag_command
(constructor) VLIB_CLI_COMMAND (map_security_check_frag_command)
Definition: map.c:1911
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:678
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:132
static vlib_cli_command_t map_fragment_df_command
(constructor) VLIB_CLI_COMMAND (map_fragment_df_command)
Definition: map.c:1903
#define clib_memcpy(a, b, c)
Definition: string.h:63
bool icmp6_enabled
Definition: map.h:215
u32 ip6_fib_lookup_with_table(ip6_main_t *im, u32 fib_index, ip6_address_t *dst)
Definition: ip6_forward.c:61
#define IP6_ROUTE_FLAG_DEL
Definition: ip6.h:352
map_ip6_reass_key_t key
Definition: map.h:179
#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:85
u32 adj4_index
Definition: map.h:204
#define IP4_ROUTE_FLAG_DEL
Definition: ip4.h:309
int map_ip4_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1715
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:573
static void map_domain_counter_lock(map_main_t *mm)
Definition: map.h:538
f32 ip4_reass_conf_ht_ratio
Definition: map.h:229
static vlib_cli_command_t map_security_check_command
(constructor) VLIB_CLI_COMMAND (map_security_check_command)
Definition: map.c:1870
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:390
int map_ip6_reass_conf_pool_size(u16 pool_size, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1815
#define ASSERT(truth)
#define u8_ptr_add(ptr, index)
Definition: map.h:515
unsigned int u32
Definition: types.h:88
bool sec_check
Definition: map.h:213
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip4_address_t dst_address
Definition: ip4.h:328
#define IP4_ROUTE_FLAG_ADD
Definition: ip4.h:308
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
bool frag_inner
Definition: map.h:245
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
u16 psid_mask
Definition: map.h:90
IPv4 main type.
Definition: ip4.h:114
void map_ip6_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1761
static void clib_mem_free(void *p)
Definition: mem.h:154
ip4_header_t ip4_header
Definition: map.h:189
#define map_ip4_reass_unlock()
Definition: map.h:443
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:1272
#define MAP_IP6_REASS_HT_RATIO_DEFAULT
Definition: map.h:68
u8 ea_shift
Definition: map.h:102
ip6_address_t ip6_prefix
Definition: map.h:86
u64 uword
Definition: types.h:112
f32 ip6_reass_conf_ht_ratio
Definition: map.h:252
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:793
vnet_main_t * vnet_main
Definition: map.h:223
unsigned short u16
Definition: types.h:57
u16 mtu
Definition: map.h:91
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
static vlib_cli_command_t show_map_stats_command
(constructor) VLIB_CLI_COMMAND (show_map_stats_command)
Definition: map.c:1955
#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:254
unsigned char u8
Definition: types.h:56
#define map_ip6_reass_lock()
Definition: map.h:465
u32 adj6_index
Definition: map.h:204
static vlib_cli_command_t map_traffic_class_command
(constructor) VLIB_CLI_COMMAND (map_traffic_class_command)
Definition: map.c:1852
i32 port
Definition: map.h:134
#define MAP_IP4_REASS_POOL_SIZE_DEFAULT
Definition: map.h:62
#define MAP_IP6_REASS_CONF_HT_RATIO_MAX
Definition: map.h:488
char * name
The counter collection&#39;s name.
Definition: counter.h:219
u32 table_index_or_table_id
Definition: ip4.h:325
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:60
u16 bucket_next
Definition: map.h:136
#define MAP_IP4_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:478
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:105
void map_ip6_reass_free(map_ip6_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1470
vlib_simple_counter_main_t * simple_domain_counters
Definition: map.h:198
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:114
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
#define MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:72
#define IP6_ROUTE_FLAG_ADD
Definition: ip6.h:351
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
u16 ip4_reass_conf_lifetime_ms
Definition: map.h:231
#define vec_foreach(var, vec)
Vector iterator.
i16 explicit_fib_index
Force re-lookup in a different FIB.
Definition: lookup.h:185
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:481
u32 map_domain_index
Definition: map.h:302
#define MAP_IP4_REASS_CONF_BUFFERS_MAX
Definition: map.h:482
u64 as_u64[2]
Definition: map.h:121
#define clib_error_return(e, args...)
Definition: error.h:111
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
u16 fifo_prev
Definition: map.h:137
struct _unformat_input_t unformat_input_t
Definition: map.h:25
void ip4_add_del_route(ip4_main_t *im, ip4_add_del_route_args_t *args)
Definition: ip4_forward.c:228
This packet needs to go to MAP with Translation - RFC7599.
Definition: lookup.h:87
u32 flags
Definition: vhost-user.h:76
u32 ip6_reass_buffered_counter
Definition: map.h:266
#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:1603
static void map_pre_resolve(ip4_address_t *ip4, ip6_address_t *ip6)
Definition: map.c:436
u16 expected_total
Definition: map.h:182
clib_error_t * map_init(vlib_main_t *vm)
Definition: map.c:1972
unformat_function_t unformat_line_input
Definition: format.h:281
u16 fifo_next
Definition: map.h:188
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:995
void map_ip6_drop_pi(u32 pi)
Definition: ip6_map.c:658
#define map_ip6_reass_pool_index(r)
Definition: map.c:1467
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480
static vlib_cli_command_t map_add_rule_command
(constructor) VLIB_CLI_COMMAND (map_add_rule_command)
Definition: map.c:1930
u32 ip6_reass_conf_buffers
Definition: map.h:255
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109