FD.io VPP  v18.01.1-37-g7ea3975
Vector Packet Processing
nat.c
Go to the documentation of this file.
1 /*
2  * snat.c - simple nat plugin
3  *
4  * Copyright (c) 2016 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/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
22 #include <nat/nat.h>
23 #include <nat/nat_ipfix_logging.h>
24 #include <nat/nat_det.h>
25 #include <nat/nat64.h>
26 #include <nat/dslite.h>
27 #include <nat/nat_reass.h>
28 #include <vnet/fib/fib_table.h>
29 #include <vnet/fib/ip4_fib.h>
30 
31 #include <vpp/app/version.h>
32 
34 
35 
36 /* Hook up input features */
37 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
38  .arc_name = "ip4-unicast",
39  .node_name = "nat44-in2out",
40  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
41 };
42 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
43  .arc_name = "ip4-unicast",
44  .node_name = "nat44-out2in",
45  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
46 };
47 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
48  .arc_name = "ip4-unicast",
49  .node_name = "nat44-classify",
50  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
51 };
52 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
53  .arc_name = "ip4-unicast",
54  .node_name = "nat44-det-in2out",
55  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
56 };
57 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
58  .arc_name = "ip4-unicast",
59  .node_name = "nat44-det-out2in",
60  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
61 };
62 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
63  .arc_name = "ip4-unicast",
64  .node_name = "nat44-det-classify",
65  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
66 };
67 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
68  .arc_name = "ip4-unicast",
69  .node_name = "nat44-in2out-worker-handoff",
70  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
71 };
72 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
73  .arc_name = "ip4-unicast",
74  .node_name = "nat44-out2in-worker-handoff",
75  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
76 };
77 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
78  .arc_name = "ip4-unicast",
79  .node_name = "nat44-handoff-classify",
80  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
81 };
82 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
83  .arc_name = "ip4-unicast",
84  .node_name = "nat44-in2out-fast",
85  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
86 };
87 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
88  .arc_name = "ip4-unicast",
89  .node_name = "nat44-out2in-fast",
90  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
91 };
92 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
93  .arc_name = "ip4-unicast",
94  .node_name = "nat44-hairpin-dst",
95  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
96 };
97 
98 /* Hook up output features */
99 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
100  .arc_name = "ip4-output",
101  .node_name = "nat44-in2out-output",
102  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
103 };
104 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
105  .arc_name = "ip4-output",
106  .node_name = "nat44-in2out-output-worker-handoff",
107  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
108 };
109 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
110  .arc_name = "ip4-output",
111  .node_name = "nat44-hairpin-src",
112  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
113 };
114 
115 /* Hook up ip4-local features */
116 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
117 {
118  .arc_name = "ip4-local",
119  .node_name = "nat44-hairpinning",
120  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
121 };
122 
123 
124 /* *INDENT-OFF* */
126  .version = VPP_BUILD_VER,
127  .description = "Network Address Translation",
128 };
129 /* *INDENT-ON* */
130 
134 
135 typedef enum {
140 
141 void
142 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
143 {
144  snat_session_key_t key;
146  nat_ed_ses_key_t ed_key;
147  clib_bihash_kv_16_8_t ed_kv;
148  int i;
149  snat_address_t *a;
151  vec_elt_at_index (sm->per_thread_data, thread_index);
152 
153  /* Endpoint dependent session lookup tables */
154  if (is_ed_session (s))
155  {
156  ed_key.l_addr = s->out2in.addr;
157  ed_key.r_addr = s->ext_host_addr;
158  ed_key.fib_index = s->out2in.fib_index;
160  {
161  ed_key.proto = s->in2out.port;
162  ed_key.r_port = 0;
163  ed_key.l_port = 0;
164  }
165  else
166  {
167  ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
168  ed_key.l_port = s->out2in.port;
169  ed_key.r_port = s->ext_host_port;
170  }
171  ed_kv.key[0] = ed_key.as_u64[0];
172  ed_kv.key[1] = ed_key.as_u64[1];
173  if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
174  clib_warning ("out2in_ed key del failed");
175 
176  ed_key.l_addr = s->in2out.addr;
177  ed_key.fib_index = s->in2out.fib_index;
178  if (!snat_is_unk_proto_session (s))
179  ed_key.l_port = s->in2out.port;
180  if (is_twice_nat_session (s))
181  {
182  ed_key.r_addr = s->ext_host_nat_addr;
183  ed_key.r_port = s->ext_host_nat_port;
184  }
185  ed_kv.key[0] = ed_key.as_u64[0];
186  ed_kv.key[1] = ed_key.as_u64[1];
187  if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
188  clib_warning ("in2out_ed key del failed");
189  }
190 
192  return;
193 
194  /* log NAT event */
195  snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
196  s->out2in.addr.as_u32,
197  s->in2out.protocol,
198  s->in2out.port,
199  s->out2in.port,
200  s->in2out.fib_index);
201 
202  /* Twice NAT address and port for external host */
203  if (is_twice_nat_session (s))
204  {
205  for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
206  {
207  key.protocol = s->in2out.protocol;
208  key.port = s->ext_host_nat_port;
209  a = sm->twice_nat_addresses + i;
210  if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
211  {
213  thread_index, &key, i);
214  break;
215  }
216  }
217  }
218 
219  if (is_ed_session (s))
220  return;
221 
222  /* Session lookup tables */
223  kv.key = s->in2out.as_u64;
224  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
225  clib_warning ("in2out key del failed");
226  kv.key = s->out2in.as_u64;
227  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
228  clib_warning ("out2in key del failed");
229 
230  if (snat_is_session_static (s))
231  return;
232 
233  if (s->outside_address_index != ~0)
235  &s->out2in, s->outside_address_index);
236 }
237 
238 snat_user_t *
240  u32 thread_index)
241 {
242  snat_user_t *u = 0;
243  snat_user_key_t user_key;
244  clib_bihash_kv_8_8_t kv, value;
245  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
246  dlist_elt_t * per_user_list_head_elt;
247 
248  user_key.addr.as_u32 = addr->as_u32;
249  user_key.fib_index = fib_index;
250  kv.key = user_key.as_u64;
251 
252  /* Ever heard of the "user" = src ip4 address before? */
253  if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
254  {
255  /* no, make a new one */
256  pool_get (tsm->users, u);
257  memset (u, 0, sizeof (*u));
258  u->addr.as_u32 = addr->as_u32;
259  u->fib_index = fib_index;
260 
261  pool_get (tsm->list_pool, per_user_list_head_elt);
262 
263  u->sessions_per_user_list_head_index = per_user_list_head_elt -
264  tsm->list_pool;
265 
267 
268  kv.value = u - tsm->users;
269 
270  /* add user */
271  if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
272  clib_warning ("user_hash keay add failed");
273  }
274  else
275  {
276  u = pool_elt_at_index (tsm->users, value.value);
277  }
278 
279  return u;
280 }
281 
282 snat_session_t *
284 {
285  snat_session_t *s;
286  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
287  u32 oldest_per_user_translation_list_index, session_index;
288  dlist_elt_t * oldest_per_user_translation_list_elt;
289  dlist_elt_t * per_user_translation_list_elt;
290 
291  /* Over quota? Recycle the least recently used translation */
293  {
294  oldest_per_user_translation_list_index =
297 
298  ASSERT (oldest_per_user_translation_list_index != ~0);
299 
300  /* Add it back to the end of the LRU list */
303  oldest_per_user_translation_list_index);
304  /* Get the list element */
305  oldest_per_user_translation_list_elt =
307  oldest_per_user_translation_list_index);
308 
309  /* Get the session index from the list element */
310  session_index = oldest_per_user_translation_list_elt->value;
311 
312  /* Get the session */
313  s = pool_elt_at_index (tsm->sessions, session_index);
314  nat_free_session_data (sm, s, thread_index);
315  s->outside_address_index = ~0;
316  s->flags = 0;
317  s->total_bytes = 0;
318  s->total_pkts = 0;
319  }
320  else
321  {
322  pool_get (tsm->sessions, s);
323  memset (s, 0, sizeof (*s));
324  s->outside_address_index = ~0;
325 
326  /* Create list elts */
327  pool_get (tsm->list_pool, per_user_translation_list_elt);
329  per_user_translation_list_elt - tsm->list_pool);
330 
331  per_user_translation_list_elt->value = s - tsm->sessions;
332  s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
333  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
334 
336  s->per_user_list_head_index,
337  per_user_translation_list_elt - tsm->list_pool);
338  }
339 
340  return s;
341 }
342 
343 static inline uword
345  vlib_node_runtime_t * node,
346  vlib_frame_t * frame)
347 {
348  u32 n_left_from, * from, * to_next;
349  nat44_classify_next_t next_index;
350  snat_main_t *sm = &snat_main;
351 
352  from = vlib_frame_vector_args (frame);
353  n_left_from = frame->n_vectors;
354  next_index = node->cached_next_index;
355 
356  while (n_left_from > 0)
357  {
358  u32 n_left_to_next;
359 
360  vlib_get_next_frame (vm, node, next_index,
361  to_next, n_left_to_next);
362 
363  while (n_left_from > 0 && n_left_to_next > 0)
364  {
365  u32 bi0;
366  vlib_buffer_t *b0;
368  ip4_header_t *ip0;
369  snat_address_t *ap;
370  snat_session_key_t m_key0;
371  clib_bihash_kv_8_8_t kv0, value0;
372 
373  /* speculatively enqueue b0 to the current next frame */
374  bi0 = from[0];
375  to_next[0] = bi0;
376  from += 1;
377  to_next += 1;
378  n_left_from -= 1;
379  n_left_to_next -= 1;
380 
381  b0 = vlib_get_buffer (vm, bi0);
382  ip0 = vlib_buffer_get_current (b0);
383 
384  vec_foreach (ap, sm->addresses)
385  {
386  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
387  {
389  break;
390  }
391  }
392 
394  {
395  m_key0.addr = ip0->dst_address;
396  m_key0.port = 0;
397  m_key0.protocol = 0;
398  m_key0.fib_index = sm->outside_fib_index;
399  kv0.key = m_key0.as_u64;
400  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
401  {
403  }
404  }
405  /* verify speculative enqueue, maybe switch current next frame */
406  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
407  to_next, n_left_to_next,
408  bi0, next0);
409  }
410 
411  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
412  }
413 
414  return frame->n_vectors;
415 }
416 
417 static uword
419  vlib_node_runtime_t * node,
420  vlib_frame_t * frame)
421 {
422  return nat44_classify_node_fn_inline (vm, node, frame);
423 };
424 
426  .function = nat44_classify_node_fn,
427  .name = "nat44-classify",
428  .vector_size = sizeof (u32),
429  .type = VLIB_NODE_TYPE_INTERNAL,
430  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
431  .next_nodes = {
432  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
433  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
434  },
435 };
436 
439 
440 static uword
442  vlib_node_runtime_t * node,
443  vlib_frame_t * frame)
444 {
445  return nat44_classify_node_fn_inline (vm, node, frame);
446 };
447 
449  .function = nat44_det_classify_node_fn,
450  .name = "nat44-det-classify",
451  .vector_size = sizeof (u32),
452  .type = VLIB_NODE_TYPE_INTERNAL,
453  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
454  .next_nodes = {
455  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
456  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
457  },
458 };
459 
462 
463 static uword
465  vlib_node_runtime_t * node,
466  vlib_frame_t * frame)
467 {
468  return nat44_classify_node_fn_inline (vm, node, frame);
469 };
470 
472  .function = nat44_handoff_classify_node_fn,
473  .name = "nat44-handoff-classify",
474  .vector_size = sizeof (u32),
475  .type = VLIB_NODE_TYPE_INTERNAL,
476  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
477  .next_nodes = {
478  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
479  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
480  },
481 };
482 
485 
486 /**
487  * @brief Add/del NAT address to FIB.
488  *
489  * Add the external NAT address to the FIB as receive entries. This ensures
490  * that VPP will reply to ARP for this address and we don't need to enable
491  * proxy ARP on the outside interface.
492  *
493  * @param addr IPv4 address.
494  * @param plen address prefix length
495  * @param sw_if_index Interface.
496  * @param is_add If 0 delete, otherwise add.
497  */
498 void
500  int is_add)
501 {
502  fib_prefix_t prefix = {
503  .fp_len = p_len,
504  .fp_proto = FIB_PROTOCOL_IP4,
505  .fp_addr = {
506  .ip4.as_u32 = addr->as_u32,
507  },
508  };
509  u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
510 
511  if (is_add)
513  &prefix,
519  NULL,
520  sw_if_index,
521  ~0,
522  1,
523  NULL,
525  else
526  fib_table_entry_delete(fib_index,
527  &prefix,
529 }
530 
532  u8 twice_nat)
533 {
534  snat_address_t * ap;
537 
538  /* Check if address already exists */
539  vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
540  {
541  if (ap->addr.as_u32 == addr->as_u32)
542  return;
543  }
544 
545  if (twice_nat)
546  vec_add2 (sm->twice_nat_addresses, ap, 1);
547  else
548  vec_add2 (sm->addresses, ap, 1);
549 
550  ap->addr = *addr;
551  if (vrf_id != ~0)
552  ap->fib_index =
555  else
556  ap->fib_index = ~0;
557 #define _(N, i, n, s) \
558  clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
559  ap->busy_##n##_ports = 0; \
560  vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
562 #undef _
563 
564  if (twice_nat)
565  return;
566 
567  /* Add external address to FIB */
568  pool_foreach (i, sm->interfaces,
569  ({
570  if (nat_interface_is_inside(i))
571  continue;
572 
573  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
574  break;
575  }));
577  ({
578  if (nat_interface_is_inside(i))
579  continue;
580 
581  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
582  break;
583  }));
584 }
585 
588 {
591  ({
592  if (m->external_addr.as_u32 == addr.as_u32)
593  return 1;
594  }));
595 
596  return 0;
597 }
598 
600 {
601  u32 v;
602 
603  v = clib_net_to_host_u32(a->as_u32) + 1;
604  a->as_u32 = clib_host_to_net_u32(v);
605 }
606 
607 static void
609  ip4_address_t l_addr,
610  u16 l_port,
611  u32 sw_if_index,
612  u16 e_port,
613  u32 vrf_id,
614  snat_protocol_t proto,
615  int addr_only,
616  int is_add)
617 {
619 
620  vec_add2 (sm->to_resolve, rp, 1);
621  rp->l_addr.as_u32 = l_addr.as_u32;
622  rp->l_port = l_port;
623  rp->sw_if_index = sw_if_index;
624  rp->e_port = e_port;
625  rp->vrf_id = vrf_id;
626  rp->proto = proto;
627  rp->addr_only = addr_only;
628  rp->is_add = is_add;
629 }
630 
631 /**
632  * @brief Add static mapping.
633  *
634  * Create static mapping between local addr+port and external addr+port.
635  *
636  * @param l_addr Local IPv4 address.
637  * @param e_addr External IPv4 address.
638  * @param l_port Local port number.
639  * @param e_port External port number.
640  * @param vrf_id VRF ID.
641  * @param addr_only If 0 address port and pair mapping, otherwise address only.
642  * @param sw_if_index External port instead of specific IP address.
643  * @param is_add If 0 delete static mapping, otherwise add.
644  * @param twice_nat If 1 translate external host address and port.
645  *
646  * @returns
647  */
649  u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
650  u32 sw_if_index, snat_protocol_t proto, int is_add,
651  u8 twice_nat)
652 {
653  snat_main_t * sm = &snat_main;
655  snat_session_key_t m_key;
656  clib_bihash_kv_8_8_t kv, value;
657  snat_address_t *a = 0;
658  u32 fib_index = ~0;
659  uword * p;
660  snat_interface_t *interface;
661  int i;
663 
664  /* If the external address is a specific interface address */
665  if (sw_if_index != ~0)
666  {
667  ip4_address_t * first_int_addr;
668 
669  /* Might be already set... */
670  first_int_addr = ip4_interface_first_address
671  (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
672 
673  /* DHCP resolution required? */
674  if (first_int_addr == 0)
675  {
677  (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
678  addr_only, is_add);
679  return 0;
680  }
681  else
682  {
683  e_addr.as_u32 = first_int_addr->as_u32;
684  /* Identity mapping? */
685  if (l_addr.as_u32 == 0)
686  l_addr.as_u32 = e_addr.as_u32;
687  }
688  }
689 
690  m_key.addr = e_addr;
691  m_key.port = addr_only ? 0 : e_port;
692  m_key.protocol = addr_only ? 0 : proto;
693  m_key.fib_index = sm->outside_fib_index;
694  kv.key = m_key.as_u64;
695  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
696  m = 0;
697  else
698  m = pool_elt_at_index (sm->static_mappings, value.value);
699 
700  if (is_add)
701  {
702  if (m)
703  return VNET_API_ERROR_VALUE_EXIST;
704 
705  if (twice_nat && addr_only)
706  return VNET_API_ERROR_UNSUPPORTED;
707 
708  /* Convert VRF id to FIB index */
709  if (vrf_id != ~0)
710  {
711  p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
712  if (!p)
713  return VNET_API_ERROR_NO_SUCH_FIB;
714  fib_index = p[0];
715  }
716  /* If not specified use inside VRF id from SNAT plugin startup config */
717  else
718  {
719  fib_index = sm->inside_fib_index;
720  vrf_id = sm->inside_vrf_id;
721  }
722 
723  /* Find external address in allocated addresses and reserve port for
724  address and port pair mapping when dynamic translations enabled */
725  if (!addr_only && !(sm->static_mapping_only))
726  {
727  for (i = 0; i < vec_len (sm->addresses); i++)
728  {
729  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
730  {
731  a = sm->addresses + i;
732  /* External port must be unused */
733  switch (proto)
734  {
735 #define _(N, j, n, s) \
736  case SNAT_PROTOCOL_##N: \
737  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
738  return VNET_API_ERROR_INVALID_VALUE; \
739  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
740  if (e_port > 1024) \
741  { \
742  a->busy_##n##_ports++; \
743  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
744  } \
745  break;
747 #undef _
748  default:
749  clib_warning("unknown_protocol");
750  return VNET_API_ERROR_INVALID_VALUE_2;
751  }
752  break;
753  }
754  }
755  /* External address must be allocated */
756  if (!a && (l_addr.as_u32 != e_addr.as_u32))
757  return VNET_API_ERROR_NO_SUCH_ENTRY;
758  }
759 
760  pool_get (sm->static_mappings, m);
761  memset (m, 0, sizeof (*m));
762  m->local_addr = l_addr;
763  m->external_addr = e_addr;
764  m->addr_only = addr_only;
765  m->vrf_id = vrf_id;
766  m->fib_index = fib_index;
767  m->twice_nat = twice_nat;
768  if (!addr_only)
769  {
770  m->local_port = l_port;
771  m->external_port = e_port;
772  m->proto = proto;
773  }
774 
775  if (sm->workers)
776  {
777  ip4_header_t ip = {
778  .src_address = m->local_addr,
779  };
780  m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index);
782  }
783  else
785 
786  m_key.addr = m->local_addr;
787  m_key.port = m->local_port;
788  m_key.protocol = m->proto;
789  m_key.fib_index = m->fib_index;
790  kv.key = m_key.as_u64;
791  kv.value = m - sm->static_mappings;
792  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
793  if (twice_nat)
794  {
795  m_key.port = clib_host_to_net_u16 (l_port);
796  kv.key = m_key.as_u64;
797  kv.value = ~0ULL;
798  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
799  clib_warning ("in2out key add failed");
800  }
801 
802  m_key.addr = m->external_addr;
803  m_key.port = m->external_port;
804  m_key.fib_index = sm->outside_fib_index;
805  kv.key = m_key.as_u64;
806  kv.value = m - sm->static_mappings;
807  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
808  if (twice_nat)
809  {
810  m_key.port = clib_host_to_net_u16 (e_port);
811  kv.key = m_key.as_u64;
812  kv.value = ~0ULL;
813  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
814  clib_warning ("out2in key add failed");
815  }
816 
817  }
818  else
819  {
820  if (!m)
821  return VNET_API_ERROR_NO_SUCH_ENTRY;
822 
823  /* Free external address port */
824  if (!addr_only && !(sm->static_mapping_only))
825  {
826  for (i = 0; i < vec_len (sm->addresses); i++)
827  {
828  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
829  {
830  a = sm->addresses + i;
831  switch (proto)
832  {
833 #define _(N, j, n, s) \
834  case SNAT_PROTOCOL_##N: \
835  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
836  if (e_port > 1024) \
837  { \
838  a->busy_##n##_ports--; \
839  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
840  } \
841  break;
843 #undef _
844  default:
845  clib_warning("unknown_protocol");
846  return VNET_API_ERROR_INVALID_VALUE_2;
847  }
848  break;
849  }
850  }
851  }
852 
853  if (sm->num_workers > 1)
855  else
857 
858  m_key.addr = m->local_addr;
859  m_key.port = m->local_port;
860  m_key.protocol = m->proto;
861  m_key.fib_index = m->fib_index;
862  kv.key = m_key.as_u64;
863  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
864  if (twice_nat)
865  {
866  m_key.port = clib_host_to_net_u16 (m->local_port);
867  kv.key = m_key.as_u64;
868  kv.value = ~0ULL;
869  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
870  clib_warning ("in2out key del failed");
871  }
872 
873  m_key.addr = m->external_addr;
874  m_key.port = m->external_port;
875  m_key.fib_index = sm->outside_fib_index;
876  kv.key = m_key.as_u64;
877  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
878  if (twice_nat)
879  {
880  m_key.port = clib_host_to_net_u16 (m->external_port);
881  kv.key = m_key.as_u64;
882  kv.value = ~0ULL;
883  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
884  clib_warning ("in2out key del failed");
885  }
886 
887  /* Delete session(s) for static mapping if exist */
888  if (!(sm->static_mapping_only) ||
890  {
891  snat_user_key_t u_key;
892  snat_user_t *u;
893  dlist_elt_t * head, * elt;
894  u32 elt_index, head_index;
895  u32 ses_index;
896  u64 user_index;
897  snat_session_t * s;
898 
899  u_key.addr = m->local_addr;
900  u_key.fib_index = m->fib_index;
901  kv.key = u_key.as_u64;
902  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
903  {
904  user_index = value.value;
905  u = pool_elt_at_index (tsm->users, user_index);
906  if (u->nstaticsessions)
907  {
908  head_index = u->sessions_per_user_list_head_index;
909  head = pool_elt_at_index (tsm->list_pool, head_index);
910  elt_index = head->next;
911  elt = pool_elt_at_index (tsm->list_pool, elt_index);
912  ses_index = elt->value;
913  while (ses_index != ~0)
914  {
915  s = pool_elt_at_index (tsm->sessions, ses_index);
916  elt = pool_elt_at_index (tsm->list_pool, elt->next);
917  ses_index = elt->value;
918 
919  if (!addr_only)
920  {
921  if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
922  (clib_net_to_host_u16 (s->out2in.port) != e_port))
923  continue;
924  }
925 
926  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
927  clib_dlist_remove (tsm->list_pool, s->per_user_index);
928  pool_put_index (tsm->list_pool, s->per_user_index);
929  pool_put (tsm->sessions, s);
930  u->nstaticsessions--;
931 
932  if (!addr_only)
933  break;
934  }
935  if (addr_only)
936  {
937  pool_put (tsm->users, u);
938  clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
939  }
940  }
941  }
942  }
943 
944  /* Delete static mapping from pool */
945  pool_put (sm->static_mappings, m);
946  }
947 
948  if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
949  return 0;
950 
951  /* Add/delete external address to FIB */
952  pool_foreach (interface, sm->interfaces,
953  ({
954  if (nat_interface_is_inside(interface))
955  continue;
956 
957  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
958  break;
959  }));
960  pool_foreach (interface, sm->output_feature_interfaces,
961  ({
962  if (nat_interface_is_inside(interface))
963  continue;
964 
965  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
966  break;
967  }));
968 
969  return 0;
970 }
971 
973  ip4_address_t * e_addr, u16 e_port)
974 {
975  snat_main_t *sm = &snat_main;
978 
979  /* *INDENT-OFF* */
981  ({
982  if (vec_len(m->locals))
983  {
984  if (m->external_port == e_port && m->external_addr.as_u32 == e_addr->as_u32)
985  continue;
986 
987  vec_foreach (ap, m->locals)
988  {
989  if (ap->port == local->port && ap->addr.as_u32 == local->addr.as_u32)
990  return 1;
991  }
992  }
993  }));
994  /* *INDENT-ON* */
995 
996  return 0;
997 }
998 
1000  snat_protocol_t proto, u32 vrf_id,
1001  nat44_lb_addr_port_t *locals, u8 is_add,
1002  u8 twice_nat)
1003 {
1004  snat_main_t * sm = &snat_main;
1006  snat_session_key_t m_key;
1007  clib_bihash_kv_8_8_t kv, value;
1008  u32 fib_index;
1009  snat_address_t *a = 0;
1010  int i;
1011  nat44_lb_addr_port_t *local;
1012  u32 worker_index = 0, elt_index, head_index, ses_index;
1014  snat_user_key_t u_key;
1015  snat_user_t *u;
1016  snat_session_t * s;
1017  dlist_elt_t * head, * elt;
1018 
1019  m_key.addr = e_addr;
1020  m_key.port = e_port;
1021  m_key.protocol = proto;
1022  m_key.fib_index = sm->outside_fib_index;
1023  kv.key = m_key.as_u64;
1024  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1025  m = 0;
1026  else
1027  m = pool_elt_at_index (sm->static_mappings, value.value);
1028 
1029  if (is_add)
1030  {
1031  if (m)
1032  return VNET_API_ERROR_VALUE_EXIST;
1033 
1034  if (vec_len (locals) < 2)
1035  return VNET_API_ERROR_INVALID_VALUE;
1036 
1038  vrf_id,
1040 
1041  /* Find external address in allocated addresses and reserve port for
1042  address and port pair mapping when dynamic translations enabled */
1043  if (!sm->static_mapping_only)
1044  {
1045  for (i = 0; i < vec_len (sm->addresses); i++)
1046  {
1047  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1048  {
1049  a = sm->addresses + i;
1050  /* External port must be unused */
1051  switch (proto)
1052  {
1053 #define _(N, j, n, s) \
1054  case SNAT_PROTOCOL_##N: \
1055  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1056  return VNET_API_ERROR_INVALID_VALUE; \
1057  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1058  if (e_port > 1024) \
1059  { \
1060  a->busy_##n##_ports++; \
1061  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1062  } \
1063  break;
1065 #undef _
1066  default:
1067  clib_warning("unknown_protocol");
1068  return VNET_API_ERROR_INVALID_VALUE_2;
1069  }
1070  break;
1071  }
1072  }
1073  /* External address must be allocated */
1074  if (!a)
1075  return VNET_API_ERROR_NO_SUCH_ENTRY;
1076  }
1077 
1078  pool_get (sm->static_mappings, m);
1079  memset (m, 0, sizeof (*m));
1080  m->external_addr = e_addr;
1081  m->addr_only = 0;
1082  m->vrf_id = vrf_id;
1083  m->fib_index = fib_index;
1084  m->external_port = e_port;
1085  m->proto = proto;
1086  m->twice_nat = twice_nat;
1087 
1088  m_key.addr = m->external_addr;
1089  m_key.port = m->external_port;
1090  m_key.protocol = m->proto;
1091  m_key.fib_index = sm->outside_fib_index;
1092  kv.key = m_key.as_u64;
1093  kv.value = m - sm->static_mappings;
1094  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1095  {
1096  clib_warning ("static_mapping_by_external key add failed");
1097  return VNET_API_ERROR_UNSPECIFIED;
1098  }
1099 
1100  /* Assign worker */
1101  if (sm->workers)
1102  {
1103  worker_index = sm->first_worker_index +
1104  sm->workers[sm->next_worker++ % vec_len (sm->workers)];
1105  tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
1106  m->worker_index = worker_index;
1107  }
1108  else
1109  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1110 
1111  m_key.port = clib_host_to_net_u16 (m->external_port);
1112  kv.key = m_key.as_u64;
1113  kv.value = ~0ULL;
1114  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
1115  {
1116  clib_warning ("out2in key add failed");
1117  return VNET_API_ERROR_UNSPECIFIED;
1118  }
1119 
1120  m_key.fib_index = m->fib_index;
1121  for (i = 0; i < vec_len (locals); i++)
1122  {
1123  m_key.addr = locals[i].addr;
1124  m_key.port = locals[i].port;
1125  kv.key = m_key.as_u64;
1126  kv.value = m - sm->static_mappings;
1127  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1128  locals[i].prefix = (i == 0) ? locals[i].probability :\
1129  (locals[i - 1].prefix + locals[i].probability);
1130  vec_add1 (m->locals, locals[i]);
1131 
1132  m_key.port = clib_host_to_net_u16 (locals[i].port);
1133  kv.key = m_key.as_u64;
1134  kv.value = ~0ULL;
1135  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
1136  {
1137  clib_warning ("in2out key add failed");
1138  return VNET_API_ERROR_UNSPECIFIED;
1139  }
1140  }
1141  }
1142  else
1143  {
1144  if (!m)
1145  return VNET_API_ERROR_NO_SUCH_ENTRY;
1146 
1148 
1149  /* Free external address port */
1150  if (!sm->static_mapping_only)
1151  {
1152  for (i = 0; i < vec_len (sm->addresses); i++)
1153  {
1154  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1155  {
1156  a = sm->addresses + i;
1157  switch (proto)
1158  {
1159 #define _(N, j, n, s) \
1160  case SNAT_PROTOCOL_##N: \
1161  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1162  if (e_port > 1024) \
1163  { \
1164  a->busy_##n##_ports--; \
1165  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1166  } \
1167  break;
1169 #undef _
1170  default:
1171  clib_warning("unknown_protocol");
1172  return VNET_API_ERROR_INVALID_VALUE_2;
1173  }
1174  break;
1175  }
1176  }
1177  }
1178 
1180  m_key.addr = m->external_addr;
1181  m_key.port = m->external_port;
1182  m_key.protocol = m->proto;
1183  m_key.fib_index = sm->outside_fib_index;
1184  kv.key = m_key.as_u64;
1185  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1186  {
1187  clib_warning ("static_mapping_by_external key del failed");
1188  return VNET_API_ERROR_UNSPECIFIED;
1189  }
1190 
1191  m_key.port = clib_host_to_net_u16 (m->external_port);
1192  kv.key = m_key.as_u64;
1193  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1194  {
1195  clib_warning ("outi2in key del failed");
1196  return VNET_API_ERROR_UNSPECIFIED;
1197  }
1198 
1199  vec_foreach (local, m->locals)
1200  {
1201  m_key.addr = local->addr;
1202  m_key.port = local->port;
1203  m_key.fib_index = m->fib_index;
1204  kv.key = m_key.as_u64;
1205  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1206  {
1207  clib_warning ("static_mapping_by_local key del failed");
1208  return VNET_API_ERROR_UNSPECIFIED;
1209  }
1210 
1211  if (!lb_local_exists(local, &e_addr, e_port))
1212  {
1213  m_key.port = clib_host_to_net_u16 (local->port);
1214  kv.key = m_key.as_u64;
1215  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1216  {
1217  clib_warning ("in2out key del failed");
1218  return VNET_API_ERROR_UNSPECIFIED;
1219  }
1220  }
1221  /* Delete sessions */
1222  u_key.addr = local->addr;
1223  u_key.fib_index = m->fib_index;
1224  kv.key = u_key.as_u64;
1225  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1226  {
1227  u = pool_elt_at_index (tsm->users, value.value);
1228  if (u->nstaticsessions)
1229  {
1230  head_index = u->sessions_per_user_list_head_index;
1231  head = pool_elt_at_index (tsm->list_pool, head_index);
1232  elt_index = head->next;
1233  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1234  ses_index = elt->value;
1235  while (ses_index != ~0)
1236  {
1237  s = pool_elt_at_index (tsm->sessions, ses_index);
1238  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1239  ses_index = elt->value;
1240 
1241  if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
1242  (clib_net_to_host_u16 (s->in2out.port) != local->port))
1243  continue;
1244 
1245  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1246  clib_dlist_remove (tsm->list_pool, s->per_user_index);
1247  pool_put_index (tsm->list_pool, s->per_user_index);
1248  pool_put (tsm->sessions, s);
1249  u->nstaticsessions--;
1250  }
1251  }
1252  }
1253  }
1254  vec_free(m->locals);
1255 
1256  pool_put (sm->static_mappings, m);
1257  }
1258 
1259  return 0;
1260 }
1261 
1262 int
1264  u8 twice_nat)
1265 {
1266  snat_address_t *a = 0;
1267  snat_session_t *ses;
1268  u32 *ses_to_be_removed = 0, *ses_index;
1269  clib_bihash_kv_8_8_t kv, value;
1270  snat_user_key_t user_key;
1271  snat_user_t *u;
1274  snat_interface_t *interface;
1275  int i;
1276  snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1277 
1278  /* Find SNAT address */
1279  for (i=0; i < vec_len (addresses); i++)
1280  {
1281  if (addresses[i].addr.as_u32 == addr.as_u32)
1282  {
1283  a = addresses + i;
1284  break;
1285  }
1286  }
1287  if (!a)
1288  return VNET_API_ERROR_NO_SUCH_ENTRY;
1289 
1290  if (delete_sm)
1291  {
1292  pool_foreach (m, sm->static_mappings,
1293  ({
1294  if (m->external_addr.as_u32 == addr.as_u32)
1295  (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1296  m->local_port, m->external_port,
1297  m->vrf_id, m->addr_only, ~0,
1298  m->proto, 0, m->twice_nat);
1299  }));
1300  }
1301  else
1302  {
1303  /* Check if address is used in some static mapping */
1305  {
1306  clib_warning ("address used in static mapping");
1307  return VNET_API_ERROR_UNSPECIFIED;
1308  }
1309  }
1310 
1311  if (a->fib_index != ~0)
1314 
1315  /* Delete sessions using address */
1316  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1317  {
1318  vec_foreach (tsm, sm->per_thread_data)
1319  {
1320  pool_foreach (ses, tsm->sessions, ({
1321  if (ses->out2in.addr.as_u32 == addr.as_u32)
1322  {
1323  ses->outside_address_index = ~0;
1324  nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1325  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1326  pool_put_index (tsm->list_pool, ses->per_user_index);
1327  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1328  user_key.addr = ses->in2out.addr;
1329  user_key.fib_index = ses->in2out.fib_index;
1330  kv.key = user_key.as_u64;
1331  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1332  {
1333  u = pool_elt_at_index (tsm->users, value.value);
1334  u->nsessions--;
1335  }
1336  }
1337  }));
1338 
1339  vec_foreach (ses_index, ses_to_be_removed)
1340  pool_put_index (tsm->sessions, ses_index[0]);
1341 
1342  vec_free (ses_to_be_removed);
1343  }
1344  }
1345 
1346  if (twice_nat)
1347  {
1348  vec_del1 (sm->twice_nat_addresses, i);
1349  return 0;
1350  }
1351  else
1352  vec_del1 (sm->addresses, i);
1353 
1354  /* Delete external address from FIB */
1355  pool_foreach (interface, sm->interfaces,
1356  ({
1357  if (nat_interface_is_inside(interface))
1358  continue;
1359 
1360  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1361  break;
1362  }));
1363  pool_foreach (interface, sm->output_feature_interfaces,
1364  ({
1365  if (nat_interface_is_inside(interface))
1366  continue;
1367 
1368  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1369  break;
1370  }));
1371 
1372  return 0;
1373 }
1374 
1375 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1376 {
1377  snat_main_t *sm = &snat_main;
1379  const char * feature_name, *del_feature_name;
1380  snat_address_t * ap;
1382  snat_det_map_t * dm;
1383 
1385  ({
1386  if (i->sw_if_index == sw_if_index)
1387  return VNET_API_ERROR_VALUE_EXIST;
1388  }));
1389 
1391  feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1392  else
1393  {
1394  if (sm->num_workers > 1 && !sm->deterministic)
1395  feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1396  else if (sm->deterministic)
1397  feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1398  else
1399  feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1400  }
1401 
1402  if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1404 
1405  if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1407 
1408  pool_foreach (i, sm->interfaces,
1409  ({
1410  if (i->sw_if_index == sw_if_index)
1411  {
1412  if (is_del)
1413  {
1414  if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1415  {
1416  if (is_inside)
1417  i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1418  else
1419  i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1420 
1421  if (sm->num_workers > 1 && !sm->deterministic)
1422  del_feature_name = "nat44-handoff-classify";
1423  else if (sm->deterministic)
1424  del_feature_name = "nat44-det-classify";
1425  else
1426  del_feature_name = "nat44-classify";
1427 
1428  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1429  sw_if_index, 0, 0, 0);
1430  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1431  sw_if_index, 1, 0, 0);
1432  }
1433  else
1434  {
1435  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1436  sw_if_index, 0, 0, 0);
1437  pool_put (sm->interfaces, i);
1438  }
1439  }
1440  else
1441  {
1442  if ((nat_interface_is_inside(i) && is_inside) ||
1443  (nat_interface_is_outside(i) && !is_inside))
1444  return 0;
1445 
1446  if (sm->num_workers > 1 && !sm->deterministic)
1447  {
1448  del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1449  "nat44-out2in-worker-handoff";
1450  feature_name = "nat44-handoff-classify";
1451  }
1452  else if (sm->deterministic)
1453  {
1454  del_feature_name = !is_inside ? "nat44-det-in2out" :
1455  "nat44-det-out2in";
1456  feature_name = "nat44-det-classify";
1457  }
1458  else
1459  {
1460  del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1461  feature_name = "nat44-classify";
1462  }
1463 
1464  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1465  sw_if_index, 0, 0, 0);
1466  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1467  sw_if_index, 1, 0, 0);
1468  goto set_flags;
1469  }
1470 
1471  goto fib;
1472  }
1473  }));
1474 
1475  if (is_del)
1476  return VNET_API_ERROR_NO_SUCH_ENTRY;
1477 
1478  pool_get (sm->interfaces, i);
1479  i->sw_if_index = sw_if_index;
1480  i->flags = 0;
1481  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1482 
1483 set_flags:
1484  if (is_inside)
1485  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1486  else
1487  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1488 
1489  /* Add/delete external addresses to FIB */
1490 fib:
1491  if (is_inside)
1492  {
1493  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1494  sw_if_index, !is_del, 0, 0);
1495  return 0;
1496  }
1497 
1498  vec_foreach (ap, sm->addresses)
1499  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1500 
1501  pool_foreach (m, sm->static_mappings,
1502  ({
1503  if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1504  continue;
1505 
1506  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1507  }));
1508 
1509  pool_foreach (dm, sm->det_maps,
1510  ({
1511  snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1512  }));
1513 
1514  return 0;
1515 }
1516 
1518  u8 is_inside,
1519  int is_del)
1520 {
1521  snat_main_t *sm = &snat_main;
1523  snat_address_t * ap;
1525 
1526  if (sm->deterministic ||
1528  return VNET_API_ERROR_UNSUPPORTED;
1529 
1530  pool_foreach (i, sm->interfaces,
1531  ({
1532  if (i->sw_if_index == sw_if_index)
1533  return VNET_API_ERROR_VALUE_EXIST;
1534  }));
1535 
1536  if (is_inside)
1537  {
1538  vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1539  sw_if_index, !is_del, 0, 0);
1540  vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1541  sw_if_index, !is_del, 0, 0);
1542  goto fq;
1543  }
1544 
1545  if (sm->num_workers > 1)
1546  {
1547  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1548  sw_if_index, !is_del, 0, 0);
1549  vnet_feature_enable_disable ("ip4-output",
1550  "nat44-in2out-output-worker-handoff",
1551  sw_if_index, !is_del, 0, 0);
1552  }
1553  else
1554  {
1555  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1556  !is_del, 0, 0);
1557  vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1558  sw_if_index, !is_del, 0, 0);
1559  }
1560 
1561 fq:
1562  if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1565 
1566  if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1568 
1570  ({
1571  if (i->sw_if_index == sw_if_index)
1572  {
1573  if (is_del)
1574  pool_put (sm->output_feature_interfaces, i);
1575  else
1576  return VNET_API_ERROR_VALUE_EXIST;
1577 
1578  goto fib;
1579  }
1580  }));
1581 
1582  if (is_del)
1583  return VNET_API_ERROR_NO_SUCH_ENTRY;
1584 
1585  pool_get (sm->output_feature_interfaces, i);
1586  i->sw_if_index = sw_if_index;
1587  i->flags = 0;
1588  if (is_inside)
1589  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1590  else
1591  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1592 
1593  /* Add/delete external addresses to FIB */
1594 fib:
1595  if (is_inside)
1596  return 0;
1597 
1598  vec_foreach (ap, sm->addresses)
1599  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1600 
1601  pool_foreach (m, sm->static_mappings,
1602  ({
1603  if (!(m->addr_only))
1604  continue;
1605 
1606  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1607  }));
1608 
1609  return 0;
1610 }
1611 
1612 int snat_set_workers (uword * bitmap)
1613 {
1614  snat_main_t *sm = &snat_main;
1615  int i, j = 0;
1616 
1617  if (sm->num_workers < 2)
1618  return VNET_API_ERROR_FEATURE_DISABLED;
1619 
1620  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1621  return VNET_API_ERROR_INVALID_WORKER;
1622 
1623  vec_free (sm->workers);
1624  clib_bitmap_foreach (i, bitmap,
1625  ({
1626  vec_add1(sm->workers, i);
1628  j++;
1629  }));
1630 
1631  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1632  sm->num_snat_thread = _vec_len (sm->workers);
1633 
1634  return 0;
1635 }
1636 
1637 
1638 static void
1640  uword opaque,
1641  u32 sw_if_index,
1642  ip4_address_t * address,
1643  u32 address_length,
1644  u32 if_address_index,
1645  u32 is_delete);
1646 
1647 static int
1649  u32 fib_index,
1650  u32 thread_index,
1651  snat_session_key_t * k,
1652  u32 * address_indexp,
1653  u16 port_per_thread,
1654  u32 snat_thread_index);
1655 
1657 {
1658  snat_main_t * sm = &snat_main;
1659  clib_error_t * error = 0;
1660  ip4_main_t * im = &ip4_main;
1661  ip_lookup_main_t * lm = &im->lookup_main;
1662  uword *p;
1665  uword *bitmap = 0;
1666  u32 i;
1668 
1669  sm->vlib_main = vm;
1670  sm->vnet_main = vnet_get_main();
1671  sm->ip4_main = im;
1672  sm->ip4_lookup_main = lm;
1673  sm->api_main = &api_main;
1674  sm->first_worker_index = 0;
1675  sm->next_worker = 0;
1676  sm->num_workers = 0;
1677  sm->num_snat_thread = 1;
1678  sm->workers = 0;
1679  sm->port_per_thread = 0xffff - 1024;
1680  sm->fq_in2out_index = ~0;
1681  sm->fq_out2in_index = ~0;
1687  sm->forwarding_enabled = 0;
1688 
1689  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1690  if (p)
1691  {
1692  tr = (vlib_thread_registration_t *) p[0];
1693  if (tr)
1694  {
1695  sm->num_workers = tr->count;
1696  sm->first_worker_index = tr->first_index;
1697  }
1698  }
1699 
1700  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1701 
1702  /* Use all available workers by default */
1703  if (sm->num_workers > 1)
1704  {
1705  for (i=0; i < sm->num_workers; i++)
1706  bitmap = clib_bitmap_set (bitmap, i, 1);
1707  snat_set_workers(bitmap);
1708  clib_bitmap_free (bitmap);
1709  }
1710  else
1711  {
1713  }
1714 
1715  error = snat_api_init(vm, sm);
1716  if (error)
1717  return error;
1718 
1719  /* Set up the interface address add/del callback */
1721  cb4.function_opaque = 0;
1722 
1724 
1725  /* Init IPFIX logging */
1727 
1728  /* Init NAT64 */
1729  error = nat64_init(vm);
1730  if (error)
1731  return error;
1732 
1733  dslite_init(vm);
1734 
1735  /* Init virtual fragmenentation reassembly */
1736  return nat_reass_init(vm);
1737 }
1738 
1740 
1742  u32 thread_index,
1743  snat_session_key_t * k,
1744  u32 address_index)
1745 {
1746  snat_address_t *a;
1747  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1748 
1749  ASSERT (address_index < vec_len (addresses));
1750 
1751  a = addresses + address_index;
1752 
1753  switch (k->protocol)
1754  {
1755 #define _(N, i, n, s) \
1756  case SNAT_PROTOCOL_##N: \
1757  ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1758  port_host_byte_order) == 1); \
1759  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1760  port_host_byte_order, 0); \
1761  a->busy_##n##_ports--; \
1762  a->busy_##n##_ports_per_thread[thread_index]--; \
1763  break;
1765 #undef _
1766  default:
1767  clib_warning("unknown_protocol");
1768  return;
1769  }
1770 }
1771 
1772 /**
1773  * @brief Match NAT44 static mapping.
1774  *
1775  * @param sm NAT main.
1776  * @param match Address and port to match.
1777  * @param mapping External or local address and port of the matched mapping.
1778  * @param by_external If 0 match by local address otherwise match by external
1779  * address.
1780  * @param is_addr_only If matched mapping is address only
1781  * @param twice_nat If matched mapping is twice NAT.
1782  *
1783  * @returns 0 if match found otherwise 1.
1784  */
1786  snat_session_key_t match,
1787  snat_session_key_t * mapping,
1788  u8 by_external,
1789  u8 *is_addr_only,
1790  u8 *twice_nat)
1791 {
1792  clib_bihash_kv_8_8_t kv, value;
1794  snat_session_key_t m_key;
1795  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1796  u32 rand, lo = 0, hi, mid;
1797 
1798  if (by_external)
1799  mapping_hash = &sm->static_mapping_by_external;
1800 
1801  m_key.addr = match.addr;
1802  m_key.port = clib_net_to_host_u16 (match.port);
1803  m_key.protocol = match.protocol;
1804  m_key.fib_index = match.fib_index;
1805 
1806  kv.key = m_key.as_u64;
1807 
1808  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1809  {
1810  /* Try address only mapping */
1811  m_key.port = 0;
1812  m_key.protocol = 0;
1813  kv.key = m_key.as_u64;
1814  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1815  return 1;
1816  }
1817 
1818  m = pool_elt_at_index (sm->static_mappings, value.value);
1819 
1820  if (by_external)
1821  {
1822  if (vec_len (m->locals))
1823  {
1824  hi = vec_len (m->locals) - 1;
1825  rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1826  while (lo < hi)
1827  {
1828  mid = ((hi - lo) >> 1) + lo;
1829  (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1830  }
1831  if (!(m->locals[lo].prefix >= rand))
1832  return 1;
1833  mapping->addr = m->locals[lo].addr;
1834  mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1835  }
1836  else
1837  {
1838  mapping->addr = m->local_addr;
1839  /* Address only mapping doesn't change port */
1840  mapping->port = m->addr_only ? match.port
1841  : clib_host_to_net_u16 (m->local_port);
1842  }
1843  mapping->fib_index = m->fib_index;
1844  mapping->protocol = m->proto;
1845  }
1846  else
1847  {
1848  mapping->addr = m->external_addr;
1849  /* Address only mapping doesn't change port */
1850  mapping->port = m->addr_only ? match.port
1851  : clib_host_to_net_u16 (m->external_port);
1852  mapping->fib_index = sm->outside_fib_index;
1853  }
1854 
1855  if (PREDICT_FALSE(is_addr_only != 0))
1856  *is_addr_only = m->addr_only;
1857 
1858  if (PREDICT_FALSE(twice_nat != 0))
1859  *twice_nat = m->twice_nat;
1860 
1861  return 0;
1862 }
1863 
1866 {
1867  snat_main_t *sm = &snat_main;
1868  return min + random_u32 (&sm->random_seed) /
1869  (random_u32_max() / (max - min + 1) + 1);
1870 }
1871 
1872 int
1874  u32 fib_index,
1875  u32 thread_index,
1876  snat_session_key_t * k,
1877  u32 * address_indexp,
1878  u16 port_per_thread,
1879  u32 snat_thread_index)
1880 {
1881  snat_main_t *sm = &snat_main;
1882 
1883  return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
1884  address_indexp, port_per_thread,
1885  snat_thread_index);
1886 }
1887 
1888 static int
1890  u32 fib_index,
1891  u32 thread_index,
1892  snat_session_key_t * k,
1893  u32 * address_indexp,
1894  u16 port_per_thread,
1895  u32 snat_thread_index)
1896 {
1897  int i, gi = 0;
1898  snat_address_t *a, *ga = 0;
1899  u32 portnum;
1900 
1901  for (i = 0; i < vec_len (addresses); i++)
1902  {
1903  a = addresses + i;
1904  switch (k->protocol)
1905  {
1906 #define _(N, j, n, s) \
1907  case SNAT_PROTOCOL_##N: \
1908  if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1909  { \
1910  if (a->fib_index == fib_index) \
1911  { \
1912  while (1) \
1913  { \
1914  portnum = (port_per_thread * \
1915  snat_thread_index) + \
1916  snat_random_port(1, port_per_thread) + 1024; \
1917  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1918  continue; \
1919  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1920  a->busy_##n##_ports_per_thread[thread_index]++; \
1921  a->busy_##n##_ports++; \
1922  k->addr = a->addr; \
1923  k->port = clib_host_to_net_u16(portnum); \
1924  *address_indexp = i; \
1925  return 0; \
1926  } \
1927  } \
1928  else if (a->fib_index == ~0) \
1929  { \
1930  ga = a; \
1931  gi = i; \
1932  } \
1933  } \
1934  break;
1936 #undef _
1937  default:
1938  clib_warning("unknown protocol");
1939  return 1;
1940  }
1941 
1942  }
1943 
1944  if (ga)
1945  {
1946  a = ga;
1947  switch (k->protocol)
1948  {
1949 #define _(N, j, n, s) \
1950  case SNAT_PROTOCOL_##N: \
1951  while (1) \
1952  { \
1953  portnum = (port_per_thread * \
1954  snat_thread_index) + \
1955  snat_random_port(1, port_per_thread) + 1024; \
1956  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1957  continue; \
1958  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1959  a->busy_##n##_ports_per_thread[thread_index]++; \
1960  a->busy_##n##_ports++; \
1961  k->addr = a->addr; \
1962  k->port = clib_host_to_net_u16(portnum); \
1963  *address_indexp = gi; \
1964  return 0; \
1965  }
1966  break;
1968 #undef _
1969  default:
1970  clib_warning ("unknown protocol");
1971  return 1;
1972  }
1973  }
1974 
1975  /* Totally out of translations to use... */
1977  return 1;
1978 }
1979 
1980 static int
1982  u32 fib_index,
1983  u32 thread_index,
1984  snat_session_key_t * k,
1985  u32 * address_indexp,
1986  u16 port_per_thread,
1987  u32 snat_thread_index)
1988 {
1989  snat_main_t *sm = &snat_main;
1990  snat_address_t *a = addresses;
1991  u16 m, ports, portnum, A, j;
1992  m = 16 - (sm->psid_offset + sm->psid_length);
1993  ports = (1 << (16 - sm->psid_length)) - (1 << m);
1994 
1995  if (!vec_len (addresses))
1996  goto exhausted;
1997 
1998  switch (k->protocol)
1999  {
2000 #define _(N, i, n, s) \
2001  case SNAT_PROTOCOL_##N: \
2002  if (a->busy_##n##_ports < ports) \
2003  { \
2004  while (1) \
2005  { \
2006  A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2007  j = snat_random_port(0, pow2_mask(m)); \
2008  portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2009  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2010  continue; \
2011  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2012  a->busy_##n##_ports++; \
2013  k->addr = a->addr; \
2014  k->port = clib_host_to_net_u16 (portnum); \
2015  *address_indexp = i; \
2016  return 0; \
2017  } \
2018  } \
2019  break;
2021 #undef _
2022  default:
2023  clib_warning("unknown protocol");
2024  return 1;
2025  }
2026 
2027 exhausted:
2028  /* Totally out of translations to use... */
2030  return 1;
2031 }
2032 
2033 static clib_error_t *
2035  unformat_input_t * input,
2036  vlib_cli_command_t * cmd)
2037 {
2038  unformat_input_t _line_input, *line_input = &_line_input;
2039  snat_main_t * sm = &snat_main;
2040  ip4_address_t start_addr, end_addr, this_addr;
2041  u32 start_host_order, end_host_order;
2042  u32 vrf_id = ~0;
2043  int i, count;
2044  int is_add = 1;
2045  int rv = 0;
2046  clib_error_t *error = 0;
2047  u8 twice_nat = 0;
2048 
2049  /* Get a line of input. */
2050  if (!unformat_user (input, unformat_line_input, line_input))
2051  return 0;
2052 
2053  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2054  {
2055  if (unformat (line_input, "%U - %U",
2056  unformat_ip4_address, &start_addr,
2057  unformat_ip4_address, &end_addr))
2058  ;
2059  else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
2060  ;
2061  else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
2062  end_addr = start_addr;
2063  else if (unformat (line_input, "twice-nat"))
2064  twice_nat = 1;
2065  else if (unformat (line_input, "del"))
2066  is_add = 0;
2067  else
2068  {
2069  error = clib_error_return (0, "unknown input '%U'",
2070  format_unformat_error, line_input);
2071  goto done;
2072  }
2073  }
2074 
2075  if (sm->static_mapping_only)
2076  {
2077  error = clib_error_return (0, "static mapping only mode");
2078  goto done;
2079  }
2080 
2081  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
2082  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
2083 
2084  if (end_host_order < start_host_order)
2085  {
2086  error = clib_error_return (0, "end address less than start address");
2087  goto done;
2088  }
2089 
2090  count = (end_host_order - start_host_order) + 1;
2091 
2092  if (count > 1024)
2093  clib_warning ("%U - %U, %d addresses...",
2094  format_ip4_address, &start_addr,
2095  format_ip4_address, &end_addr,
2096  count);
2097 
2098  this_addr = start_addr;
2099 
2100  for (i = 0; i < count; i++)
2101  {
2102  if (is_add)
2103  snat_add_address (sm, &this_addr, vrf_id, twice_nat);
2104  else
2105  rv = snat_del_address (sm, this_addr, 0, twice_nat);
2106 
2107  switch (rv)
2108  {
2109  case VNET_API_ERROR_NO_SUCH_ENTRY:
2110  error = clib_error_return (0, "S-NAT address not exist.");
2111  goto done;
2112  case VNET_API_ERROR_UNSPECIFIED:
2113  error = clib_error_return (0, "S-NAT address used in static mapping.");
2114  goto done;
2115  default:
2116  break;
2117  }
2118 
2119  increment_v4_address (&this_addr);
2120  }
2121 
2122 done:
2123  unformat_free (line_input);
2124 
2125  return error;
2126 }
2127 
2128 VLIB_CLI_COMMAND (add_address_command, static) = {
2129  .path = "nat44 add address",
2130  .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
2131  "[tenant-vrf <vrf-id>] [twice-nat] [del]",
2132  .function = add_address_command_fn,
2133 };
2134 
2135 static clib_error_t *
2137  unformat_input_t * input,
2138  vlib_cli_command_t * cmd)
2139 {
2140  unformat_input_t _line_input, *line_input = &_line_input;
2141  vnet_main_t * vnm = vnet_get_main();
2142  clib_error_t * error = 0;
2143  u32 sw_if_index;
2144  u32 * inside_sw_if_indices = 0;
2145  u32 * outside_sw_if_indices = 0;
2146  u8 is_output_feature = 0;
2147  int is_del = 0;
2148  int i;
2149 
2150  sw_if_index = ~0;
2151 
2152  /* Get a line of input. */
2153  if (!unformat_user (input, unformat_line_input, line_input))
2154  return 0;
2155 
2156  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2157  {
2158  if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
2159  vnm, &sw_if_index))
2160  vec_add1 (inside_sw_if_indices, sw_if_index);
2161  else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
2162  vnm, &sw_if_index))
2163  vec_add1 (outside_sw_if_indices, sw_if_index);
2164  else if (unformat (line_input, "output-feature"))
2165  is_output_feature = 1;
2166  else if (unformat (line_input, "del"))
2167  is_del = 1;
2168  else
2169  {
2170  error = clib_error_return (0, "unknown input '%U'",
2171  format_unformat_error, line_input);
2172  goto done;
2173  }
2174  }
2175 
2176  if (vec_len (inside_sw_if_indices))
2177  {
2178  for (i = 0; i < vec_len(inside_sw_if_indices); i++)
2179  {
2180  sw_if_index = inside_sw_if_indices[i];
2181  if (is_output_feature)
2182  {
2183  if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
2184  {
2185  error = clib_error_return (0, "%s %U failed",
2186  is_del ? "del" : "add",
2188  sw_if_index);
2189  goto done;
2190  }
2191  }
2192  else
2193  {
2194  if (snat_interface_add_del (sw_if_index, 1, is_del))
2195  {
2196  error = clib_error_return (0, "%s %U failed",
2197  is_del ? "del" : "add",
2199  sw_if_index);
2200  goto done;
2201  }
2202  }
2203  }
2204  }
2205 
2206  if (vec_len (outside_sw_if_indices))
2207  {
2208  for (i = 0; i < vec_len(outside_sw_if_indices); i++)
2209  {
2210  sw_if_index = outside_sw_if_indices[i];
2211  if (is_output_feature)
2212  {
2213  if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
2214  {
2215  error = clib_error_return (0, "%s %U failed",
2216  is_del ? "del" : "add",
2218  sw_if_index);
2219  goto done;
2220  }
2221  }
2222  else
2223  {
2224  if (snat_interface_add_del (sw_if_index, 0, is_del))
2225  {
2226  error = clib_error_return (0, "%s %U failed",
2227  is_del ? "del" : "add",
2229  sw_if_index);
2230  goto done;
2231  }
2232  }
2233  }
2234  }
2235 
2236 done:
2237  unformat_free (line_input);
2238  vec_free (inside_sw_if_indices);
2239  vec_free (outside_sw_if_indices);
2240 
2241  return error;
2242 }
2243 
2244 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
2245  .path = "set interface nat44",
2246  .function = snat_feature_command_fn,
2247  .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
2248  "[del]",
2249 };
2250 
2251 uword
2252 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2253 {
2254  u32 *r = va_arg (*args, u32 *);
2255 
2256  if (0);
2257 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2259 #undef _
2260  else
2261  return 0;
2262  return 1;
2263 }
2264 
2265 u8 *
2266 format_snat_protocol (u8 * s, va_list * args)
2267 {
2268  u32 i = va_arg (*args, u32);
2269  u8 *t = 0;
2270 
2271  switch (i)
2272  {
2273 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2275 #undef _
2276  default:
2277  s = format (s, "unknown");
2278  return s;
2279  }
2280  s = format (s, "%s", t);
2281  return s;
2282 }
2283 
2284 static clib_error_t *
2286  unformat_input_t * input,
2287  vlib_cli_command_t * cmd)
2288 {
2289  unformat_input_t _line_input, *line_input = &_line_input;
2290  clib_error_t * error = 0;
2291  ip4_address_t l_addr, e_addr;
2292  u32 l_port = 0, e_port = 0, vrf_id = ~0;
2293  int is_add = 1;
2294  int addr_only = 1;
2295  u32 sw_if_index = ~0;
2296  vnet_main_t * vnm = vnet_get_main();
2297  int rv;
2298  snat_protocol_t proto = ~0;
2299  u8 proto_set = 0;
2300  u8 twice_nat = 0;
2301 
2302  /* Get a line of input. */
2303  if (!unformat_user (input, unformat_line_input, line_input))
2304  return 0;
2305 
2306  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2307  {
2308  if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2309  &l_port))
2310  addr_only = 0;
2311  else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2312  ;
2313  else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2314  &e_addr, &e_port))
2315  addr_only = 0;
2316  else if (unformat (line_input, "external %U", unformat_ip4_address,
2317  &e_addr))
2318  ;
2319  else if (unformat (line_input, "external %U %u",
2320  unformat_vnet_sw_interface, vnm, &sw_if_index,
2321  &e_port))
2322  addr_only = 0;
2323 
2324  else if (unformat (line_input, "external %U",
2325  unformat_vnet_sw_interface, vnm, &sw_if_index))
2326  ;
2327  else if (unformat (line_input, "vrf %u", &vrf_id))
2328  ;
2329  else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2330  proto_set = 1;
2331  else if (unformat (line_input, "twice-nat"))
2332  twice_nat = 1;
2333  else if (unformat (line_input, "del"))
2334  is_add = 0;
2335  else
2336  {
2337  error = clib_error_return (0, "unknown input: '%U'",
2338  format_unformat_error, line_input);
2339  goto done;
2340  }
2341  }
2342 
2343  if (twice_nat && addr_only)
2344  {
2345  error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
2346  goto done;
2347  }
2348 
2349  if (!addr_only && !proto_set)
2350  {
2351  error = clib_error_return (0, "missing protocol");
2352  goto done;
2353  }
2354 
2355  rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2356  vrf_id, addr_only, sw_if_index, proto, is_add,
2357  twice_nat);
2358 
2359  switch (rv)
2360  {
2361  case VNET_API_ERROR_INVALID_VALUE:
2362  error = clib_error_return (0, "External port already in use.");
2363  goto done;
2364  case VNET_API_ERROR_NO_SUCH_ENTRY:
2365  if (is_add)
2366  error = clib_error_return (0, "External addres must be allocated.");
2367  else
2368  error = clib_error_return (0, "Mapping not exist.");
2369  goto done;
2370  case VNET_API_ERROR_NO_SUCH_FIB:
2371  error = clib_error_return (0, "No such VRF id.");
2372  goto done;
2373  case VNET_API_ERROR_VALUE_EXIST:
2374  error = clib_error_return (0, "Mapping already exist.");
2375  goto done;
2376  default:
2377  break;
2378  }
2379 
2380 done:
2381  unformat_free (line_input);
2382 
2383  return error;
2384 }
2385 
2386 /*?
2387  * @cliexpar
2388  * @cliexstart{snat add static mapping}
2389  * Static mapping allows hosts on the external network to initiate connection
2390  * to to the local network host.
2391  * To create static mapping between local host address 10.0.0.3 port 6303 and
2392  * external address 4.4.4.4 port 3606 for TCP protocol use:
2393  * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2394  * If not runnig "static mapping only" NAT plugin mode use before:
2395  * vpp# nat44 add address 4.4.4.4
2396  * To create static mapping between local and external address use:
2397  * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2398  * @cliexend
2399 ?*/
2400 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2401  .path = "nat44 add static mapping",
2402  .function = add_static_mapping_command_fn,
2403  .short_help =
2404  "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
2405  "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
2406 };
2407 
2408 static clib_error_t *
2410  unformat_input_t * input,
2411  vlib_cli_command_t * cmd)
2412 {
2413  unformat_input_t _line_input, *line_input = &_line_input;
2414  clib_error_t * error = 0;
2416  u32 port = 0, vrf_id = ~0;
2417  int is_add = 1;
2418  int addr_only = 1;
2419  u32 sw_if_index = ~0;
2420  vnet_main_t * vnm = vnet_get_main();
2421  int rv;
2422  snat_protocol_t proto;
2423 
2424  addr.as_u32 = 0;
2425 
2426  /* Get a line of input. */
2427  if (!unformat_user (input, unformat_line_input, line_input))
2428  return 0;
2429 
2430  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2431  {
2432  if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2433  ;
2434  else if (unformat (line_input, "external %U",
2435  unformat_vnet_sw_interface, vnm, &sw_if_index))
2436  ;
2437  else if (unformat (line_input, "vrf %u", &vrf_id))
2438  ;
2439  else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2440  &port))
2441  addr_only = 0;
2442  else if (unformat (line_input, "del"))
2443  is_add = 0;
2444  else
2445  {
2446  error = clib_error_return (0, "unknown input: '%U'",
2447  format_unformat_error, line_input);
2448  goto done;
2449  }
2450  }
2451 
2452  rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2453  vrf_id, addr_only, sw_if_index, proto, is_add,
2454  0);
2455 
2456  switch (rv)
2457  {
2458  case VNET_API_ERROR_INVALID_VALUE:
2459  error = clib_error_return (0, "External port already in use.");
2460  goto done;
2461  case VNET_API_ERROR_NO_SUCH_ENTRY:
2462  if (is_add)
2463  error = clib_error_return (0, "External addres must be allocated.");
2464  else
2465  error = clib_error_return (0, "Mapping not exist.");
2466  goto done;
2467  case VNET_API_ERROR_NO_SUCH_FIB:
2468  error = clib_error_return (0, "No such VRF id.");
2469  goto done;
2470  case VNET_API_ERROR_VALUE_EXIST:
2471  error = clib_error_return (0, "Mapping already exist.");
2472  goto done;
2473  default:
2474  break;
2475  }
2476 
2477 done:
2478  unformat_free (line_input);
2479 
2480  return error;
2481 }
2482 
2483 /*?
2484  * @cliexpar
2485  * @cliexstart{snat add identity mapping}
2486  * Identity mapping translate an IP address to itself.
2487  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2488  * use:
2489  * vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2490  * To create identity mapping for address 10.0.0.3 use:
2491  * vpp# nat44 add identity mapping 10.0.0.3
2492  * To create identity mapping for DHCP addressed interface use:
2493  * vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2494  * @cliexend
2495 ?*/
2496 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2497  .path = "nat44 add identity mapping",
2498  .function = add_identity_mapping_command_fn,
2499  .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2500  "[<protocol> <port>] [vrf <table-id>] [del]",
2501 };
2502 
2503 static clib_error_t *
2505  unformat_input_t * input,
2506  vlib_cli_command_t * cmd)
2507 {
2508  unformat_input_t _line_input, *line_input = &_line_input;
2509  clib_error_t * error = 0;
2510  ip4_address_t l_addr, e_addr;
2511  u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2512  int is_add = 1;
2513  int rv;
2514  snat_protocol_t proto;
2515  u8 proto_set = 0;
2516  nat44_lb_addr_port_t *locals = 0, local;
2517  u8 twice_nat = 0;
2518 
2519  /* Get a line of input. */
2520  if (!unformat_user (input, unformat_line_input, line_input))
2521  return 0;
2522 
2523  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2524  {
2525  if (unformat (line_input, "local %U:%u probability %u",
2526  unformat_ip4_address, &l_addr, &l_port, &probability))
2527  {
2528  memset (&local, 0, sizeof (local));
2529  local.addr = l_addr;
2530  local.port = (u16) l_port;
2531  local.probability = (u8) probability;
2532  vec_add1 (locals, local);
2533  }
2534  else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2535  &e_addr, &e_port))
2536  ;
2537  else if (unformat (line_input, "vrf %u", &vrf_id))
2538  ;
2539  else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2540  &proto))
2541  proto_set = 1;
2542  else if (unformat (line_input, "twice-nat"))
2543  twice_nat = 1;
2544  else if (unformat (line_input, "del"))
2545  is_add = 0;
2546  else
2547  {
2548  error = clib_error_return (0, "unknown input: '%U'",
2549  format_unformat_error, line_input);
2550  goto done;
2551  }
2552  }
2553 
2554  if (vec_len (locals) < 2)
2555  {
2556  error = clib_error_return (0, "at least two local must be set");
2557  goto done;
2558  }
2559 
2560  if (!proto_set)
2561  {
2562  error = clib_error_return (0, "missing protocol");
2563  goto done;
2564  }
2565 
2566  rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2567  locals, is_add, twice_nat);
2568 
2569  switch (rv)
2570  {
2571  case VNET_API_ERROR_INVALID_VALUE:
2572  error = clib_error_return (0, "External port already in use.");
2573  goto done;
2574  case VNET_API_ERROR_NO_SUCH_ENTRY:
2575  if (is_add)
2576  error = clib_error_return (0, "External addres must be allocated.");
2577  else
2578  error = clib_error_return (0, "Mapping not exist.");
2579  goto done;
2580  case VNET_API_ERROR_VALUE_EXIST:
2581  error = clib_error_return (0, "Mapping already exist.");
2582  goto done;
2583  default:
2584  break;
2585  }
2586 
2587 done:
2588  unformat_free (line_input);
2589  vec_free (locals);
2590 
2591  return error;
2592 }
2593 
2594 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2595  .path = "nat44 add load-balancing static mapping",
2597  .short_help =
2598  "nat44 add load-balancing static mapping protocol tcp|udp "
2599  "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
2600  "[vrf <table-id>] [del]",
2601 };
2602 
2603 static clib_error_t *
2605  unformat_input_t * input,
2606  vlib_cli_command_t * cmd)
2607 {
2608  unformat_input_t _line_input, *line_input = &_line_input;
2609  uword *bitmap = 0;
2610  int rv = 0;
2611  clib_error_t *error = 0;
2612 
2613  /* Get a line of input. */
2614  if (!unformat_user (input, unformat_line_input, line_input))
2615  return 0;
2616 
2617  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2618  {
2619  if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2620  ;
2621  else
2622  {
2623  error = clib_error_return (0, "unknown input '%U'",
2624  format_unformat_error, line_input);
2625  goto done;
2626  }
2627  }
2628 
2629  if (bitmap == 0)
2630  {
2631  error = clib_error_return (0, "List of workers must be specified.");
2632  goto done;
2633  }
2634 
2635  rv = snat_set_workers(bitmap);
2636 
2637  clib_bitmap_free (bitmap);
2638 
2639  switch (rv)
2640  {
2641  case VNET_API_ERROR_INVALID_WORKER:
2642  error = clib_error_return (0, "Invalid worker(s).");
2643  goto done;
2644  case VNET_API_ERROR_FEATURE_DISABLED:
2645  error = clib_error_return (0,
2646  "Supported only if 2 or more workes available.");
2647  goto done;
2648  default:
2649  break;
2650  }
2651 
2652 done:
2653  unformat_free (line_input);
2654 
2655  return error;
2656 }
2657 
2658 /*?
2659  * @cliexpar
2660  * @cliexstart{set snat workers}
2661  * Set NAT workers if 2 or more workers available, use:
2662  * vpp# set snat workers 0-2,5
2663  * @cliexend
2664 ?*/
2665 VLIB_CLI_COMMAND (set_workers_command, static) = {
2666  .path = "set nat workers",
2667  .function = set_workers_command_fn,
2668  .short_help =
2669  "set nat workers <workers-list>",
2670 };
2671 
2672 static clib_error_t *
2674  unformat_input_t * input,
2675  vlib_cli_command_t * cmd)
2676 {
2677  unformat_input_t _line_input, *line_input = &_line_input;
2678  u32 domain_id = 0;
2679  u32 src_port = 0;
2680  u8 enable = 1;
2681  int rv = 0;
2682  clib_error_t *error = 0;
2683 
2684  /* Get a line of input. */
2685  if (!unformat_user (input, unformat_line_input, line_input))
2686  return 0;
2687 
2688  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2689  {
2690  if (unformat (line_input, "domain %d", &domain_id))
2691  ;
2692  else if (unformat (line_input, "src-port %d", &src_port))
2693  ;
2694  else if (unformat (line_input, "disable"))
2695  enable = 0;
2696  else
2697  {
2698  error = clib_error_return (0, "unknown input '%U'",
2699  format_unformat_error, line_input);
2700  goto done;
2701  }
2702  }
2703 
2704  rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2705 
2706  if (rv)
2707  {
2708  error = clib_error_return (0, "ipfix logging enable failed");
2709  goto done;
2710  }
2711 
2712 done:
2713  unformat_free (line_input);
2714 
2715  return error;
2716 }
2717 
2718 /*?
2719  * @cliexpar
2720  * @cliexstart{snat ipfix logging}
2721  * To enable NAT IPFIX logging use:
2722  * vpp# nat ipfix logging
2723  * To set IPFIX exporter use:
2724  * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2725  * @cliexend
2726 ?*/
2727 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2728  .path = "nat ipfix logging",
2730  .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2731 };
2732 
2733 static u32
2735 {
2736  snat_main_t *sm = &snat_main;
2737  u32 next_worker_index = 0;
2738  u32 hash;
2739 
2740  next_worker_index = sm->first_worker_index;
2741  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2742  (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2743 
2744  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2745  next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2746  else
2747  next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2748 
2749  return next_worker_index;
2750 }
2751 
2752 static u32
2754 {
2755  snat_main_t *sm = &snat_main;
2756  udp_header_t *udp;
2757  u16 port;
2758  snat_session_key_t m_key;
2759  clib_bihash_kv_8_8_t kv, value;
2761  nat_ed_ses_key_t key;
2762  clib_bihash_kv_16_8_t s_kv, s_value;
2764  snat_session_t *s;
2765  int i;
2766  u32 proto;
2767  u32 next_worker_index = 0;
2768 
2769  /* first try static mappings without port */
2771  {
2772  m_key.addr = ip0->dst_address;
2773  m_key.port = 0;
2774  m_key.protocol = 0;
2775  m_key.fib_index = rx_fib_index0;
2776  kv.key = m_key.as_u64;
2777  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2778  {
2779  m = pool_elt_at_index (sm->static_mappings, value.value);
2780  return m->worker_index;
2781  }
2782  }
2783 
2784  proto = ip_proto_to_snat_proto (ip0->protocol);
2785  udp = ip4_next_header (ip0);
2786  port = udp->dst_port;
2787 
2788  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2789  {
2791  return vlib_get_thread_index ();
2792 
2793  if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2794  {
2795  nat_reass_ip4_t *reass;
2796 
2797  reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2798  ip0->fragment_id, ip0->protocol);
2799 
2800  if (reass && (reass->thread_index != (u32) ~ 0))
2801  return reass->thread_index;
2802  else
2803  return vlib_get_thread_index ();
2804  }
2805  }
2806 
2807  /* unknown protocol */
2808  if (PREDICT_FALSE (proto == ~0))
2809  {
2810  key.l_addr = ip0->dst_address;
2811  key.r_addr = ip0->src_address;
2812  key.fib_index = rx_fib_index0;
2813  key.proto = ip0->protocol;
2814  key.r_port = 0;
2815  key.l_port = 0;
2816  s_kv.key[0] = key.as_u64[0];
2817  s_kv.key[1] = key.as_u64[1];
2818 
2819  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2820  {
2821  for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2822  {
2823  tsm = vec_elt_at_index (sm->per_thread_data, i);
2824  if (!pool_is_free_index(tsm->sessions, s_value.value))
2825  {
2826  s = pool_elt_at_index (tsm->sessions, s_value.value);
2827  if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2828  s->out2in.port == ip0->protocol &&
2830  return i;
2831  }
2832  }
2833  }
2834 
2835  /* if no session use current thread */
2836  return vlib_get_thread_index ();
2837  }
2838 
2839  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2840  {
2841  icmp46_header_t * icmp = (icmp46_header_t *) udp;
2842  icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2843  if (!icmp_is_error_message (icmp))
2844  port = echo->identifier;
2845  else
2846  {
2847  ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2848  proto = ip_proto_to_snat_proto (inner_ip->protocol);
2849  void *l4_header = ip4_next_header (inner_ip);
2850  switch (proto)
2851  {
2852  case SNAT_PROTOCOL_ICMP:
2853  icmp = (icmp46_header_t*)l4_header;
2854  echo = (icmp_echo_header_t *)(icmp + 1);
2855  port = echo->identifier;
2856  break;
2857  case SNAT_PROTOCOL_UDP:
2858  case SNAT_PROTOCOL_TCP:
2859  port = ((tcp_udp_header_t*)l4_header)->src_port;
2860  break;
2861  default:
2862  return vlib_get_thread_index ();
2863  }
2864  }
2865  }
2866 
2867  /* try static mappings with port */
2868  if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2869  {
2870  m_key.addr = ip0->dst_address;
2871  m_key.port = clib_net_to_host_u16 (port);
2872  m_key.protocol = proto;
2873  m_key.fib_index = rx_fib_index0;
2874  kv.key = m_key.as_u64;
2875  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2876  {
2877  m = pool_elt_at_index (sm->static_mappings, value.value);
2878  return m->worker_index;
2879  }
2880  }
2881 
2882  /* worker by outside port */
2883  next_worker_index = sm->first_worker_index;
2884  next_worker_index +=
2885  sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2886  return next_worker_index;
2887 }
2888 
2889 static clib_error_t *
2891 {
2892  snat_main_t * sm = &snat_main;
2893  u32 translation_buckets = 1024;
2894  u32 translation_memory_size = 128<<20;
2895  u32 user_buckets = 128;
2896  u32 user_memory_size = 64<<20;
2897  u32 max_translations_per_user = 100;
2898  u32 outside_vrf_id = 0;
2899  u32 inside_vrf_id = 0;
2900  u32 static_mapping_buckets = 1024;
2901  u32 static_mapping_memory_size = 64<<20;
2902  u32 nat64_bib_buckets = 1024;
2903  u32 nat64_bib_memory_size = 128 << 20;
2904  u32 nat64_st_buckets = 2048;
2905  u32 nat64_st_memory_size = 256 << 20;
2906  u8 static_mapping_only = 0;
2907  u8 static_mapping_connection_tracking = 0;
2909 
2910  sm->deterministic = 0;
2911 
2912  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2913  {
2914  if (unformat (input, "translation hash buckets %d", &translation_buckets))
2915  ;
2916  else if (unformat (input, "translation hash memory %d",
2917  &translation_memory_size));
2918  else if (unformat (input, "user hash buckets %d", &user_buckets))
2919  ;
2920  else if (unformat (input, "user hash memory %d",
2921  &user_memory_size))
2922  ;
2923  else if (unformat (input, "max translations per user %d",
2924  &max_translations_per_user))
2925  ;
2926  else if (unformat (input, "outside VRF id %d",
2927  &outside_vrf_id))
2928  ;
2929  else if (unformat (input, "inside VRF id %d",
2930  &inside_vrf_id))
2931  ;
2932  else if (unformat (input, "static mapping only"))
2933  {
2934  static_mapping_only = 1;
2935  if (unformat (input, "connection tracking"))
2936  static_mapping_connection_tracking = 1;
2937  }
2938  else if (unformat (input, "deterministic"))
2939  sm->deterministic = 1;
2940  else if (unformat (input, "nat64 bib hash buckets %d",
2941  &nat64_bib_buckets))
2942  ;
2943  else if (unformat (input, "nat64 bib hash memory %d",
2944  &nat64_bib_memory_size))
2945  ;
2946  else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2947  ;
2948  else if (unformat (input, "nat64 st hash memory %d",
2949  &nat64_st_memory_size))
2950  ;
2951  else
2952  return clib_error_return (0, "unknown input '%U'",
2953  format_unformat_error, input);
2954  }
2955 
2956  /* for show commands, etc. */
2957  sm->translation_buckets = translation_buckets;
2958  sm->translation_memory_size = translation_memory_size;
2959  /* do not exceed load factor 10 */
2960  sm->max_translations = 10 * translation_buckets;
2961  sm->user_buckets = user_buckets;
2962  sm->user_memory_size = user_memory_size;
2963  sm->max_translations_per_user = max_translations_per_user;
2964  sm->outside_vrf_id = outside_vrf_id;
2966  outside_vrf_id,
2968  sm->inside_vrf_id = inside_vrf_id;
2970  inside_vrf_id,
2972  sm->static_mapping_only = static_mapping_only;
2973  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2974 
2975  nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2976  nat64_st_memory_size);
2977 
2978  if (sm->deterministic)
2979  {
2981  sm->in2out_output_node_index = ~0;
2985  }
2986  else
2987  {
2990  sm->in2out_node_index = snat_in2out_node.index;
2992  sm->out2in_node_index = snat_out2in_node.index;
2993  if (!static_mapping_only ||
2994  (static_mapping_only && static_mapping_connection_tracking))
2995  {
2998 
2999  vec_foreach (tsm, sm->per_thread_data)
3000  {
3001  clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
3002  translation_memory_size);
3003 
3004  clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
3005  translation_memory_size);
3006 
3007  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3008  user_memory_size);
3009  }
3010 
3011  clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
3012  translation_buckets, translation_memory_size);
3013 
3014  clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
3015  translation_buckets, translation_memory_size);
3016  }
3017  else
3018  {
3021  }
3022  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3023  "static_mapping_by_local", static_mapping_buckets,
3024  static_mapping_memory_size);
3025 
3026  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3027  "static_mapping_by_external", static_mapping_buckets,
3028  static_mapping_memory_size);
3029  }
3030 
3031  return 0;
3032 }
3033 
3035 
3036 u8 * format_snat_session_state (u8 * s, va_list * args)
3037 {
3038  u32 i = va_arg (*args, u32);
3039  u8 *t = 0;
3040 
3041  switch (i)
3042  {
3043 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
3045 #undef _
3046  default:
3047  t = format (t, "unknown");
3048  }
3049  s = format (s, "%s", t);
3050  return s;
3051 }
3052 
3053 u8 * format_snat_key (u8 * s, va_list * args)
3054 {
3055  snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
3056 
3057  s = format (s, "%U proto %U port %d fib %d",
3058  format_ip4_address, &key->addr,
3060  clib_net_to_host_u16 (key->port), key->fib_index);
3061  return s;
3062 }
3063 
3064 u8 * format_snat_session (u8 * s, va_list * args)
3065 {
3066  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
3067  snat_session_t * sess = va_arg (*args, snat_session_t *);
3068 
3069  if (snat_is_unk_proto_session (sess))
3070  {
3071  s = format (s, " i2o %U proto %u fib %u\n",
3072  format_ip4_address, &sess->in2out.addr,
3073  clib_net_to_host_u16 (sess->in2out.port),
3074  sess->in2out.fib_index);
3075  s = format (s, " o2i %U proto %u fib %u\n",
3076  format_ip4_address, &sess->out2in.addr,
3077  clib_net_to_host_u16 (sess->out2in.port),
3078  sess->out2in.fib_index);
3079  }
3080  else
3081  {
3082  s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
3083  s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
3084  }
3085  if (is_twice_nat_session (sess))
3086  {
3087  s = format (s, " external host o2i %U:%d i2o %U:%d\n",
3088  format_ip4_address, &sess->ext_host_addr,
3089  clib_net_to_host_u16 (sess->ext_host_port),
3090  format_ip4_address, &sess->ext_host_nat_addr,
3091  clib_net_to_host_u16 (sess->ext_host_nat_port));
3092  }
3093  else
3094  {
3095  if (sess->ext_host_addr.as_u32)
3096  s = format (s, " external host %U\n",
3097  format_ip4_address, &sess->ext_host_addr);
3098  }
3099  s = format (s, " last heard %.2f\n", sess->last_heard);
3100  s = format (s, " total pkts %d, total bytes %lld\n",
3101  sess->total_pkts, sess->total_bytes);
3102  if (snat_is_session_static (sess))
3103  s = format (s, " static translation\n");
3104  else
3105  s = format (s, " dynamic translation\n");
3106  if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
3107  s = format (s, " load-balancing\n");
3108  if (is_twice_nat_session (sess))
3109  s = format (s, " twice-nat\n");
3110 
3111  return s;
3112 }
3113 
3114 u8 * format_snat_user (u8 * s, va_list * args)
3115 {
3117  snat_user_t * u = va_arg (*args, snat_user_t *);
3118  int verbose = va_arg (*args, int);
3119  dlist_elt_t * head, * elt;
3120  u32 elt_index, head_index;
3121  u32 session_index;
3122  snat_session_t * sess;
3123 
3124  s = format (s, "%U: %d dynamic translations, %d static translations\n",
3126 
3127  if (verbose == 0)
3128  return s;
3129 
3130  if (u->nsessions || u->nstaticsessions)
3131  {
3132  head_index = u->sessions_per_user_list_head_index;
3133  head = pool_elt_at_index (sm->list_pool, head_index);
3134 
3135  elt_index = head->next;
3136  elt = pool_elt_at_index (sm->list_pool, elt_index);
3137  session_index = elt->value;
3138 
3139  while (session_index != ~0)
3140  {
3141  sess = pool_elt_at_index (sm->sessions, session_index);
3142 
3143  s = format (s, " %U\n", format_snat_session, sm, sess);
3144 
3145  elt_index = elt->next;
3146  elt = pool_elt_at_index (sm->list_pool, elt_index);
3147  session_index = elt->value;
3148  }
3149  }
3150 
3151  return s;
3152 }
3153 
3154 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3155 {
3156  snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3157  nat44_lb_addr_port_t *local;
3158 
3159  if (m->addr_only)
3160  s = format (s, "local %U external %U vrf %d %s",
3163  m->vrf_id, m->twice_nat ? "twice-nat" : "");
3164  else
3165  {
3166  if (vec_len (m->locals))
3167  {
3168  s = format (s, "%U vrf %d external %U:%d %s",
3170  m->vrf_id,
3172  m->twice_nat ? "twice-nat" : "");
3173  vec_foreach (local, m->locals)
3174  s = format (s, "\n local %U:%d probability %d\%",
3175  format_ip4_address, &local->addr, local->port,
3176  local->probability);
3177  }
3178  else
3179  s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
3183  m->vrf_id, m->twice_nat ? "twice-nat" : "");
3184  }
3185  return s;
3186 }
3187 
3188 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3189 {
3191  vnet_main_t *vnm = vnet_get_main();
3192 
3193  if (m->addr_only)
3194  s = format (s, "local %U external %U vrf %d",
3197  m->vrf_id);
3198  else
3199  s = format (s, "%U local %U:%d external %U:%d vrf %d",
3201  format_ip4_address, &m->l_addr, m->l_port,
3203  m->e_port, m->vrf_id);
3204 
3205  return s;
3206 }
3207 
3208 u8 * format_det_map_ses (u8 * s, va_list * args)
3209 {
3210  snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3211  ip4_address_t in_addr, out_addr;
3212  u32 in_offset, out_offset;
3213  snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3214  u32 * i = va_arg (*args, u32 *);
3215 
3216  u32 user_index = *i / SNAT_DET_SES_PER_USER;
3217  in_addr.as_u32 = clib_host_to_net_u32 (
3218  clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3219  in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3220  clib_net_to_host_u32(det_map->in_addr.as_u32);
3221  out_offset = in_offset / det_map->sharing_ratio;
3222  out_addr.as_u32 = clib_host_to_net_u32(
3223  clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3224  s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3225  format_ip4_address, &in_addr,
3226  clib_net_to_host_u16 (ses->in_port),
3227  format_ip4_address, &out_addr,
3228  clib_net_to_host_u16 (ses->out.out_port),
3230  clib_net_to_host_u16 (ses->out.ext_host_port),
3232  ses->expire);
3233 
3234  return s;
3235 }
3236 
3237 static clib_error_t *
3239  unformat_input_t * input,
3240  vlib_cli_command_t * cmd)
3241 {
3242  int verbose = 0;
3243  snat_main_t * sm = &snat_main;
3244  snat_user_t * u;
3247  snat_address_t * ap;
3248  vnet_main_t *vnm = vnet_get_main();
3250  u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
3251  uword j = 0;
3253  snat_det_map_t * dm;
3254  snat_det_session_t * ses;
3255 
3256  if (unformat (input, "detail"))
3257  verbose = 1;
3258  else if (unformat (input, "verbose"))
3259  verbose = 2;
3260 
3261  if (sm->static_mapping_only)
3262  {
3264  vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
3265  "tracking");
3266  else
3267  vlib_cli_output (vm, "NAT plugin mode: static mapping only");
3268  }
3269  else if (sm->deterministic)
3270  {
3271  vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
3272  }
3273  else
3274  {
3275  vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
3276  }
3277 
3278  if (verbose > 0)
3279  {
3280  pool_foreach (i, sm->interfaces,
3281  ({
3282  vlib_cli_output (vm, "%U %s", format_vnet_sw_if_index_name, vnm,
3283  i->sw_if_index,
3284  (nat_interface_is_inside(i) &&
3285  nat_interface_is_outside(i)) ? "in out" :
3286  (nat_interface_is_inside(i) ? "in" : "out"));
3287  }));
3288 
3290  ({
3291  vlib_cli_output (vm, "%U output-feature %s",
3292  format_vnet_sw_if_index_name, vnm, i->sw_if_index,
3293  (nat_interface_is_inside(i) &&
3294  nat_interface_is_outside(i)) ? "in out" :
3295  (nat_interface_is_inside(i) ? "in" : "out"));
3296  }));
3297 
3298  if (vec_len (sm->auto_add_sw_if_indices))
3299  {
3300  vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
3301  vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
3302  {
3304  *sw_if_index);
3305  }
3306  }
3307 
3309  {
3310  vlib_cli_output (vm, "NAT44 twice-nat pool addresses interfaces:");
3312  {
3314  *sw_if_index);
3315  }
3316  }
3317 
3318  vlib_cli_output (vm, "NAT44 pool addresses:");
3319  vec_foreach (ap, sm->addresses)
3320  {
3321  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3322  if (ap->fib_index != ~0)
3323  vlib_cli_output (vm, " tenant VRF: %u",
3325  else
3326  vlib_cli_output (vm, " tenant VRF independent");
3327 #define _(N, i, n, s) \
3328  vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
3330 #undef _
3331  }
3332 
3333  vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
3335  {
3336  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3337  if (ap->fib_index != ~0)
3338  vlib_cli_output (vm, " tenant VRF: %u",
3340  else
3341  vlib_cli_output (vm, " tenant VRF independent");
3342 #define _(N, i, n, s) \
3343  vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
3345 #undef _
3346  }
3347  }
3348 
3349  if (sm->num_workers > 1)
3350  {
3351  vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
3352  if (verbose > 0)
3353  {
3354  vec_foreach (worker, sm->workers)
3355  {
3357  vlib_worker_threads + *worker + sm->first_worker_index;
3358  vlib_cli_output (vm, " %s", w->name);
3359  }
3360  }
3361  }
3362 
3363  if (sm->deterministic)
3364  {
3365  vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
3366  vlib_cli_output (vm, "tcp-established timeout: %dsec",
3368  vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
3370  vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
3371  vlib_cli_output (vm, "%d deterministic mappings",
3372  pool_elts (sm->det_maps));
3373  if (verbose > 0)
3374  {
3375  pool_foreach (dm, sm->det_maps,
3376  ({
3377  vlib_cli_output (vm, "in %U/%d out %U/%d\n",
3378  format_ip4_address, &dm->in_addr, dm->in_plen,
3379  format_ip4_address, &dm->out_addr, dm->out_plen);
3380  vlib_cli_output (vm, " outside address sharing ratio: %d\n",
3381  dm->sharing_ratio);
3382  vlib_cli_output (vm, " number of ports per inside host: %d\n",
3383  dm->ports_per_host);
3384  vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
3385  if (verbose > 1)
3386  {
3387  vec_foreach_index (j, dm->sessions)
3388  {
3389  ses = vec_elt_at_index (dm->sessions, j);
3390  if (ses->in_port)
3391  vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
3392  &j);
3393  }
3394  }
3395  }));
3396  }
3397  }
3398  else
3399  {
3400  if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
3401  {
3402  vlib_cli_output (vm, "%d static mappings",
3403  pool_elts (sm->static_mappings));
3404 
3405  if (verbose > 0)
3406  {
3407  pool_foreach (m, sm->static_mappings,
3408  ({
3409  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3410  }));
3411  }
3412  }
3413  else
3414  {
3415  vec_foreach (tsm, sm->per_thread_data)
3416  {
3417  users_num += pool_elts (tsm->users);
3418  sessions_num += pool_elts (tsm->sessions);
3419  }
3420 
3421  vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3422  " %d static mappings, %d twice-nat addresses",
3423  users_num,
3424  vec_len (sm->addresses),
3425  sessions_num,
3426  pool_elts (sm->static_mappings),
3427  vec_len (sm->twice_nat_addresses));
3428 
3429  if (verbose > 0)
3430  {
3431  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3432  verbose - 1);
3433  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3434  verbose - 1);
3435  vec_foreach_index (j, sm->per_thread_data)
3436  {
3437  tsm = vec_elt_at_index (sm->per_thread_data, j);
3438 
3439  if (pool_elts (tsm->users) == 0)
3440  continue;
3441 
3443  vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3444  w->lcore_id);
3445  vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
3446  verbose - 1);
3447  vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
3448  verbose - 1);
3449  vlib_cli_output (vm, " %d list pool elements",
3450  pool_elts (tsm->list_pool));
3451 
3452  pool_foreach (u, tsm->users,
3453  ({
3454  vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
3455  verbose - 1);
3456  }));
3457  }
3458 
3459  if (pool_elts (sm->static_mappings))
3460  {
3461  vlib_cli_output (vm, "static mappings:");
3462  pool_foreach (m, sm->static_mappings,
3463  ({
3464  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3465  }));
3466  for (j = 0; j < vec_len (sm->to_resolve); j++)
3467  {
3468  rp = sm->to_resolve + j;
3469  vlib_cli_output (vm, "%U",
3471  }
3472  }
3473  }
3474  }
3475  }
3476 
3477  return 0;
3478 }
3479 
3480 VLIB_CLI_COMMAND (show_snat_command, static) = {
3481  .path = "show nat44",
3482  .short_help = "show nat44",
3483  .function = show_snat_command_fn,
3484 };
3485 
3486 
3487 static void
3489  uword opaque,
3490  u32 sw_if_index,
3491  ip4_address_t * address,
3492  u32 address_length,
3493  u32 if_address_index,
3494  u32 is_delete)
3495 {
3496  snat_main_t *sm = &snat_main;
3498  u32 *indices_to_delete = 0;
3499  ip4_address_t l_addr;
3500  int i, j;
3501  int rv;
3502  u8 twice_nat = 0;
3503  snat_address_t *addresses = sm->addresses;
3504 
3505  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3506  {
3507  if (sw_if_index == sm->auto_add_sw_if_indices[i])
3508  goto match;
3509  }
3510 
3511  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3512  {
3513  twice_nat = 1;
3514  addresses = sm->twice_nat_addresses;
3515  if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3516  goto match;
3517  }
3518 
3519  return;
3520 
3521 match:
3522  if (!is_delete)
3523  {
3524  /* Don't trip over lease renewal, static config */
3525  for (j = 0; j < vec_len(addresses); j++)
3526  if (addresses[j].addr.as_u32 == address->as_u32)
3527  return;
3528 
3529  snat_add_address (sm, address, ~0, twice_nat);
3530  /* Scan static map resolution vector */
3531  for (j = 0; j < vec_len (sm->to_resolve); j++)
3532  {
3533  rp = sm->to_resolve + j;
3534  /* On this interface? */
3535  if (rp->sw_if_index == sw_if_index)
3536  {
3537  /* Indetity mapping? */
3538  if (rp->l_addr.as_u32 == 0)
3539  l_addr.as_u32 = address[0].as_u32;
3540  else
3541  l_addr.as_u32 = rp->l_addr.as_u32;
3542  /* Add the static mapping */
3543  rv = snat_add_static_mapping (l_addr,
3544  address[0],
3545  rp->l_port,
3546  rp->e_port,
3547  rp->vrf_id,
3548  rp->addr_only,
3549  ~0 /* sw_if_index */,
3550  rp->proto,
3551  rp->is_add,
3552  0);
3553  if (rv)
3554  clib_warning ("snat_add_static_mapping returned %d",
3555  rv);
3556  vec_add1 (indices_to_delete, j);
3557  }
3558  }
3559  /* If we resolved any of the outstanding static mappings */
3560  if (vec_len(indices_to_delete))
3561  {
3562  /* Delete them */
3563  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3564  vec_delete(sm->to_resolve, 1, j);
3565  vec_free(indices_to_delete);
3566  }
3567  return;
3568  }
3569  else
3570  {
3571  (void) snat_del_address(sm, address[0], 1, twice_nat);
3572  return;
3573  }
3574 }
3575 
3576 
3577 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3578  u8 twice_nat)
3579 {
3580  ip4_main_t * ip4_main = sm->ip4_main;
3581  ip4_address_t * first_int_addr;
3583  u32 *indices_to_delete = 0;
3584  int i, j;
3585  u32 *auto_add_sw_if_indices =
3587 
3588  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3589  0 /* just want the address*/);
3590 
3591  for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3592  {
3593  if (auto_add_sw_if_indices[i] == sw_if_index)
3594  {
3595  if (is_del)
3596  {
3597  /* if have address remove it */
3598  if (first_int_addr)
3599  (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3600  else
3601  {
3602  for (j = 0; j < vec_len (sm->to_resolve); j++)
3603  {
3604  rp = sm->to_resolve + j;
3605  if (rp->sw_if_index == sw_if_index)
3606  vec_add1 (indices_to_delete, j);
3607  }
3608  if (vec_len(indices_to_delete))
3609  {
3610  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3611  vec_del1(sm->to_resolve, j);
3612  vec_free(indices_to_delete);
3613  }
3614  }
3615  if (twice_nat)
3617  else
3619  }
3620  else
3621  return VNET_API_ERROR_VALUE_EXIST;
3622 
3623  return 0;
3624  }
3625  }
3626 
3627  if (is_del)
3628  return VNET_API_ERROR_NO_SUCH_ENTRY;
3629 
3630  /* add to the auto-address list */
3631  if (twice_nat)
3632  vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3633  else
3634  vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3635 
3636  /* If the address is already bound - or static - add it now */
3637  if (first_int_addr)
3638  snat_add_address (sm, first_int_addr, ~0, twice_nat);
3639 
3640  return 0;
3641 }
3642 
3643 static clib_error_t *
3645  unformat_input_t * input,
3646  vlib_cli_command_t * cmd)
3647 {
3648  snat_main_t *sm = &snat_main;
3649  unformat_input_t _line_input, *line_input = &_line_input;
3650  u32 sw_if_index;
3651  int rv;
3652  int is_del = 0;
3653  clib_error_t *error = 0;
3654  u8 twice_nat = 0;
3655 
3656  /* Get a line of input. */
3657  if (!unformat_user (input, unformat_line_input, line_input))
3658  return 0;
3659 
3660  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3661  {
3662  if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3663  sm->vnet_main, &sw_if_index))
3664  ;
3665  else if (unformat (line_input, "twice-nat"))
3666  twice_nat = 1;
3667  else if (unformat (line_input, "del"))
3668  is_del = 1;
3669  else
3670  {
3671  error = clib_error_return (0, "unknown input '%U'",
3672  format_unformat_error, line_input);
3673  goto done;
3674  }
3675  }
3676 
3677  rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
3678 
3679  switch (rv)
3680  {
3681  case 0:
3682  break;
3683 
3684  default:
3685  error = clib_error_return (0, "snat_add_interface_address returned %d",
3686  rv);
3687  goto done;
3688  }
3689 
3690 done:
3691  unformat_free (line_input);
3692 
3693  return error;
3694 }
3695 
3696 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3697  .path = "nat44 add interface address",
3698  .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
3700 };
3701 
3702 int
3704  snat_protocol_t proto, u32 vrf_id, int is_in)
3705 {
3707  clib_bihash_kv_8_8_t kv, value;
3708  ip4_header_t ip;
3709  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3710  snat_session_key_t key;
3711  snat_session_t *s;
3712  clib_bihash_8_8_t *t;
3713  snat_user_key_t u_key;
3714  snat_user_t *u;
3715 
3716  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3717  if (sm->num_workers > 1)
3718  tsm =
3720  sm->worker_in2out_cb (&ip, fib_index));
3721  else
3722  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3723 
3724  key.addr.as_u32 = addr->as_u32;
3725  key.port = clib_host_to_net_u16 (port);
3726  key.protocol = proto;
3727  key.fib_index = fib_index;
3728  kv.key = key.as_u64;
3729  t = is_in ? &tsm->in2out : &tsm->out2in;
3730  if (!clib_bihash_search_8_8 (t, &kv, &value))
3731  {
3732  s = pool_elt_at_index (tsm->sessions, value.value);
3733  kv.key = s->in2out.as_u64;
3734  clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3735  kv.key = s->out2in.as_u64;
3736  clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3737  u_key.addr = s->in2out.addr;
3738  u_key.fib_index = s->in2out.fib_index;
3739  kv.key = u_key.as_u64;
3740  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3741  {
3742  u = pool_elt_at_index (tsm->users, value.value);
3743  u->nsessions--;
3744  }
3745  clib_dlist_remove (tsm->list_pool, s->per_user_index);
3746  pool_put (tsm->sessions, s);
3747  return 0;
3748  }
3749 
3750  return VNET_API_ERROR_NO_SUCH_ENTRY;
3751 }
3752 
3753 static clib_error_t *
3755  unformat_input_t * input,
3756  vlib_cli_command_t * cmd)
3757 {
3758  snat_main_t *sm = &snat_main;
3759  unformat_input_t _line_input, *line_input = &_line_input;
3760  int is_in = 0;
3761  clib_error_t *error = 0;
3763  u32 port = 0, vrf_id = sm->outside_vrf_id;
3764  snat_protocol_t proto;
3765  int rv;
3766 
3767  /* Get a line of input. */
3768  if (!unformat_user (input, unformat_line_input, line_input))
3769  return 0;
3770 
3771  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3772  {
3773  if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3774  unformat_snat_protocol, &proto))
3775  ;
3776  else if (unformat (line_input, "in"))
3777  {
3778  is_in = 1;
3779  vrf_id = sm->inside_vrf_id;
3780  }
3781  else if (unformat (line_input, "vrf %u", &vrf_id))
3782  ;
3783  else
3784  {
3785  error = clib_error_return (0, "unknown input '%U'",
3786  format_unformat_error, line_input);
3787  goto done;
3788  }
3789  }
3790 
3791  rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3792 
3793  switch (rv)
3794  {
3795  case 0:
3796  break;
3797 
3798  default:
3799  error = clib_error_return (0, "nat44_del_session returned %d", rv);
3800  goto done;
3801  }
3802 
3803 done:
3804  unformat_free (line_input);
3805 
3806  return error;
3807 }
3808 
3809 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3810  .path = "nat44 del session",
3811  .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3812  .function = nat44_del_session_command_fn,
3813 };
3814 
3815 static clib_error_t *
3817  unformat_input_t * input,
3818  vlib_cli_command_t * cmd)
3819 {
3820  snat_main_t *sm = &snat_main;
3821  unformat_input_t _line_input, *line_input = &_line_input;
3822  clib_error_t *error = 0;
3823  u32 psid, psid_offset, psid_length;
3824 
3825  /* Get a line of input. */
3826  if (!unformat_user (input, unformat_line_input, line_input))
3827  return 0;
3828 
3829  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3830  {
3831  if (unformat (line_input, "default"))
3833  else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3834  &psid, &psid_offset, &psid_length))
3835  {
3837  sm->psid = (u16) psid;
3838  sm->psid_offset = (u16) psid_offset;
3839  sm->psid_length = (u16) psid_length;
3840  }
3841  else
3842  {
3843  error = clib_error_return (0, "unknown input '%U'",
3844  format_unformat_error, line_input);
3845  goto done;
3846  }
3847  }
3848 
3849 done:
3850  unformat_free (line_input);
3851 
3852  return error;
3853 };
3854 
3855 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3856  .path = "nat addr-port-assignment-alg",
3857  .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
3859 };
3860 
3861 static clib_error_t *
3863  unformat_input_t * input,
3864  vlib_cli_command_t * cmd)
3865 {
3866  snat_main_t *sm = &snat_main;
3867  unformat_input_t _line_input, *line_input = &_line_input;
3868  ip4_address_t in_addr, out_addr;
3869  u32 in_plen, out_plen;
3870  int is_add = 1, rv;
3871  clib_error_t *error = 0;
3872 
3873  /* Get a line of input. */
3874  if (!unformat_user (input, unformat_line_input, line_input))
3875  return 0;
3876 
3877  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3878  {
3879  if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3880  ;
3881  else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3882  ;
3883  else if (unformat (line_input, "del"))
3884  is_add = 0;
3885  else
3886  {
3887  error = clib_error_return (0, "unknown input '%U'",
3888  format_unformat_error, line_input);
3889  goto done;
3890  }
3891  }
3892 
3893  rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3894  is_add);
3895 
3896  if (rv)
3897  {
3898  error = clib_error_return (0, "snat_det_add_map return %d", rv);
3899  goto done;
3900  }
3901 
3902 done:
3903  unformat_free (line_input);
3904 
3905  return error;
3906 }
3907 
3908 /*?
3909  * @cliexpar
3910  * @cliexstart{snat deterministic add}
3911  * Create bijective mapping of inside address to outside address and port range
3912  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3913  * CGN deployments.
3914  * To create deterministic mapping between inside network 10.0.0.0/18 and
3915  * outside network 1.1.1.0/30 use:
3916  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3917  * @cliexend
3918 ?*/
3919 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3920  .path = "nat44 deterministic add",
3921  .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3922  .function = snat_det_map_command_fn,
3923 };
3924 
3925 static clib_error_t *
3927  unformat_input_t * input,
3928  vlib_cli_command_t * cmd)
3929 {
3930  snat_main_t *sm = &snat_main;
3931  unformat_input_t _line_input, *line_input = &_line_input;
3932  ip4_address_t in_addr, out_addr;
3933  u16 lo_port;
3934  snat_det_map_t * dm;
3935  clib_error_t *error = 0;
3936 
3937  /* Get a line of input. */
3938  if (!unformat_user (input, unformat_line_input, line_input))
3939  return 0;
3940 
3941  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3942  {
3943  if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3944  ;
3945  else
3946  {
3947  error = clib_error_return (0, "unknown input '%U'",
3948  format_unformat_error, line_input);
3949  goto done;
3950  }
3951  }
3952 
3953  dm = snat_det_map_by_user(sm, &in_addr);
3954  if (!dm)
3955  vlib_cli_output (vm, "no match");
3956  else
3957  {
3958  snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3959  vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3960  lo_port, lo_port + dm->ports_per_host - 1);
3961  }
3962 
3963 done:
3964  unformat_free (line_input);
3965 
3966  return error;
3967 }
3968 
3969 /*?
3970  * @cliexpar
3971  * @cliexstart{snat deterministic forward}
3972  * Return outside address and port range from inside address for deterministic
3973  * NAT.
3974  * To obtain outside address and port of inside host use:
3975  * vpp# nat44 deterministic forward 10.0.0.2
3976  * 1.1.1.0:<1054-1068>
3977  * @cliexend
3978 ?*/
3979 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3980  .path = "nat44 deterministic forward",
3981  .short_help = "nat44 deterministic forward <addr>",
3982  .function = snat_det_forward_command_fn,
3983 };
3984 
3985 static clib_error_t *
3987  unformat_input_t * input,
3988  vlib_cli_command_t * cmd)
3989 {
3990  snat_main_t *sm = &snat_main;
3991  unformat_input_t _line_input, *line_input = &_line_input;
3992  ip4_address_t in_addr, out_addr;
3993  u32 out_port;
3994  snat_det_map_t * dm;
3995  clib_error_t *error = 0;
3996 
3997  /* Get a line of input. */
3998  if (!unformat_user (input, unformat_line_input, line_input))
3999  return 0;
4000 
4001  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4002  {
4003  if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
4004  ;
4005  else
4006  {
4007  error = clib_error_return (0, "unknown input '%U'",
4008  format_unformat_error, line_input);
4009  goto done;
4010  }
4011  }
4012 
4013  if (out_port < 1024 || out_port > 65535)
4014  {
4015  error = clib_error_return (0, "wrong port, must be <1024-65535>");
4016  goto done;
4017  }
4018 
4019  dm = snat_det_map_by_out(sm, &out_addr);
4020  if (!dm)
4021  vlib_cli_output (vm, "no match");
4022  else
4023  {
4024  snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
4025  vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
4026  }
4027 
4028 done:
4029  unformat_free (line_input);
4030 
4031  return error;
4032 }
4033 
4034 /*?
4035  * @cliexpar
4036  * @cliexstart{snat deterministic reverse}
4037  * Return inside address from outside address and port for deterministic NAT.
4038  * To obtain inside host address from outside address and port use:
4039  * #vpp nat44 deterministic reverse 1.1.1.1:1276
4040  * 10.0.16.16
4041  * @cliexend
4042 ?*/
4043 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
4044  .path = "nat44 deterministic reverse",
4045  .short_help = "nat44 deterministic reverse <addr>:<port>",
4046  .function = snat_det_reverse_command_fn,
4047 };
4048 
4049 static clib_error_t *
4051  unformat_input_t * input,
4052  vlib_cli_command_t * cmd)
4053 {
4054  snat_main_t *sm = &snat_main;
4055  unformat_input_t _line_input, *line_input = &_line_input;
4056  clib_error_t *error = 0;
4057 
4058  /* Get a line of input. */
4059  if (!unformat_user (input, unformat_line_input, line_input))
4060  return 0;
4061 
4062  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4063  {
4064  if (unformat (line_input, "udp %u", &sm->udp_timeout))
4065  ;
4066  else if (unformat (line_input, "tcp-established %u",
4068  ;
4069  else if (unformat (line_input, "tcp-transitory %u",
4070  &sm->tcp_transitory_timeout))
4071  ;
4072  else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
4073  ;
4074  else if (unformat (line_input, "reset"))
4075  {
4080  }
4081  else
4082  {
4083  error = clib_error_return (0, "unknown input '%U'",
4084  format_unformat_error, line_input);
4085  goto done;
4086  }
4087  }
4088 
4089 done:
4090  unformat_free (line_input);
4091 
4092  return error;
4093 }
4094 
4095 /*?
4096  * @cliexpar
4097  * @cliexstart{set snat deterministic timeout}
4098  * Set values of timeouts for deterministic NAT (in seconds), use:
4099  * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
4100  * tcp-transitory 250 icmp 90
4101  * To reset default values use:
4102  * vpp# set nat44 deterministic timeout reset
4103  * @cliexend
4104 ?*/
4105 VLIB_CLI_COMMAND (set_timeout_command, static) = {
4106  .path = "set nat44 deterministic timeout",
4107  .function = set_timeout_command_fn,
4108  .short_help =
4109  "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
4110  "tcp-transitory <sec> | icmp <sec> | reset]",
4111 };
4112 
4113 static clib_error_t *
4115  unformat_input_t * input,
4116  vlib_cli_command_t * cmd)
4117 {
4118  snat_main_t *sm = &snat_main;
4119  unformat_input_t _line_input, *line_input = &_line_input;
4120  ip4_address_t out_addr, ext_addr, in_addr;
4121  u32 out_port, ext_port;
4122  snat_det_map_t * dm;
4123  snat_det_session_t * ses;
4124  snat_det_out_key_t key;
4125  clib_error_t *error = 0;
4126 
4127  /* Get a line of input. */
4128  if (!unformat_user (input, unformat_line_input, line_input))
4129  return 0;
4130 
4131  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4132  {
4133  if (unformat (line_input, "%U:%d %U:%d",
4134  unformat_ip4_address, &out_addr, &out_port,
4135  unformat_ip4_address, &ext_addr, &ext_port))
4136  ;
4137  else
4138  {
4139  error = clib_error_return (0, "unknown input '%U'",
4140  format_unformat_error, line_input);
4141  goto done;
4142  }
4143  }
4144 
4145  unformat_free (line_input);
4146 
4147  dm = snat_det_map_by_out(sm, &out_addr);
4148  if (!dm)
4149  vlib_cli_output (vm, "no match");
4150  else
4151  {
4152  snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
4153  key.ext_host_addr = out_addr;
4154  key.ext_host_port = ntohs((u16)ext_port);
4155  key.out_port = ntohs((u16)out_port);
4156  ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
4157  if (!ses)
4158  vlib_cli_output (vm, "no match");
4159  else
4160  snat_det_ses_close(dm, ses);
4161  }
4162 
4163 done:
4164  unformat_free (line_input);
4165 
4166  return error;
4167 }
4168 
4169 /*?
4170  * @cliexpar
4171  * @cliexstart{snat deterministic close session out}
4172  * Close session using outside ip address and port
4173  * and external ip address and port, use:
4174  * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
4175  * @cliexend
4176 ?*/
4177 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
4178  .path = "nat44 deterministic close session out",
4179  .short_help = "nat44 deterministic close session out "
4180  "<out_addr>:<out_port> <ext_addr>:<ext_port>",
4181  .function = snat_det_close_session_out_fn,
4182 };
4183 
4184 static clib_error_t *
4186  unformat_input_t * input,
4187  vlib_cli_command_t * cmd)
4188 {
4189  snat_main_t *sm = &snat_main;
4190  unformat_input_t _line_input, *line_input = &_line_input;
4191  ip4_address_t in_addr, ext_addr;
4192  u32 in_port, ext_port;
4193  snat_det_map_t * dm;
4194  snat_det_session_t * ses;
4195  snat_det_out_key_t key;
4196  clib_error_t *error = 0;
4197 
4198  /* Get a line of input. */
4199  if (!unformat_user (input, unformat_line_input, line_input))
4200  return 0;
4201 
4202  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4203  {
4204  if (unformat (line_input, "%U:%d %U:%d",
4205  unformat_ip4_address, &in_addr, &in_port,
4206  unformat_ip4_address, &ext_addr, &ext_port))
4207  ;
4208  else
4209  {
4210  error = clib_error_return (0, "unknown input '%U'",
4211  format_unformat_error, line_input);
4212  goto done;
4213  }
4214  }
4215 
4216  unformat_free (line_input);
4217 
4218  dm = snat_det_map_by_user (sm, &in_addr);
4219  if (!dm)
4220  vlib_cli_output (vm, "no match");
4221  else
4222  {
4223  key.ext_host_addr = ext_addr;
4224  key.ext_host_port = ntohs ((u16)ext_port);
4225  ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
4226  if (!ses)
4227  vlib_cli_output (vm, "no match");
4228  else
4229  snat_det_ses_close(dm, ses);
4230  }
4231 
4232 done:
4233  unformat_free(line_input);
4234 
4235  return error;
4236 }
4237 
4238 /*?
4239  * @cliexpar
4240  * @cliexstart{snat deterministic close_session_in}
4241  * Close session using inside ip address and port
4242  * and external ip address and port, use:
4243  * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
4244  * @cliexend
4245 ?*/
4246 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
4247  .path = "nat44 deterministic close session in",
4248  .short_help = "nat44 deterministic close session in "
4249  "<in_addr>:<in_port> <ext_addr>:<ext_port>",
4250  .function = snat_det_close_session_in_fn,
4251 };
4252 
4253 static clib_error_t *
4255  unformat_input_t * input,
4256  vlib_cli_command_t * cmd)
4257 {
4258  snat_main_t *sm = &snat_main;
4259  unformat_input_t _line_input, *line_input = &_line_input;
4260  u8 forwarding_enable;
4261  u8 forwarding_enable_set = 0;
4262  clib_error_t *error = 0;
4263 
4264  /* Get a line of input. */
4265  if (!unformat_user (input, unformat_line_input, line_input))
4266  return clib_error_return (0, "'enable' or 'disable' expected");
4267 
4268  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4269  {
4270  if (!forwarding_enable_set && unformat (line_input, "enable"))
4271  {
4272  forwarding_enable = 1;
4273  forwarding_enable_set = 1;
4274  }
4275  else if (!forwarding_enable_set && unformat (line_input, "disable"))
4276  {
4277  forwarding_enable = 0;
4278  forwarding_enable_set = 1;
4279  }
4280  else
4281  {
4282  error = clib_error_return (0, "unknown input '%U'",
4283  format_unformat_error, line_input);
4284  goto done;
4285  }
4286  }
4287 
4288  if (!forwarding_enable_set)
4289  {
4290  error = clib_error_return (0, "'enable' or 'disable' expected");
4291  goto done;
4292  }
4293 
4294  sm->forwarding_enabled = forwarding_enable;
4295 
4296 done:
4297  unformat_free(line_input);
4298 
4299  return error;
4300 }
4301 
4302 /*?
4303  * @cliexpar
4304  * @cliexstart{nat44 forwarding}
4305  * Enable or disable forwarding
4306  * Forward packets which don't match existing translation
4307  * or static mapping instead of dropping them.
4308  * To enable forwarding, use:
4309  * vpp# nat44 forwarding enable
4310  * To disable forwarding, use:
4311  * vpp# nat44 forwarding disable
4312  * @cliexend
4313 ?*/
4314 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
4315  .path = "nat44 forwarding",
4316  .short_help = "nat44 forwarding enable|disable",
4317  .function = snat_forwarding_set_command_fn,
4318 };
ip4_address_t external_addr
Definition: nat.h:215
u32 user_memory_size
Definition: nat.h:364
u8 * format_snat_user(u8 *s, va_list *args)
Definition: nat.c:3114
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
clib_error_t * snat_api_init(vlib_main_t *vm, snat_main_t *sm)
Definition: nat_api.c:2563
u32 next
Definition: dlist.h:30
vmrglw vmrglh hi
#define vec_foreach_index(var, v)
Iterate over vector indices.
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:438
u32 sessions_per_user_list_head_index
Definition: nat.h:171
clib_bihash_16_8_t out2in_ed
Definition: nat.h:289
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
int snat_del_address(snat_main_t *sm, ip4_address_t addr, u8 delete_sm, u8 twice_nat)
Definition: nat.c:1263
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
Definition: nat.c:133
u16 ext_host_port
Definition: nat.h:79
void dslite_init(vlib_main_t *vm)
Definition: dslite.c:22
u16 out_port
Definition: nat.h:80
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:129
VLIB_NODE_FUNCTION_MULTIARCH(nat44_classify_node, nat44_classify_node_fn)
a
Definition: bitmap.h:516
u8 * format_snat_protocol(u8 *s, va_list *args)
Definition: nat.c:2266
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u32 icmp_timeout
Definition: nat.h:375
ip4_address_t src_address
Definition: ip4_packet.h:164
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static int nat_alloc_addr_and_port_mape(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:1981
u32 fq_in2out_output_index
Definition: nat.h:342
clib_error_t * nat_reass_init(vlib_main_t *vm)
Initialize NAT virtual fragmentation reassembly.
Definition: nat_reass.c:576
#define SNAT_TCP_ESTABLISHED_TIMEOUT
Definition: nat.h:36
#define PREDICT_TRUE(x)
Definition: clib.h:106
u32 nsessions
Definition: nat.h:172
#define is_ed_session(s)
Check if NAT session is endpoint dependent.
Definition: nat.h:462
static clib_error_t * nat44_del_session_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3754
ip4_address_t addr
Definition: nat.h:207
#define NULL
Definition: clib.h:55
snat_protocol_t proto
Definition: nat.h:222
ip4_address_t * ip4_interface_first_address(ip4_main_t *im, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip4_forward.c:690
u16 port_per_thread
Definition: nat.h:301
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1748
nat_reass_ip4_t * nat_ip4_reass_find(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto)
Find reassembly.
Definition: nat_reass.c:198
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
static clib_error_t * snat_det_map_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3862
u32 nstaticsessions
Definition: nat.h:173
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: nat_det.h:179
struct _vlib_node_registration vlib_node_registration_t
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:386
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:557
#define NAT_INTERFACE_FLAG_IS_OUTSIDE
Definition: nat.h:134
static snat_det_session_t * snat_det_find_ses_by_in(snat_det_map_t *dm, ip4_address_t *in_addr, u16 in_port, snat_det_out_key_t out_key)
Definition: nat_det.h:129
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Update the entry to have just one path.
Definition: fib_table.c:755
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
static void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
Definition: nat_det.h:75
ip_lookup_main_t lookup_main
Definition: ip4.h:97
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:2459
void nat64_set_hash(u32 bib_buckets, u32 bib_memory_size, u32 st_buckets, u32 st_memory_size)
Set NAT64 hash tables configuration.
Definition: nat64.c:251
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
u32 fib_index
Definition: nat.h:170
clib_bihash_16_8_t in2out_ed
Definition: nat.h:290
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only, u8 *twice_nat)
Match NAT44 static mapping.
Definition: nat.c:1785
void snat_add_del_addr_to_fib(ip4_address_t *addr, u8 p_len, u32 sw_if_index, int is_add)
Add/del NAT address to FIB.
Definition: nat.c:499
snat_det_map_t * det_maps
Definition: nat.h:351
static clib_error_t * snat_add_interface_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3644
nat_alloc_out_addr_and_port_function_t * alloc_addr_and_port
Definition: nat.h:322
static void snat_ip4_add_del_interface_address_cb(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
Definition: nat.c:3488
u32 num_snat_thread
Definition: nat.h:302
static clib_error_t * snat_det_close_session_in_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:4185
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
dlist_elt_t * list_pool
Definition: nat.h:259
static void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: nat_det.h:90
#define snat_is_unk_proto_session(s)
Check if SNAT session for unknown protocol.
Definition: nat.h:444
u8 * format_snat_static_mapping(u8 *s, va_list *args)
Definition: nat.c:3154
u32 proto
Definition: nat.h:64
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: in2out.c:673
format_function_t format_vnet_sw_if_index_name
u8 deterministic
Definition: nat.h:359
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Definition: nat.c:1375
static uword nat44_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:344
u16 l_port
Definition: nat.h:66
nat44_lb_addr_port_t * locals
Definition: nat.h:224
u32 user_buckets
Definition: nat.h:363
clib_bihash_8_8_t user_hash
Definition: nat.h:250
u16 identifier
Definition: nat.h:474
u32 max_translations_per_user
Definition: nat.h:365
clib_bihash_8_8_t in2out
Definition: nat.h:247
static clib_error_t * snat_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2136
u32 in2out_output_node_index
Definition: nat.h:347
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:226
format_function_t format_ip4_address
Definition: format.h:79
#define static_always_inline
Definition: clib.h:93
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:438
unformat_function_t unformat_ip4_address
Definition: format.h:76
u16 r_port
Definition: nat.h:67
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:1676
u32 table_id
Definition: ip4_fib.h:51
ip4_address_t ext_host_addr
Definition: nat.h:78
ip4_address_t dst_address
Definition: ip4_packet.h:164
static u32 snat_get_worker_in2out_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: nat.c:2734
u32 translation_buckets
Definition: nat.h:360
ip4_address_t addr
Definition: nat.h:169
#define SNAT_DET_SES_PER_USER
Definition: nat_det.h:30
A high priority source a plugin can use.
Definition: fib_entry.h:62
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregrate type for a prefix.
Definition: fib_types.h:172
#define clib_error_return(e, args...)
Definition: error.h:99
int snat_ipfix_logging_enable_disable(int enable, u32 domain_id, u16 src_port)
Enable/disable NAT plugin IPFIX logging.
void snat_ipfix_logging_init(vlib_main_t *vm)
Initialize NAT plugin IPFIX logging.
u8 * format_snat_key(u8 *s, va_list *args)
Definition: nat.c:3053
ip4_main_t * ip4_main
Definition: nat.h:383
unsigned long u64
Definition: types.h:89
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
nat44_classify_next_t
Definition: nat.c:135
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1028
static clib_error_t * add_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2034
u16 fp_len
The mask length.
Definition: fib_types.h:176
ip4_address_t local_addr
Definition: nat.h:214
u64 as_u64[2]
Definition: nat.h:69
static uword nat44_det_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:441
snat_protocol_t proto
Definition: nat.h:238
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:2498
unformat_function_t unformat_line_input
Definition: format.h:281
static int ip4_is_fragment(ip4_header_t *i)
Definition: ip4_packet.h:205
VNET_FEATURE_INIT(ip4_snat_in2out, static)
u32 max_translations
Definition: nat.h:362
u32 * auto_add_sw_if_indices_twice_nat
Definition: nat.h:332
Definition: fib_entry.h:243
u32 fib_index
Definition: nat.h:64
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:35
#define hash_get(h, key)
Definition: hash.h:248
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Definition: nat.c:239
Definition: fib_entry.h:242
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
void nat_free_session_data(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Definition: nat.c:142
static clib_error_t * snat_det_forward_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3926
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:121
static uword clib_bitmap_last_set(uword *ai)
Return the higest numbered set bit in a bitmap.
Definition: bitmap.h:402
static clib_error_t * nat44_set_alloc_addr_and_port_alg_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3816
u64 key
the key
Definition: bihash_8_8.h:35
static snat_det_map_t * snat_det_map_by_out(snat_main_t *sm, ip4_address_t *out_addr)
Definition: nat_det.h:60
vlib_main_t * vlib_main
Definition: nat.h:381
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
#define v
Definition: acl.c:341
static clib_error_t * show_snat_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3238
struct _unformat_input_t unformat_input_t
u16 protocol
Definition: nat.h:50
#define SNAT_UDP_TIMEOUT
Definition: nat.h:33
snat_static_mapping_t * static_mappings
Definition: nat.h:314
u32 inside_fib_index
Definition: nat.h:369
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
vlib_node_registration_t nat44_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_classify_node)
Definition: nat.c:131
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
u32 udp_timeout
Definition: nat.h:372
u8 static_mapping_only
Definition: nat.h:357
#define PREDICT_FALSE(x)
Definition: clib.h:105
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
static clib_error_t * set_workers_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2604
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:801
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:311
u8 psid_offset
Definition: nat.h:323
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
api_main_t * api_main
Definition: nat.h:385
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1180
u8 psid_length
Definition: nat.h:324
vnet_main_t * vnet_main
Definition: nat.h:382
u32 inside_vrf_id
Definition: nat.h:368
static clib_error_t * add_lb_static_mapping_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2504
u32 fq_out2in_index
Definition: nat.h:343
snat_interface_t * output_feature_interfaces
Definition: nat.h:318
static uword nat44_handoff_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:464
snat_main_t snat_main
Definition: nat.c:33
u64 value
the value
Definition: bihash_8_8.h:36
snat_user_t * users
Definition: nat.h:253
u32 random_seed
Definition: nat.h:338
api_main_t api_main
Definition: api_shared.c:35
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:344
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k, u32 address_index)
Definition: nat.c:1741
clib_bihash_8_8_t out2in
Definition: nat.h:246
static u32 random_u32_max(void)
Maximum value returned by random_u32()
Definition: random.h:80
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:167
vlib_main_t * vm
Definition: buffer.c:283
u32 outside_vrf_id
Definition: nat.h:366
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:106
ip4_address_t l_addr
Definition: nat.h:62
u8 static_mapping_connection_tracking
Definition: nat.h:358
snat_get_worker_function_t * worker_in2out_cb
Definition: nat.h:299
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:836
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:72
static ip4_fib_t * ip4_fib_get(u32 index)
Get the FIB at the given index.
Definition: ip4_fib.h:105
deterministic NAT definitions
#define clib_warning(format, args...)
Definition: error.h:59
VLIB_PLUGIN_REGISTER()
int snat_interface_add_del_output_feature(u32 sw_if_index, u8 is_inside, int is_del)
Definition: nat.c:1517
static int ip4_is_first_fragment(ip4_header_t *i)
Definition: ip4_packet.h:212
u32 sharing_ratio
Definition: nat.h:199
ip4_address_t out_addr
Definition: nat.h:197
u16 psid
Definition: nat.h:325
static uword nat44_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:418
u32 outside_fib_index
Definition: nat.h:367
static clib_error_t * add_identity_mapping_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2409
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:268
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
ip4_address_t addr
Definition: nat.h:48
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:454
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:543
u32 tcp_transitory_timeout
Definition: nat.h:374
ip4_address_t r_addr
Definition: nat.h:63
int snat_det_add_map(snat_main_t *sm, ip4_address_t *in_addr, u8 in_plen, ip4_address_t *out_addr, u8 out_plen, int is_add)
Add/delete deterministic NAT mapping.
Definition: nat_det.c:40
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
u32 * auto_add_sw_if_indices
Definition: nat.h:331
static_always_inline u16 snat_random_port(u16 min, u16 max)
Definition: nat.c:1865
static int nat_alloc_addr_and_port_default(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:1889
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
static snat_det_map_t * snat_det_map_by_user(snat_main_t *sm, ip4_address_t *user_addr)
Definition: nat_det.h:45
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:294
#define ASSERT(truth)
#define NAT_INTERFACE_FLAG_IS_INSIDE
Definition: nat.h:133
u8 * format_snat_static_map_to_resolve(u8 *s, va_list *args)
Definition: nat.c:3188
u32 num_workers
Definition: nat.h:295
unsigned int u32
Definition: types.h:88
u32 first_worker_index
Definition: nat.h:296
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:781
snat_get_worker_function_t * worker_out2in_cb
Definition: nat.h:300
ip4_address_t l_addr
Definition: nat.h:233
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat.h:479
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:293
IPv4 main type.
Definition: ip4.h:95
u64 as_u64
Definition: nat.h:94
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1087
ip4_address_t addr
Definition: nat.h:91
ip4_address_t in_addr
Definition: nat.h:195
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
u32 fq_in2out_index
Definition: nat.h:341
size_t count
Definition: vapi.c:42
uword * thread_registrations_by_name
Definition: threads.h:297
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u32 out2in_node_index
Definition: nat.h:348
ip4_address_t addr
Definition: nat.h:177
int nat44_del_session(snat_main_t *sm, ip4_address_t *addr, u16 port, snat_protocol_t proto, u32 vrf_id, int is_in)
Definition: nat.c:3703
snat_address_t * twice_nat_addresses
Definition: nat.h:328
#define VNET_FEATURES(...)
Definition: feature.h:368
int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, u8 twice_nat)
Add static mapping.
Definition: nat.c:648
int nat44_add_del_lb_static_mapping(ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add, u8 twice_nat)
Definition: nat.c:999
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: nat.c:1656
static uword is_pow2(uword x)
Definition: clib.h:280
u32 value
Definition: dlist.h:32
u64 uword
Definition: types.h:112
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat.c:283
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
Definition: in2out.c:110
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: out2in.c:536
clib_error_t * nat64_init(vlib_main_t *vm)
Initialize NAT64.
Definition: nat64.c:211
NAT64 global declarations.
void increment_v4_address(ip4_address_t *a)
Definition: nat.c:599
unsigned short u16
Definition: types.h:57
void snat_add_address(snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, u8 twice_nat)
Definition: nat.c:531
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:1873
static int lb_local_exists(nat44_lb_addr_port_t *local, ip4_address_t *e_addr, u16 e_port)
Definition: nat.c:972
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static clib_error_t * set_timeout_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:4050
unsigned char u8
Definition: types.h:56
static clib_error_t * snat_forwarding_set_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:4254
u16 ports_per_host
Definition: nat.h:200
Definition: fib_entry.h:239
static void snat_add_static_mapping_when_resolved(snat_main_t *sm, ip4_address_t l_addr, u16 l_port, u32 sw_if_index, u16 e_port, u32 vrf_id, snat_protocol_t proto, int addr_only, int is_add)
Definition: nat.c:608
static uword unformat_bitmap_list(unformat_input_t *input, va_list *va)
unformat a list of bit ranges into a bitmap (eg "0-3,5-7,11" )
Definition: bitmap.h:693
void snat_ipfix_logging_addresses_exhausted(u32 pool_id)
Generate NAT addresses exhausted event.
u32 * workers
Definition: nat.h:298
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:305
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
snat_protocol_t
Definition: nat.h:104
snat_det_out_key_t out
Definition: nat.h:189
static clib_error_t * snat_det_reverse_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:3986
u32 fib_index
Definition: nat.h:92
snat_address_t * addresses
Definition: nat.h:321
int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del, u8 twice_nat)
Definition: nat.c:3577
u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:3366
u8 * format_snat_session(u8 *s, va_list *args)
Definition: nat.c:3064
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * format_det_map_ses(u8 *s, va_list *args)
Definition: nat.c:3208
u32 in2out_node_index
Definition: nat.h:346
#define SNAT_ICMP_TIMEOUT
Definition: nat.h:38
uword unformat_snat_protocol(unformat_input_t *input, va_list *args)
Definition: nat.c:2252
static snat_det_session_t * snat_det_get_ses_by_out(snat_det_map_t *dm, ip4_address_t *in_addr, u64 out_key)
Definition: nat_det.h:112
snat_static_map_resolve_t * to_resolve
Definition: nat.h:335
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1181
static clib_error_t * snat_ipfix_logging_enable_disable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2673
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
u8 forwarding_enabled
Definition: nat.h:354
u32 translation_memory_size
Definition: nat.h:361
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t snat_in2out_output_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_node)
Definition: in2out.c:111
vlib_node_registration_t nat44_det_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_det_classify_node)
Definition: nat.c:132
static clib_error_t * snat_det_close_session_out_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:4114
u32 next_worker
Definition: nat.h:297
int snat_set_workers(uword *bitmap)
Definition: nat.c:1612
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:450
static clib_error_t * add_static_mapping_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nat.c:2285
vhost_vring_addr_t addr
Definition: vhost-user.h:83
static clib_error_t * snat_config(vlib_main_t *vm, unformat_input_t *input)
Definition: nat.c:2890
NAT plugin virtual fragmentation reassembly.
#define SNAT_TCP_TRANSITORY_TIMEOUT
Definition: nat.h:35
ip_lookup_main_t * ip4_lookup_main
Definition: nat.h:384
static int is_snat_address_used_in_static_mapping(snat_main_t *sm, ip4_address_t addr)
Definition: nat.c:586
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
snat_session_t * sessions
Definition: nat.h:256
u8 * format_snat_session_state(u8 *s, va_list *args)
Definition: nat.c:3036
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
snat_icmp_match_function_t * icmp_match_in2out_cb
Definition: nat.h:292
#define SNAT_SESSION_FLAG_LOAD_BALANCING
Definition: nat.h:130
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:308
static u32 snat_get_worker_out2in_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: nat.c:2753
u32 fib_index
Definition: nat.h:178
snat_interface_t * interfaces
Definition: nat.h:317
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u16 fib_index
Definition: nat.h:50
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:229
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat.h:569
static u8 snat_proto_to_ip_proto(snat_protocol_t snat_proto)
Definition: nat.h:492
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117
u32 tcp_established_timeout
Definition: nat.h:373
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128