FD.io VPP  v18.01-8-g0eacf49
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_before = VNET_FEATURES ("nat44-out2in"),
41 };
42 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
43  .arc_name = "ip4-unicast",
44  .node_name = "nat44-out2in",
45  .runs_before = VNET_FEATURES ("ip4-lookup"),
46 };
47 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
48  .arc_name = "ip4-unicast",
49  .node_name = "nat44-classify",
50  .runs_before = VNET_FEATURES ("ip4-lookup"),
51 };
52 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
53  .arc_name = "ip4-unicast",
54  .node_name = "nat44-det-in2out",
55  .runs_before = VNET_FEATURES ("nat44-det-out2in"),
56 };
57 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
58  .arc_name = "ip4-unicast",
59  .node_name = "nat44-det-out2in",
60  .runs_before = VNET_FEATURES ("ip4-lookup"),
61 };
62 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
63  .arc_name = "ip4-unicast",
64  .node_name = "nat44-det-classify",
65  .runs_before = VNET_FEATURES ("ip4-lookup"),
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_before = VNET_FEATURES ("nat44-out2in-worker-handoff"),
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_before = VNET_FEATURES ("ip4-lookup"),
76 };
77 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
78  .arc_name = "ip4-unicast",
79  .node_name = "nat44-handoff-classify",
80  .runs_before = VNET_FEATURES ("ip4-lookup"),
81 };
82 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
83  .arc_name = "ip4-unicast",
84  .node_name = "nat44-in2out-fast",
85  .runs_before = VNET_FEATURES ("nat44-out2in-fast"),
86 };
87 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
88  .arc_name = "ip4-unicast",
89  .node_name = "nat44-out2in-fast",
90  .runs_before = VNET_FEATURES ("ip4-lookup"),
91 };
92 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
93  .arc_name = "ip4-unicast",
94  .node_name = "nat44-hairpin-dst",
95  .runs_before = VNET_FEATURES ("ip4-lookup"),
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_before = VNET_FEATURES ("interface-output"),
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_before = VNET_FEATURES ("interface-output"),
108 };
109 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
110  .arc_name = "ip4-output",
111  .node_name = "nat44-hairpin-src",
112  .runs_before = VNET_FEATURES ("interface-output"),
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)
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  snat_protocol_t proto, u32 vrf_id,
974  nat44_lb_addr_port_t *locals, u8 is_add,
975  u8 twice_nat)
976 {
977  snat_main_t * sm = &snat_main;
979  snat_session_key_t m_key;
980  clib_bihash_kv_8_8_t kv, value;
981  u32 fib_index;
982  snat_address_t *a = 0;
983  int i;
984  nat44_lb_addr_port_t *local;
985  u32 worker_index = 0, elt_index, head_index, ses_index;
987  snat_user_key_t u_key;
988  snat_user_t *u;
989  snat_session_t * s;
990  dlist_elt_t * head, * elt;
991 
992  m_key.addr = e_addr;
993  m_key.port = e_port;
994  m_key.protocol = proto;
995  m_key.fib_index = sm->outside_fib_index;
996  kv.key = m_key.as_u64;
997  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
998  m = 0;
999  else
1000  m = pool_elt_at_index (sm->static_mappings, value.value);
1001 
1002  if (is_add)
1003  {
1004  if (m)
1005  return VNET_API_ERROR_VALUE_EXIST;
1006 
1007  if (vec_len (locals) < 2)
1008  return VNET_API_ERROR_INVALID_VALUE;
1009 
1011  vrf_id,
1013 
1014  /* Find external address in allocated addresses and reserve port for
1015  address and port pair mapping when dynamic translations enabled */
1016  if (!sm->static_mapping_only)
1017  {
1018  for (i = 0; i < vec_len (sm->addresses); i++)
1019  {
1020  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1021  {
1022  a = sm->addresses + i;
1023  /* External port must be unused */
1024  switch (proto)
1025  {
1026 #define _(N, j, n, s) \
1027  case SNAT_PROTOCOL_##N: \
1028  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1029  return VNET_API_ERROR_INVALID_VALUE; \
1030  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1031  if (e_port > 1024) \
1032  { \
1033  a->busy_##n##_ports++; \
1034  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1035  } \
1036  break;
1038 #undef _
1039  default:
1040  clib_warning("unknown_protocol");
1041  return VNET_API_ERROR_INVALID_VALUE_2;
1042  }
1043  break;
1044  }
1045  }
1046  /* External address must be allocated */
1047  if (!a)
1048  return VNET_API_ERROR_NO_SUCH_ENTRY;
1049  }
1050 
1051  pool_get (sm->static_mappings, m);
1052  memset (m, 0, sizeof (*m));
1053  m->external_addr = e_addr;
1054  m->addr_only = 0;
1055  m->vrf_id = vrf_id;
1056  m->fib_index = fib_index;
1057  m->external_port = e_port;
1058  m->proto = proto;
1059  m->twice_nat = twice_nat;
1060 
1061  m_key.addr = m->external_addr;
1062  m_key.port = m->external_port;
1063  m_key.protocol = m->proto;
1064  m_key.fib_index = sm->outside_fib_index;
1065  kv.key = m_key.as_u64;
1066  kv.value = m - sm->static_mappings;
1067  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1068  {
1069  clib_warning ("static_mapping_by_external key add failed");
1070  return VNET_API_ERROR_UNSPECIFIED;
1071  }
1072 
1073  /* Assign worker */
1074  if (sm->workers)
1075  {
1076  worker_index = sm->first_worker_index +
1077  sm->workers[sm->next_worker++ % vec_len (sm->workers)];
1078  tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
1079  m->worker_index = worker_index;
1080  }
1081  else
1082  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1083 
1084  m_key.port = clib_host_to_net_u16 (m->external_port);
1085  kv.key = m_key.as_u64;
1086  kv.value = ~0ULL;
1087  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
1088  {
1089  clib_warning ("out2in key add failed");
1090  return VNET_API_ERROR_UNSPECIFIED;
1091  }
1092 
1093  m_key.fib_index = m->fib_index;
1094  for (i = 0; i < vec_len (locals); i++)
1095  {
1096  m_key.addr = locals[i].addr;
1097  m_key.port = locals[i].port;
1098  kv.key = m_key.as_u64;
1099  kv.value = m - sm->static_mappings;
1100  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1101  locals[i].prefix = (i == 0) ? locals[i].probability :\
1102  (locals[i - 1].prefix + locals[i].probability);
1103  vec_add1 (m->locals, locals[i]);
1104 
1105  m_key.port = clib_host_to_net_u16 (locals[i].port);
1106  kv.key = m_key.as_u64;
1107  kv.value = ~0ULL;
1108  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
1109  {
1110  clib_warning ("in2out key add failed");
1111  return VNET_API_ERROR_UNSPECIFIED;
1112  }
1113  }
1114  }
1115  else
1116  {
1117  if (!m)
1118  return VNET_API_ERROR_NO_SUCH_ENTRY;
1119 
1121 
1122  /* Free external address port */
1123  if (!sm->static_mapping_only)
1124  {
1125  for (i = 0; i < vec_len (sm->addresses); i++)
1126  {
1127  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1128  {
1129  a = sm->addresses + i;
1130  switch (proto)
1131  {
1132 #define _(N, j, n, s) \
1133  case SNAT_PROTOCOL_##N: \
1134  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1135  if (e_port > 1024) \
1136  { \
1137  a->busy_##n##_ports--; \
1138  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1139  } \
1140  break;
1142 #undef _
1143  default:
1144  clib_warning("unknown_protocol");
1145  return VNET_API_ERROR_INVALID_VALUE_2;
1146  }
1147  break;
1148  }
1149  }
1150  }
1151 
1153  m_key.addr = m->external_addr;
1154  m_key.port = m->external_port;
1155  m_key.protocol = m->proto;
1156  m_key.fib_index = sm->outside_fib_index;
1157  kv.key = m_key.as_u64;
1158  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1159  {
1160  clib_warning ("static_mapping_by_external key del failed");
1161  return VNET_API_ERROR_UNSPECIFIED;
1162  }
1163 
1164  m_key.port = clib_host_to_net_u16 (m->external_port);
1165  kv.key = m_key.as_u64;
1166  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1167  {
1168  clib_warning ("outi2in key del failed");
1169  return VNET_API_ERROR_UNSPECIFIED;
1170  }
1171 
1172  vec_foreach (local, m->locals)
1173  {
1174  m_key.addr = local->addr;
1175  m_key.port = local->port;
1176  m_key.fib_index = m->fib_index;
1177  kv.key = m_key.as_u64;
1178  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1179  {
1180  clib_warning ("static_mapping_by_local key del failed");
1181  return VNET_API_ERROR_UNSPECIFIED;
1182  }
1183 
1184  m_key.port = clib_host_to_net_u16 (local->port);
1185  kv.key = m_key.as_u64;
1186  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1187  {
1188  clib_warning ("in2out key del failed");
1189  return VNET_API_ERROR_UNSPECIFIED;
1190  }
1191  /* Delete sessions */
1192  u_key.addr = local->addr;
1193  u_key.fib_index = m->fib_index;
1194  kv.key = u_key.as_u64;
1195  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1196  {
1197  u = pool_elt_at_index (tsm->users, value.value);
1198  if (u->nstaticsessions)
1199  {
1200  head_index = u->sessions_per_user_list_head_index;
1201  head = pool_elt_at_index (tsm->list_pool, head_index);
1202  elt_index = head->next;
1203  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1204  ses_index = elt->value;
1205  while (ses_index != ~0)
1206  {
1207  s = pool_elt_at_index (tsm->sessions, ses_index);
1208  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1209  ses_index = elt->value;
1210 
1211  if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
1212  (clib_net_to_host_u16 (s->in2out.port) != local->port))
1213  continue;
1214 
1215  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1216  clib_dlist_remove (tsm->list_pool, s->per_user_index);
1217  pool_put_index (tsm->list_pool, s->per_user_index);
1218  pool_put (tsm->sessions, s);
1219  u->nstaticsessions--;
1220  }
1221  }
1222  }
1223  }
1224  vec_free(m->locals);
1225 
1226  pool_put (sm->static_mappings, m);
1227  }
1228 
1229  return 0;
1230 }
1231 
1232 int
1234  u8 twice_nat)
1235 {
1236  snat_address_t *a = 0;
1237  snat_session_t *ses;
1238  u32 *ses_to_be_removed = 0, *ses_index;
1239  clib_bihash_kv_8_8_t kv, value;
1240  snat_user_key_t user_key;
1241  snat_user_t *u;
1244  snat_interface_t *interface;
1245  int i;
1246  snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1247 
1248  /* Find SNAT address */
1249  for (i=0; i < vec_len (addresses); i++)
1250  {
1251  if (addresses[i].addr.as_u32 == addr.as_u32)
1252  {
1253  a = addresses + i;
1254  break;
1255  }
1256  }
1257  if (!a)
1258  return VNET_API_ERROR_NO_SUCH_ENTRY;
1259 
1260  if (delete_sm)
1261  {
1262  pool_foreach (m, sm->static_mappings,
1263  ({
1264  if (m->external_addr.as_u32 == addr.as_u32)
1265  (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1266  m->local_port, m->external_port,
1267  m->vrf_id, m->addr_only, ~0,
1268  m->proto, 0, m->twice_nat);
1269  }));
1270  }
1271  else
1272  {
1273  /* Check if address is used in some static mapping */
1275  {
1276  clib_warning ("address used in static mapping");
1277  return VNET_API_ERROR_UNSPECIFIED;
1278  }
1279  }
1280 
1281  if (a->fib_index != ~0)
1284 
1285  /* Delete sessions using address */
1286  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1287  {
1288  vec_foreach (tsm, sm->per_thread_data)
1289  {
1290  pool_foreach (ses, tsm->sessions, ({
1291  if (ses->out2in.addr.as_u32 == addr.as_u32)
1292  {
1293  ses->outside_address_index = ~0;
1294  nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1295  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1296  pool_put_index (tsm->list_pool, ses->per_user_index);
1297  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1298  user_key.addr = ses->in2out.addr;
1299  user_key.fib_index = ses->in2out.fib_index;
1300  kv.key = user_key.as_u64;
1301  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1302  {
1303  u = pool_elt_at_index (tsm->users, value.value);
1304  u->nsessions--;
1305  }
1306  }
1307  }));
1308 
1309  vec_foreach (ses_index, ses_to_be_removed)
1310  pool_put_index (tsm->sessions, ses_index[0]);
1311 
1312  vec_free (ses_to_be_removed);
1313  }
1314  }
1315 
1316  if (twice_nat)
1317  {
1318  vec_del1 (sm->twice_nat_addresses, i);
1319  return 0;
1320  }
1321  else
1322  vec_del1 (sm->addresses, i);
1323 
1324  /* Delete external address from FIB */
1325  pool_foreach (interface, sm->interfaces,
1326  ({
1327  if (nat_interface_is_inside(interface))
1328  continue;
1329 
1330  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1331  break;
1332  }));
1333  pool_foreach (interface, sm->output_feature_interfaces,
1334  ({
1335  if (nat_interface_is_inside(interface))
1336  continue;
1337 
1338  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1339  break;
1340  }));
1341 
1342  return 0;
1343 }
1344 
1345 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1346 {
1347  snat_main_t *sm = &snat_main;
1349  const char * feature_name, *del_feature_name;
1350  snat_address_t * ap;
1352  snat_det_map_t * dm;
1353 
1355  feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1356  else
1357  {
1358  if (sm->num_workers > 1 && !sm->deterministic)
1359  feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1360  else if (sm->deterministic)
1361  feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1362  else
1363  feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1364  }
1365 
1366  if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1368 
1369  if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1371 
1372  pool_foreach (i, sm->interfaces,
1373  ({
1374  if (i->sw_if_index == sw_if_index)
1375  {
1376  if (is_del)
1377  {
1378  if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1379  {
1380  if (is_inside)
1381  i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1382  else
1383  i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1384 
1385  if (sm->num_workers > 1 && !sm->deterministic)
1386  del_feature_name = "nat44-handoff-classify";
1387  else if (sm->deterministic)
1388  del_feature_name = "nat44-det-classify";
1389  else
1390  del_feature_name = "nat44-classify";
1391 
1392  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1393  sw_if_index, 0, 0, 0);
1394  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1395  sw_if_index, 1, 0, 0);
1396  }
1397  else
1398  {
1399  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1400  sw_if_index, 0, 0, 0);
1401  pool_put (sm->interfaces, i);
1402  }
1403  }
1404  else
1405  {
1406  if ((nat_interface_is_inside(i) && is_inside) ||
1407  (nat_interface_is_outside(i) && !is_inside))
1408  return 0;
1409 
1410  if (sm->num_workers > 1 && !sm->deterministic)
1411  {
1412  del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1413  "nat44-out2in-worker-handoff";
1414  feature_name = "nat44-handoff-classify";
1415  }
1416  else if (sm->deterministic)
1417  {
1418  del_feature_name = !is_inside ? "nat44-det-in2out" :
1419  "nat44-det-out2in";
1420  feature_name = "nat44-det-classify";
1421  }
1422  else
1423  {
1424  del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1425  feature_name = "nat44-classify";
1426  }
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  goto set_flags;
1433  }
1434 
1435  goto fib;
1436  }
1437  }));
1438 
1439  if (is_del)
1440  return VNET_API_ERROR_NO_SUCH_ENTRY;
1441 
1442  pool_get (sm->interfaces, i);
1443  i->sw_if_index = sw_if_index;
1444  i->flags = 0;
1445  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1446 
1447 set_flags:
1448  if (is_inside)
1449  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1450  else
1451  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1452 
1453  /* Add/delete external addresses to FIB */
1454 fib:
1455  if (is_inside)
1456  {
1457  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1458  sw_if_index, !is_del, 0, 0);
1459  return 0;
1460  }
1461 
1462  vec_foreach (ap, sm->addresses)
1463  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1464 
1465  pool_foreach (m, sm->static_mappings,
1466  ({
1467  if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1468  continue;
1469 
1470  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1471  }));
1472 
1473  pool_foreach (dm, sm->det_maps,
1474  ({
1475  snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1476  }));
1477 
1478  return 0;
1479 }
1480 
1482  u8 is_inside,
1483  int is_del)
1484 {
1485  snat_main_t *sm = &snat_main;
1487  snat_address_t * ap;
1489 
1490  if (sm->deterministic ||
1492  return VNET_API_ERROR_UNSUPPORTED;
1493 
1494  if (is_inside)
1495  {
1496  vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1497  sw_if_index, !is_del, 0, 0);
1498  vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1499  sw_if_index, !is_del, 0, 0);
1500  goto fq;
1501  }
1502 
1503  if (sm->num_workers > 1)
1504  {
1505  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1506  sw_if_index, !is_del, 0, 0);
1507  vnet_feature_enable_disable ("ip4-output",
1508  "nat44-in2out-output-worker-handoff",
1509  sw_if_index, !is_del, 0, 0);
1510  }
1511  else
1512  {
1513  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1514  !is_del, 0, 0);
1515  vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1516  sw_if_index, !is_del, 0, 0);
1517  }
1518 
1519 fq:
1520  if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1523 
1524  if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1526 
1528  ({
1529  if (i->sw_if_index == sw_if_index)
1530  {
1531  if (is_del)
1532  pool_put (sm->output_feature_interfaces, i);
1533  else
1534  return VNET_API_ERROR_VALUE_EXIST;
1535 
1536  goto fib;
1537  }
1538  }));
1539 
1540  if (is_del)
1541  return VNET_API_ERROR_NO_SUCH_ENTRY;
1542 
1543  pool_get (sm->output_feature_interfaces, i);
1544  i->sw_if_index = sw_if_index;
1545  i->flags = 0;
1546  if (is_inside)
1547  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1548  else
1549  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1550 
1551  /* Add/delete external addresses to FIB */
1552 fib:
1553  if (is_inside)
1554  return 0;
1555 
1556  vec_foreach (ap, sm->addresses)
1557  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1558 
1559  pool_foreach (m, sm->static_mappings,
1560  ({
1561  if (!(m->addr_only))
1562  continue;
1563 
1564  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1565  }));
1566 
1567  return 0;
1568 }
1569 
1570 int snat_set_workers (uword * bitmap)
1571 {
1572  snat_main_t *sm = &snat_main;
1573  int i, j = 0;
1574 
1575  if (sm->num_workers < 2)
1576  return VNET_API_ERROR_FEATURE_DISABLED;
1577 
1578  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1579  return VNET_API_ERROR_INVALID_WORKER;
1580 
1581  vec_free (sm->workers);
1582  clib_bitmap_foreach (i, bitmap,
1583  ({
1584  vec_add1(sm->workers, i);
1586  j++;
1587  }));
1588 
1589  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1590  sm->num_snat_thread = _vec_len (sm->workers);
1591 
1592  return 0;
1593 }
1594 
1595 
1596 static void
1598  uword opaque,
1599  u32 sw_if_index,
1600  ip4_address_t * address,
1601  u32 address_length,
1602  u32 if_address_index,
1603  u32 is_delete);
1604 
1605 static int
1607  u32 fib_index,
1608  u32 thread_index,
1609  snat_session_key_t * k,
1610  u32 * address_indexp,
1611  u16 port_per_thread,
1612  u32 snat_thread_index);
1613 
1615 {
1616  snat_main_t * sm = &snat_main;
1617  clib_error_t * error = 0;
1618  ip4_main_t * im = &ip4_main;
1619  ip_lookup_main_t * lm = &im->lookup_main;
1620  uword *p;
1623  uword *bitmap = 0;
1624  u32 i;
1626 
1627  sm->vlib_main = vm;
1628  sm->vnet_main = vnet_get_main();
1629  sm->ip4_main = im;
1630  sm->ip4_lookup_main = lm;
1631  sm->api_main = &api_main;
1632  sm->first_worker_index = 0;
1633  sm->next_worker = 0;
1634  sm->num_workers = 0;
1635  sm->num_snat_thread = 1;
1636  sm->workers = 0;
1637  sm->port_per_thread = 0xffff - 1024;
1638  sm->fq_in2out_index = ~0;
1639  sm->fq_out2in_index = ~0;
1645  sm->forwarding_enabled = 0;
1646 
1647  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1648  if (p)
1649  {
1650  tr = (vlib_thread_registration_t *) p[0];
1651  if (tr)
1652  {
1653  sm->num_workers = tr->count;
1654  sm->first_worker_index = tr->first_index;
1655  }
1656  }
1657 
1658  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1659 
1660  /* Use all available workers by default */
1661  if (sm->num_workers > 1)
1662  {
1663  for (i=0; i < sm->num_workers; i++)
1664  bitmap = clib_bitmap_set (bitmap, i, 1);
1665  snat_set_workers(bitmap);
1666  clib_bitmap_free (bitmap);
1667  }
1668  else
1669  {
1671  }
1672 
1673  error = snat_api_init(vm, sm);
1674  if (error)
1675  return error;
1676 
1677  /* Set up the interface address add/del callback */
1679  cb4.function_opaque = 0;
1680 
1682 
1683  /* Init IPFIX logging */
1685 
1686  /* Init NAT64 */
1687  error = nat64_init(vm);
1688  if (error)
1689  return error;
1690 
1691  dslite_init(vm);
1692 
1693  /* Init virtual fragmenentation reassembly */
1694  return nat_reass_init(vm);
1695 }
1696 
1698 
1700  u32 thread_index,
1701  snat_session_key_t * k,
1702  u32 address_index)
1703 {
1704  snat_address_t *a;
1705  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1706 
1707  ASSERT (address_index < vec_len (addresses));
1708 
1709  a = addresses + address_index;
1710 
1711  switch (k->protocol)
1712  {
1713 #define _(N, i, n, s) \
1714  case SNAT_PROTOCOL_##N: \
1715  ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1716  port_host_byte_order) == 1); \
1717  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1718  port_host_byte_order, 0); \
1719  a->busy_##n##_ports--; \
1720  a->busy_##n##_ports_per_thread[thread_index]--; \
1721  break;
1723 #undef _
1724  default:
1725  clib_warning("unknown_protocol");
1726  return;
1727  }
1728 }
1729 
1730 /**
1731  * @brief Match NAT44 static mapping.
1732  *
1733  * @param sm NAT main.
1734  * @param match Address and port to match.
1735  * @param mapping External or local address and port of the matched mapping.
1736  * @param by_external If 0 match by local address otherwise match by external
1737  * address.
1738  * @param is_addr_only If matched mapping is address only
1739  * @param twice_nat If matched mapping is twice NAT.
1740  *
1741  * @returns 0 if match found otherwise 1.
1742  */
1744  snat_session_key_t match,
1745  snat_session_key_t * mapping,
1746  u8 by_external,
1747  u8 *is_addr_only,
1748  u8 *twice_nat)
1749 {
1750  clib_bihash_kv_8_8_t kv, value;
1752  snat_session_key_t m_key;
1753  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1754  u32 rand, lo = 0, hi, mid;
1755 
1756  if (by_external)
1757  mapping_hash = &sm->static_mapping_by_external;
1758 
1759  m_key.addr = match.addr;
1760  m_key.port = clib_net_to_host_u16 (match.port);
1761  m_key.protocol = match.protocol;
1762  m_key.fib_index = match.fib_index;
1763 
1764  kv.key = m_key.as_u64;
1765 
1766  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1767  {
1768  /* Try address only mapping */
1769  m_key.port = 0;
1770  m_key.protocol = 0;
1771  kv.key = m_key.as_u64;
1772  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1773  return 1;
1774  }
1775 
1776  m = pool_elt_at_index (sm->static_mappings, value.value);
1777 
1778  if (by_external)
1779  {
1780  if (vec_len (m->locals))
1781  {
1782  hi = vec_len (m->locals) - 1;
1783  rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1784  while (lo < hi)
1785  {
1786  mid = ((hi - lo) >> 1) + lo;
1787  (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1788  }
1789  if (!(m->locals[lo].prefix >= rand))
1790  return 1;
1791  mapping->addr = m->locals[lo].addr;
1792  mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1793  }
1794  else
1795  {
1796  mapping->addr = m->local_addr;
1797  /* Address only mapping doesn't change port */
1798  mapping->port = m->addr_only ? match.port
1799  : clib_host_to_net_u16 (m->local_port);
1800  }
1801  mapping->fib_index = m->fib_index;
1802  mapping->protocol = m->proto;
1803  }
1804  else
1805  {
1806  mapping->addr = m->external_addr;
1807  /* Address only mapping doesn't change port */
1808  mapping->port = m->addr_only ? match.port
1809  : clib_host_to_net_u16 (m->external_port);
1810  mapping->fib_index = sm->outside_fib_index;
1811  }
1812 
1813  if (PREDICT_FALSE(is_addr_only != 0))
1814  *is_addr_only = m->addr_only;
1815 
1816  if (PREDICT_FALSE(twice_nat != 0))
1817  *twice_nat = m->twice_nat;
1818 
1819  return 0;
1820 }
1821 
1824 {
1825  snat_main_t *sm = &snat_main;
1826  return min + random_u32 (&sm->random_seed) /
1827  (random_u32_max() / (max - min + 1) + 1);
1828 }
1829 
1830 int
1832  u32 fib_index,
1833  u32 thread_index,
1834  snat_session_key_t * k,
1835  u32 * address_indexp,
1836  u16 port_per_thread,
1837  u32 snat_thread_index)
1838 {
1839  snat_main_t *sm = &snat_main;
1840 
1841  return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
1842  address_indexp, port_per_thread,
1843  snat_thread_index);
1844 }
1845 
1846 static int
1848  u32 fib_index,
1849  u32 thread_index,
1850  snat_session_key_t * k,
1851  u32 * address_indexp,
1852  u16 port_per_thread,
1853  u32 snat_thread_index)
1854 {
1855  int i, gi = 0;
1856  snat_address_t *a, *ga = 0;
1857  u32 portnum;
1858 
1859  for (i = 0; i < vec_len (addresses); i++)
1860  {
1861  a = addresses + i;
1862  switch (k->protocol)
1863  {
1864 #define _(N, j, n, s) \
1865  case SNAT_PROTOCOL_##N: \
1866  if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1867  { \
1868  if (a->fib_index == fib_index) \
1869  { \
1870  while (1) \
1871  { \
1872  portnum = (port_per_thread * \
1873  snat_thread_index) + \
1874  snat_random_port(1, port_per_thread) + 1024; \
1875  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1876  continue; \
1877  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1878  a->busy_##n##_ports_per_thread[thread_index]++; \
1879  a->busy_##n##_ports++; \
1880  k->addr = a->addr; \
1881  k->port = clib_host_to_net_u16(portnum); \
1882  *address_indexp = i; \
1883  return 0; \
1884  } \
1885  } \
1886  else if (a->fib_index == ~0) \
1887  { \
1888  ga = a; \
1889  gi = i; \
1890  } \
1891  } \
1892  break;
1894 #undef _
1895  default:
1896  clib_warning("unknown protocol");
1897  return 1;
1898  }
1899 
1900  }
1901 
1902  if (ga)
1903  {
1904  a = ga;
1905  switch (k->protocol)
1906  {
1907 #define _(N, j, n, s) \
1908  case SNAT_PROTOCOL_##N: \
1909  while (1) \
1910  { \
1911  portnum = (port_per_thread * \
1912  snat_thread_index) + \
1913  snat_random_port(1, port_per_thread) + 1024; \
1914  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1915  continue; \
1916  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1917  a->busy_##n##_ports_per_thread[thread_index]++; \
1918  a->busy_##n##_ports++; \
1919  k->addr = a->addr; \
1920  k->port = clib_host_to_net_u16(portnum); \
1921  *address_indexp = gi; \
1922  return 0; \
1923  }
1924  break;
1926 #undef _
1927  default:
1928  clib_warning ("unknown protocol");
1929  return 1;
1930  }
1931  }
1932 
1933  /* Totally out of translations to use... */
1935  return 1;
1936 }
1937 
1938 static int
1940  u32 fib_index,
1941  u32 thread_index,
1942  snat_session_key_t * k,
1943  u32 * address_indexp,
1944  u16 port_per_thread,
1945  u32 snat_thread_index)
1946 {
1947  snat_main_t *sm = &snat_main;
1948  snat_address_t *a = addresses;
1949  u16 m, ports, portnum, A, j;
1950  m = 16 - (sm->psid_offset + sm->psid_length);
1951  ports = (1 << (16 - sm->psid_length)) - (1 << m);
1952 
1953  if (!vec_len (addresses))
1954  goto exhausted;
1955 
1956  switch (k->protocol)
1957  {
1958 #define _(N, i, n, s) \
1959  case SNAT_PROTOCOL_##N: \
1960  if (a->busy_##n##_ports < ports) \
1961  { \
1962  while (1) \
1963  { \
1964  A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
1965  j = snat_random_port(0, pow2_mask(m)); \
1966  portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
1967  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1968  continue; \
1969  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1970  a->busy_##n##_ports++; \
1971  k->addr = a->addr; \
1972  k->port = clib_host_to_net_u16 (portnum); \
1973  *address_indexp = i; \
1974  return 0; \
1975  } \
1976  } \
1977  break;
1979 #undef _
1980  default:
1981  clib_warning("unknown protocol");
1982  return 1;
1983  }
1984 
1985 exhausted:
1986  /* Totally out of translations to use... */
1988  return 1;
1989 }
1990 
1991 static clib_error_t *
1993  unformat_input_t * input,
1994  vlib_cli_command_t * cmd)
1995 {
1996  unformat_input_t _line_input, *line_input = &_line_input;
1997  snat_main_t * sm = &snat_main;
1998  ip4_address_t start_addr, end_addr, this_addr;
1999  u32 start_host_order, end_host_order;
2000  u32 vrf_id = ~0;
2001  int i, count;
2002  int is_add = 1;
2003  int rv = 0;
2004  clib_error_t *error = 0;
2005  u8 twice_nat = 0;
2006 
2007  /* Get a line of input. */
2008  if (!unformat_user (input, unformat_line_input, line_input))
2009  return 0;
2010 
2011  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2012  {
2013  if (unformat (line_input, "%U - %U",
2014  unformat_ip4_address, &start_addr,
2015  unformat_ip4_address, &end_addr))
2016  ;
2017  else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
2018  ;
2019  else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
2020  end_addr = start_addr;
2021  else if (unformat (line_input, "twice-nat"))
2022  twice_nat = 1;
2023  else if (unformat (line_input, "del"))
2024  is_add = 0;
2025  else
2026  {
2027  error = clib_error_return (0, "unknown input '%U'",
2028  format_unformat_error, line_input);
2029  goto done;
2030  }
2031  }
2032 
2033  if (sm->static_mapping_only)
2034  {
2035  error = clib_error_return (0, "static mapping only mode");
2036  goto done;
2037  }
2038 
2039  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
2040  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
2041 
2042  if (end_host_order < start_host_order)
2043  {
2044  error = clib_error_return (0, "end address less than start address");
2045  goto done;
2046  }
2047 
2048  count = (end_host_order - start_host_order) + 1;
2049 
2050  if (count > 1024)
2051  clib_warning ("%U - %U, %d addresses...",
2052  format_ip4_address, &start_addr,
2053  format_ip4_address, &end_addr,
2054  count);
2055 
2056  this_addr = start_addr;
2057 
2058  for (i = 0; i < count; i++)
2059  {
2060  if (is_add)
2061  snat_add_address (sm, &this_addr, vrf_id, twice_nat);
2062  else
2063  rv = snat_del_address (sm, this_addr, 0, twice_nat);
2064 
2065  switch (rv)
2066  {
2067  case VNET_API_ERROR_NO_SUCH_ENTRY:
2068  error = clib_error_return (0, "S-NAT address not exist.");
2069  goto done;
2070  case VNET_API_ERROR_UNSPECIFIED:
2071  error = clib_error_return (0, "S-NAT address used in static mapping.");
2072  goto done;
2073  default:
2074  break;
2075  }
2076 
2077  increment_v4_address (&this_addr);
2078  }
2079 
2080 done:
2081  unformat_free (line_input);
2082 
2083  return error;
2084 }
2085 
2086 VLIB_CLI_COMMAND (add_address_command, static) = {
2087  .path = "nat44 add address",
2088  .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
2089  "[tenant-vrf <vrf-id>] [twice-nat] [del]",
2090  .function = add_address_command_fn,
2091 };
2092 
2093 static clib_error_t *
2095  unformat_input_t * input,
2096  vlib_cli_command_t * cmd)
2097 {
2098  unformat_input_t _line_input, *line_input = &_line_input;
2099  vnet_main_t * vnm = vnet_get_main();
2100  clib_error_t * error = 0;
2101  u32 sw_if_index;
2102  u32 * inside_sw_if_indices = 0;
2103  u32 * outside_sw_if_indices = 0;
2104  u8 is_output_feature = 0;
2105  int is_del = 0;
2106  int i;
2107 
2108  sw_if_index = ~0;
2109 
2110  /* Get a line of input. */
2111  if (!unformat_user (input, unformat_line_input, line_input))
2112  return 0;
2113 
2114  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2115  {
2116  if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
2117  vnm, &sw_if_index))
2118  vec_add1 (inside_sw_if_indices, sw_if_index);
2119  else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
2120  vnm, &sw_if_index))
2121  vec_add1 (outside_sw_if_indices, sw_if_index);
2122  else if (unformat (line_input, "output-feature"))
2123  is_output_feature = 1;
2124  else if (unformat (line_input, "del"))
2125  is_del = 1;
2126  else
2127  {
2128  error = clib_error_return (0, "unknown input '%U'",
2129  format_unformat_error, line_input);
2130  goto done;
2131  }
2132  }
2133 
2134  if (vec_len (inside_sw_if_indices))
2135  {
2136  for (i = 0; i < vec_len(inside_sw_if_indices); i++)
2137  {
2138  sw_if_index = inside_sw_if_indices[i];
2139  if (is_output_feature)
2140  {
2141  if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
2142  {
2143  error = clib_error_return (0, "%s %U failed",
2144  is_del ? "del" : "add",
2146  vnet_get_sw_interface (vnm,
2147  sw_if_index));
2148  goto done;
2149  }
2150  }
2151  else
2152  {
2153  if (snat_interface_add_del (sw_if_index, 1, is_del))
2154  {
2155  error = clib_error_return (0, "%s %U failed",
2156  is_del ? "del" : "add",
2158  vnet_get_sw_interface (vnm,
2159  sw_if_index));
2160  goto done;
2161  }
2162  }
2163  }
2164  }
2165 
2166  if (vec_len (outside_sw_if_indices))
2167  {
2168  for (i = 0; i < vec_len(outside_sw_if_indices); i++)
2169  {
2170  sw_if_index = outside_sw_if_indices[i];
2171  if (is_output_feature)
2172  {
2173  if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
2174  {
2175  error = clib_error_return (0, "%s %U failed",
2176  is_del ? "del" : "add",
2178  vnet_get_sw_interface (vnm,
2179  sw_if_index));
2180  goto done;
2181  }
2182  }
2183  else
2184  {
2185  if (snat_interface_add_del (sw_if_index, 0, is_del))
2186  {
2187  error = clib_error_return (0, "%s %U failed",
2188  is_del ? "del" : "add",
2190  vnet_get_sw_interface (vnm,
2191  sw_if_index));
2192  goto done;
2193  }
2194  }
2195  }
2196  }
2197 
2198 done:
2199  unformat_free (line_input);
2200  vec_free (inside_sw_if_indices);
2201  vec_free (outside_sw_if_indices);
2202 
2203  return error;
2204 }
2205 
2206 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
2207  .path = "set interface nat44",
2208  .function = snat_feature_command_fn,
2209  .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
2210  "[del]",
2211 };
2212 
2213 uword
2214 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2215 {
2216  u32 *r = va_arg (*args, u32 *);
2217 
2218  if (0);
2219 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2221 #undef _
2222  else
2223  return 0;
2224  return 1;
2225 }
2226 
2227 u8 *
2228 format_snat_protocol (u8 * s, va_list * args)
2229 {
2230  u32 i = va_arg (*args, u32);
2231  u8 *t = 0;
2232 
2233  switch (i)
2234  {
2235 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2237 #undef _
2238  default:
2239  s = format (s, "unknown");
2240  return s;
2241  }
2242  s = format (s, "%s", t);
2243  return s;
2244 }
2245 
2246 static clib_error_t *
2248  unformat_input_t * input,
2249  vlib_cli_command_t * cmd)
2250 {
2251  unformat_input_t _line_input, *line_input = &_line_input;
2252  clib_error_t * error = 0;
2253  ip4_address_t l_addr, e_addr;
2254  u32 l_port = 0, e_port = 0, vrf_id = ~0;
2255  int is_add = 1;
2256  int addr_only = 1;
2257  u32 sw_if_index = ~0;
2258  vnet_main_t * vnm = vnet_get_main();
2259  int rv;
2260  snat_protocol_t proto = ~0;
2261  u8 proto_set = 0;
2262  u8 twice_nat = 0;
2263 
2264  /* Get a line of input. */
2265  if (!unformat_user (input, unformat_line_input, line_input))
2266  return 0;
2267 
2268  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2269  {
2270  if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2271  &l_port))
2272  addr_only = 0;
2273  else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2274  ;
2275  else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2276  &e_addr, &e_port))
2277  addr_only = 0;
2278  else if (unformat (line_input, "external %U", unformat_ip4_address,
2279  &e_addr))
2280  ;
2281  else if (unformat (line_input, "external %U %u",
2282  unformat_vnet_sw_interface, vnm, &sw_if_index,
2283  &e_port))
2284  addr_only = 0;
2285 
2286  else if (unformat (line_input, "external %U",
2287  unformat_vnet_sw_interface, vnm, &sw_if_index))
2288  ;
2289  else if (unformat (line_input, "vrf %u", &vrf_id))
2290  ;
2291  else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2292  proto_set = 1;
2293  else if (unformat (line_input, "twice-nat"))
2294  twice_nat = 1;
2295  else if (unformat (line_input, "del"))
2296  is_add = 0;
2297  else
2298  {
2299  error = clib_error_return (0, "unknown input: '%U'",
2300  format_unformat_error, line_input);
2301  goto done;
2302  }
2303  }
2304 
2305  if (twice_nat && addr_only)
2306  {
2307  error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
2308  goto done;
2309  }
2310 
2311  if (!addr_only && !proto_set)
2312  {
2313  error = clib_error_return (0, "missing protocol");
2314  goto done;
2315  }
2316 
2317  rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2318  vrf_id, addr_only, sw_if_index, proto, is_add,
2319  twice_nat);
2320 
2321  switch (rv)
2322  {
2323  case VNET_API_ERROR_INVALID_VALUE:
2324  error = clib_error_return (0, "External port already in use.");
2325  goto done;
2326  case VNET_API_ERROR_NO_SUCH_ENTRY:
2327  if (is_add)
2328  error = clib_error_return (0, "External addres must be allocated.");
2329  else
2330  error = clib_error_return (0, "Mapping not exist.");
2331  goto done;
2332  case VNET_API_ERROR_NO_SUCH_FIB:
2333  error = clib_error_return (0, "No such VRF id.");
2334  goto done;
2335  case VNET_API_ERROR_VALUE_EXIST:
2336  error = clib_error_return (0, "Mapping already exist.");
2337  goto done;
2338  default:
2339  break;
2340  }
2341 
2342 done:
2343  unformat_free (line_input);
2344 
2345  return error;
2346 }
2347 
2348 /*?
2349  * @cliexpar
2350  * @cliexstart{snat add static mapping}
2351  * Static mapping allows hosts on the external network to initiate connection
2352  * to to the local network host.
2353  * To create static mapping between local host address 10.0.0.3 port 6303 and
2354  * external address 4.4.4.4 port 3606 for TCP protocol use:
2355  * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2356  * If not runnig "static mapping only" NAT plugin mode use before:
2357  * vpp# nat44 add address 4.4.4.4
2358  * To create static mapping between local and external address use:
2359  * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2360  * @cliexend
2361 ?*/
2362 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2363  .path = "nat44 add static mapping",
2364  .function = add_static_mapping_command_fn,
2365  .short_help =
2366  "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
2367  "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
2368 };
2369 
2370 static clib_error_t *
2372  unformat_input_t * input,
2373  vlib_cli_command_t * cmd)
2374 {
2375  unformat_input_t _line_input, *line_input = &_line_input;
2376  clib_error_t * error = 0;
2378  u32 port = 0, vrf_id = ~0;
2379  int is_add = 1;
2380  int addr_only = 1;
2381  u32 sw_if_index = ~0;
2382  vnet_main_t * vnm = vnet_get_main();
2383  int rv;
2384  snat_protocol_t proto;
2385 
2386  addr.as_u32 = 0;
2387 
2388  /* Get a line of input. */
2389  if (!unformat_user (input, unformat_line_input, line_input))
2390  return 0;
2391 
2392  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2393  {
2394  if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2395  ;
2396  else if (unformat (line_input, "external %U",
2397  unformat_vnet_sw_interface, vnm, &sw_if_index))
2398  ;
2399  else if (unformat (line_input, "vrf %u", &vrf_id))
2400  ;
2401  else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2402  &port))
2403  addr_only = 0;
2404  else if (unformat (line_input, "del"))
2405  is_add = 0;
2406  else
2407  {
2408  error = clib_error_return (0, "unknown input: '%U'",
2409  format_unformat_error, line_input);
2410  goto done;
2411  }
2412  }
2413 
2414  rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2415  vrf_id, addr_only, sw_if_index, proto, is_add,
2416  0);
2417 
2418  switch (rv)
2419  {
2420  case VNET_API_ERROR_INVALID_VALUE:
2421  error = clib_error_return (0, "External port already in use.");
2422  goto done;
2423  case VNET_API_ERROR_NO_SUCH_ENTRY:
2424  if (is_add)
2425  error = clib_error_return (0, "External addres must be allocated.");
2426  else
2427  error = clib_error_return (0, "Mapping not exist.");
2428  goto done;
2429  case VNET_API_ERROR_NO_SUCH_FIB:
2430  error = clib_error_return (0, "No such VRF id.");
2431  goto done;
2432  case VNET_API_ERROR_VALUE_EXIST:
2433  error = clib_error_return (0, "Mapping already exist.");
2434  goto done;
2435  default:
2436  break;
2437  }
2438 
2439 done:
2440  unformat_free (line_input);
2441 
2442  return error;
2443 }
2444 
2445 /*?
2446  * @cliexpar
2447  * @cliexstart{snat add identity mapping}
2448  * Identity mapping translate an IP address to itself.
2449  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2450  * use:
2451  * vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2452  * To create identity mapping for address 10.0.0.3 use:
2453  * vpp# nat44 add identity mapping 10.0.0.3
2454  * To create identity mapping for DHCP addressed interface use:
2455  * vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2456  * @cliexend
2457 ?*/
2458 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2459  .path = "nat44 add identity mapping",
2460  .function = add_identity_mapping_command_fn,
2461  .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2462  "[<protocol> <port>] [vrf <table-id>] [del]",
2463 };
2464 
2465 static clib_error_t *
2467  unformat_input_t * input,
2468  vlib_cli_command_t * cmd)
2469 {
2470  unformat_input_t _line_input, *line_input = &_line_input;
2471  clib_error_t * error = 0;
2472  ip4_address_t l_addr, e_addr;
2473  u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2474  int is_add = 1;
2475  int rv;
2476  snat_protocol_t proto;
2477  u8 proto_set = 0;
2478  nat44_lb_addr_port_t *locals = 0, local;
2479  u8 twice_nat = 0;
2480 
2481  /* Get a line of input. */
2482  if (!unformat_user (input, unformat_line_input, line_input))
2483  return 0;
2484 
2485  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2486  {
2487  if (unformat (line_input, "local %U:%u probability %u",
2488  unformat_ip4_address, &l_addr, &l_port, &probability))
2489  {
2490  memset (&local, 0, sizeof (local));
2491  local.addr = l_addr;
2492  local.port = (u16) l_port;
2493  local.probability = (u8) probability;
2494  vec_add1 (locals, local);
2495  }
2496  else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2497  &e_addr, &e_port))
2498  ;
2499  else if (unformat (line_input, "vrf %u", &vrf_id))
2500  ;
2501  else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2502  &proto))
2503  proto_set = 1;
2504  else if (unformat (line_input, "twice-nat"))
2505  twice_nat = 1;
2506  else if (unformat (line_input, "del"))
2507  is_add = 0;
2508  else
2509  {
2510  error = clib_error_return (0, "unknown input: '%U'",
2511  format_unformat_error, line_input);
2512  goto done;
2513  }
2514  }
2515 
2516  if (vec_len (locals) < 2)
2517  {
2518  error = clib_error_return (0, "at least two local must be set");
2519  goto done;
2520  }
2521 
2522  if (!proto_set)
2523  {
2524  error = clib_error_return (0, "missing protocol");
2525  goto done;
2526  }
2527 
2528  rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2529  locals, is_add, twice_nat);
2530 
2531  switch (rv)
2532  {
2533  case VNET_API_ERROR_INVALID_VALUE:
2534  error = clib_error_return (0, "External port already in use.");
2535  goto done;
2536  case VNET_API_ERROR_NO_SUCH_ENTRY:
2537  if (is_add)
2538  error = clib_error_return (0, "External addres must be allocated.");
2539  else
2540  error = clib_error_return (0, "Mapping not exist.");
2541  goto done;
2542  case VNET_API_ERROR_VALUE_EXIST:
2543  error = clib_error_return (0, "Mapping already exist.");
2544  goto done;
2545  default:
2546  break;
2547  }
2548 
2549 done:
2550  unformat_free (line_input);
2551  vec_free (locals);
2552 
2553  return error;
2554 }
2555 
2556 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2557  .path = "nat44 add load-balancing static mapping",
2559  .short_help =
2560  "nat44 add load-balancing static mapping protocol tcp|udp "
2561  "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
2562  "[vrf <table-id>] [del]",
2563 };
2564 
2565 static clib_error_t *
2567  unformat_input_t * input,
2568  vlib_cli_command_t * cmd)
2569 {
2570  unformat_input_t _line_input, *line_input = &_line_input;
2571  uword *bitmap = 0;
2572  int rv = 0;
2573  clib_error_t *error = 0;
2574 
2575  /* Get a line of input. */
2576  if (!unformat_user (input, unformat_line_input, line_input))
2577  return 0;
2578 
2579  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2580  {
2581  if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2582  ;
2583  else
2584  {
2585  error = clib_error_return (0, "unknown input '%U'",
2586  format_unformat_error, line_input);
2587  goto done;
2588  }
2589  }
2590 
2591  if (bitmap == 0)
2592  {
2593  error = clib_error_return (0, "List of workers must be specified.");
2594  goto done;
2595  }
2596 
2597  rv = snat_set_workers(bitmap);
2598 
2599  clib_bitmap_free (bitmap);
2600 
2601  switch (rv)
2602  {
2603  case VNET_API_ERROR_INVALID_WORKER:
2604  error = clib_error_return (0, "Invalid worker(s).");
2605  goto done;
2606  case VNET_API_ERROR_FEATURE_DISABLED:
2607  error = clib_error_return (0,
2608  "Supported only if 2 or more workes available.");
2609  goto done;
2610  default:
2611  break;
2612  }
2613 
2614 done:
2615  unformat_free (line_input);
2616 
2617  return error;
2618 }
2619 
2620 /*?
2621  * @cliexpar
2622  * @cliexstart{set snat workers}
2623  * Set NAT workers if 2 or more workers available, use:
2624  * vpp# set snat workers 0-2,5
2625  * @cliexend
2626 ?*/
2627 VLIB_CLI_COMMAND (set_workers_command, static) = {
2628  .path = "set nat workers",
2629  .function = set_workers_command_fn,
2630  .short_help =
2631  "set nat workers <workers-list>",
2632 };
2633 
2634 static clib_error_t *
2636  unformat_input_t * input,
2637  vlib_cli_command_t * cmd)
2638 {
2639  unformat_input_t _line_input, *line_input = &_line_input;
2640  u32 domain_id = 0;
2641  u32 src_port = 0;
2642  u8 enable = 1;
2643  int rv = 0;
2644  clib_error_t *error = 0;
2645 
2646  /* Get a line of input. */
2647  if (!unformat_user (input, unformat_line_input, line_input))
2648  return 0;
2649 
2650  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2651  {
2652  if (unformat (line_input, "domain %d", &domain_id))
2653  ;
2654  else if (unformat (line_input, "src-port %d", &src_port))
2655  ;
2656  else if (unformat (line_input, "disable"))
2657  enable = 0;
2658  else
2659  {
2660  error = clib_error_return (0, "unknown input '%U'",
2661  format_unformat_error, line_input);
2662  goto done;
2663  }
2664  }
2665 
2666  rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2667 
2668  if (rv)
2669  {
2670  error = clib_error_return (0, "ipfix logging enable failed");
2671  goto done;
2672  }
2673 
2674 done:
2675  unformat_free (line_input);
2676 
2677  return error;
2678 }
2679 
2680 /*?
2681  * @cliexpar
2682  * @cliexstart{snat ipfix logging}
2683  * To enable NAT IPFIX logging use:
2684  * vpp# nat ipfix logging
2685  * To set IPFIX exporter use:
2686  * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2687  * @cliexend
2688 ?*/
2689 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2690  .path = "nat ipfix logging",
2692  .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2693 };
2694 
2695 static u32
2697 {
2698  snat_main_t *sm = &snat_main;
2699  u32 next_worker_index = 0;
2700  u32 hash;
2701 
2702  next_worker_index = sm->first_worker_index;
2703  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2704  (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2705 
2706  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2707  next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2708  else
2709  next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2710 
2711  return next_worker_index;
2712 }
2713 
2714 static u32
2716 {
2717  snat_main_t *sm = &snat_main;
2718  udp_header_t *udp;
2719  u16 port;
2720  snat_session_key_t m_key;
2721  clib_bihash_kv_8_8_t kv, value;
2723  nat_ed_ses_key_t key;
2724  clib_bihash_kv_16_8_t s_kv, s_value;
2726  snat_session_t *s;
2727  int i;
2728  u32 proto;
2729  u32 next_worker_index = 0;
2730 
2731  /* first try static mappings without port */
2733  {
2734  m_key.addr = ip0->dst_address;
2735  m_key.port = 0;
2736  m_key.protocol = 0;
2737  m_key.fib_index = rx_fib_index0;
2738  kv.key = m_key.as_u64;
2739  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2740  {
2741  m = pool_elt_at_index (sm->static_mappings, value.value);
2742  return m->worker_index;
2743  }
2744  }
2745 
2746  proto = ip_proto_to_snat_proto (ip0->protocol);
2747  udp = ip4_next_header (ip0);
2748  port = udp->dst_port;
2749 
2750  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2751  {
2753  return vlib_get_thread_index ();
2754 
2755  if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2756  {
2757  nat_reass_ip4_t *reass;
2758 
2759  reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2760  ip0->fragment_id, ip0->protocol);
2761 
2762  if (reass && (reass->thread_index != (u32) ~ 0))
2763  return reass->thread_index;
2764  else
2765  return vlib_get_thread_index ();
2766  }
2767  }
2768 
2769  /* unknown protocol */
2770  if (PREDICT_FALSE (proto == ~0))
2771  {
2772  key.l_addr = ip0->dst_address;
2773  key.r_addr = ip0->src_address;
2774  key.fib_index = rx_fib_index0;
2775  key.proto = ip0->protocol;
2776  key.r_port = 0;
2777  key.l_port = 0;
2778  s_kv.key[0] = key.as_u64[0];
2779  s_kv.key[1] = key.as_u64[1];
2780 
2781  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2782  {
2783  for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2784  {
2785  tsm = vec_elt_at_index (sm->per_thread_data, i);
2786  if (!pool_is_free_index(tsm->sessions, s_value.value))
2787  {
2788  s = pool_elt_at_index (tsm->sessions, s_value.value);
2789  if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2790  s->out2in.port == ip0->protocol &&
2792  return i;
2793  }
2794  }
2795  }
2796 
2797  /* if no session use current thread */
2798  return vlib_get_thread_index ();
2799  }
2800 
2801  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2802  {
2803  icmp46_header_t * icmp = (icmp46_header_t *) udp;
2804  icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2805  if (!icmp_is_error_message (icmp))
2806  port = echo->identifier;
2807  else
2808  {
2809  ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2810  proto = ip_proto_to_snat_proto (inner_ip->protocol);
2811  void *l4_header = ip4_next_header (inner_ip);
2812  switch (proto)
2813  {
2814  case SNAT_PROTOCOL_ICMP:
2815  icmp = (icmp46_header_t*)l4_header;
2816  echo = (icmp_echo_header_t *)(icmp + 1);
2817  port = echo->identifier;
2818  break;
2819  case SNAT_PROTOCOL_UDP:
2820  case SNAT_PROTOCOL_TCP:
2821  port = ((tcp_udp_header_t*)l4_header)->src_port;
2822  break;
2823  default:
2824  return vlib_get_thread_index ();
2825  }
2826  }
2827  }
2828 
2829  /* try static mappings with port */
2830  if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2831  {
2832  m_key.addr = ip0->dst_address;
2833  m_key.port = clib_net_to_host_u16 (port);
2834  m_key.protocol = proto;
2835  m_key.fib_index = rx_fib_index0;
2836  kv.key = m_key.as_u64;
2837  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2838  {
2839  m = pool_elt_at_index (sm->static_mappings, value.value);
2840  return m->worker_index;
2841  }
2842  }
2843 
2844  /* worker by outside port */
2845  next_worker_index = sm->first_worker_index;
2846  next_worker_index +=
2847  sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2848  return next_worker_index;
2849 }
2850 
2851 static clib_error_t *
2853 {
2854  snat_main_t * sm = &snat_main;
2855  u32 translation_buckets = 1024;
2856  u32 translation_memory_size = 128<<20;
2857  u32 user_buckets = 128;
2858  u32 user_memory_size = 64<<20;
2859  u32 max_translations_per_user = 100;
2860  u32 outside_vrf_id = 0;
2861  u32 inside_vrf_id = 0;
2862  u32 static_mapping_buckets = 1024;
2863  u32 static_mapping_memory_size = 64<<20;
2864  u32 nat64_bib_buckets = 1024;
2865  u32 nat64_bib_memory_size = 128 << 20;
2866  u32 nat64_st_buckets = 2048;
2867  u32 nat64_st_memory_size = 256 << 20;
2868  u8 static_mapping_only = 0;
2869  u8 static_mapping_connection_tracking = 0;
2871 
2872  sm->deterministic = 0;
2873 
2874  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2875  {
2876  if (unformat (input, "translation hash buckets %d", &translation_buckets))
2877  ;
2878  else if (unformat (input, "translation hash memory %d",
2879  &translation_memory_size));
2880  else if (unformat (input, "user hash buckets %d", &user_buckets))
2881  ;
2882  else if (unformat (input, "user hash memory %d",
2883  &user_memory_size))
2884  ;
2885  else if (unformat (input, "max translations per user %d",
2886  &max_translations_per_user))
2887  ;
2888  else if (unformat (input, "outside VRF id %d",
2889  &outside_vrf_id))
2890  ;
2891  else if (unformat (input, "inside VRF id %d",
2892  &inside_vrf_id))
2893  ;
2894  else if (unformat (input, "static mapping only"))
2895  {
2896  static_mapping_only = 1;
2897  if (unformat (input, "connection tracking"))
2898  static_mapping_connection_tracking = 1;
2899  }
2900  else if (unformat (input, "deterministic"))
2901  sm->deterministic = 1;
2902  else if (unformat (input, "nat64 bib hash buckets %d",
2903  &nat64_bib_buckets))
2904  ;
2905  else if (unformat (input, "nat64 bib hash memory %d",
2906  &nat64_bib_memory_size))
2907  ;
2908  else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2909  ;
2910  else if (unformat (input, "nat64 st hash memory %d",
2911  &nat64_st_memory_size))
2912  ;
2913  else
2914  return clib_error_return (0, "unknown input '%U'",
2915  format_unformat_error, input);
2916  }
2917 
2918  /* for show commands, etc. */
2919  sm->translation_buckets = translation_buckets;
2920  sm->translation_memory_size = translation_memory_size;
2921  /* do not exceed load factor 10 */
2922  sm->max_translations = 10 * translation_buckets;
2923  sm->user_buckets = user_buckets;
2924  sm->user_memory_size = user_memory_size;
2925  sm->max_translations_per_user = max_translations_per_user;
2926  sm->outside_vrf_id = outside_vrf_id;
2928  outside_vrf_id,
2930  sm->inside_vrf_id = inside_vrf_id;
2932  inside_vrf_id,
2934  sm->static_mapping_only = static_mapping_only;
2935  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2936 
2937  nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2938  nat64_st_memory_size);
2939 
2940  if (sm->deterministic)
2941  {
2943  sm->in2out_output_node_index = ~0;
2947  }
2948  else
2949  {
2952  sm->in2out_node_index = snat_in2out_node.index;
2954  sm->out2in_node_index = snat_out2in_node.index;
2955  if (!static_mapping_only ||
2956  (static_mapping_only && static_mapping_connection_tracking))
2957  {
2960 
2961  vec_foreach (tsm, sm->per_thread_data)
2962  {
2963  clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2964  translation_memory_size);
2965 
2966  clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2967  translation_memory_size);
2968 
2969  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2970  user_memory_size);
2971  }
2972 
2973  clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2974  translation_buckets, translation_memory_size);
2975 
2976  clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2977  translation_buckets, translation_memory_size);
2978  }
2979  else
2980  {
2983  }
2984  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2985  "static_mapping_by_local", static_mapping_buckets,
2986  static_mapping_memory_size);
2987 
2988  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2989  "static_mapping_by_external", static_mapping_buckets,
2990  static_mapping_memory_size);
2991  }
2992 
2993  return 0;
2994 }
2995 
2997 
2998 u8 * format_snat_session_state (u8 * s, va_list * args)
2999 {
3000  u32 i = va_arg (*args, u32);
3001  u8 *t = 0;
3002 
3003  switch (i)
3004  {
3005 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
3007 #undef _
3008  default:
3009  t = format (t, "unknown");
3010  }
3011  s = format (s, "%s", t);
3012  return s;
3013 }
3014 
3015 u8 * format_snat_key (u8 * s, va_list * args)
3016 {
3017  snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
3018 
3019  s = format (s, "%U proto %U port %d fib %d",
3020  format_ip4_address, &key->addr,
3022  clib_net_to_host_u16 (key->port), key->fib_index);
3023  return s;
3024 }
3025 
3026 u8 * format_snat_session (u8 * s, va_list * args)
3027 {
3028  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
3029  snat_session_t * sess = va_arg (*args, snat_session_t *);
3030 
3031  if (snat_is_unk_proto_session (sess))
3032  {
3033  s = format (s, " i2o %U proto %u fib %u\n",
3034  format_ip4_address, &sess->in2out.addr,
3035  clib_net_to_host_u16 (sess->in2out.port),
3036  sess->in2out.fib_index);
3037  s = format (s, " o2i %U proto %u fib %u\n",
3038  format_ip4_address, &sess->out2in.addr,
3039  clib_net_to_host_u16 (sess->out2in.port),
3040  sess->out2in.fib_index);
3041  }
3042  else
3043  {
3044  s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
3045  s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
3046  }
3047  if (is_twice_nat_session (sess))
3048  {
3049  s = format (s, " external host o2i %U:%d i2o %U:%d\n",
3050  format_ip4_address, &sess->ext_host_addr,
3051  clib_net_to_host_u16 (sess->ext_host_port),
3052  format_ip4_address, &sess->ext_host_nat_addr,
3053  clib_net_to_host_u16 (sess->ext_host_nat_port));
3054  }
3055  else
3056  {
3057  if (sess->ext_host_addr.as_u32)
3058  s = format (s, " external host %U\n",
3059  format_ip4_address, &sess->ext_host_addr);
3060  }
3061  s = format (s, " last heard %.2f\n", sess->last_heard);
3062  s = format (s, " total pkts %d, total bytes %lld\n",
3063  sess->total_pkts, sess->total_bytes);
3064  if (snat_is_session_static (sess))
3065  s = format (s, " static translation\n");
3066  else
3067  s = format (s, " dynamic translation\n");
3068  if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
3069  s = format (s, " load-balancing\n");
3070  if (is_twice_nat_session (sess))
3071  s = format (s, " twice-nat\n");
3072 
3073  return s;
3074 }
3075 
3076 u8 * format_snat_user (u8 * s, va_list * args)
3077 {
3079  snat_user_t * u = va_arg (*args, snat_user_t *);
3080  int verbose = va_arg (*args, int);
3081  dlist_elt_t * head, * elt;
3082  u32 elt_index, head_index;
3083  u32 session_index;
3084  snat_session_t * sess;
3085 
3086  s = format (s, "%U: %d dynamic translations, %d static translations\n",
3088 
3089  if (verbose == 0)
3090  return s;
3091 
3092  if (u->nsessions || u->nstaticsessions)
3093  {
3094  head_index = u->sessions_per_user_list_head_index;
3095  head = pool_elt_at_index (sm->list_pool, head_index);
3096 
3097  elt_index = head->next;
3098  elt = pool_elt_at_index (sm->list_pool, elt_index);
3099  session_index = elt->value;
3100 
3101  while (session_index != ~0)
3102  {
3103  sess = pool_elt_at_index (sm->sessions, session_index);
3104 
3105  s = format (s, " %U\n", format_snat_session, sm, sess);
3106 
3107  elt_index = elt->next;
3108  elt = pool_elt_at_index (sm->list_pool, elt_index);
3109  session_index = elt->value;
3110  }
3111  }
3112 
3113  return s;
3114 }
3115 
3116 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3117 {
3118  snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3119  nat44_lb_addr_port_t *local;
3120 
3121  if (m->addr_only)
3122  s = format (s, "local %U external %U vrf %d %s",
3125  m->vrf_id, m->twice_nat ? "twice-nat" : "");
3126  else
3127  {
3128  if (vec_len (m->locals))
3129  {
3130  s = format (s, "%U vrf %d external %U:%d %s",
3132  m->vrf_id,
3134  m->twice_nat ? "twice-nat" : "");
3135  vec_foreach (local, m->locals)
3136  s = format (s, "\n local %U:%d probability %d\%",
3137  format_ip4_address, &local->addr, local->port,
3138  local->probability);
3139  }
3140  else
3141  s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
3145  m->vrf_id, m->twice_nat ? "twice-nat" : "");
3146  }
3147  return s;
3148 }
3149 
3150 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3151 {
3153  vnet_main_t *vnm = vnet_get_main();
3154 
3155  if (m->addr_only)
3156  s = format (s, "local %U external %U vrf %d",
3160  m->vrf_id);
3161  else
3162  s = format (s, "%U local %U:%d external %U:%d vrf %d",
3164  format_ip4_address, &m->l_addr, m->l_port,
3167  m->vrf_id);
3168 
3169  return s;
3170 }
3171 
3172 u8 * format_det_map_ses (u8 * s, va_list * args)
3173 {
3174  snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3175  ip4_address_t in_addr, out_addr;
3176  u32 in_offset, out_offset;
3177  snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3178  u32 * i = va_arg (*args, u32 *);
3179 
3180  u32 user_index = *i / SNAT_DET_SES_PER_USER;
3181  in_addr.as_u32 = clib_host_to_net_u32 (
3182  clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3183  in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3184  clib_net_to_host_u32(det_map->in_addr.as_u32);
3185  out_offset = in_offset / det_map->sharing_ratio;
3186  out_addr.as_u32 = clib_host_to_net_u32(
3187  clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3188  s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3189  format_ip4_address, &in_addr,
3190  clib_net_to_host_u16 (ses->in_port),
3191  format_ip4_address, &out_addr,
3192  clib_net_to_host_u16 (ses->out.out_port),
3194  clib_net_to_host_u16 (ses->out.ext_host_port),
3196  ses->expire);
3197 
3198  return s;
3199 }
3200 
3201 static clib_error_t *
3203  unformat_input_t * input,
3204  vlib_cli_command_t * cmd)
3205 {
3206  int verbose = 0;
3207  snat_main_t * sm = &snat_main;
3208  snat_user_t * u;
3211  snat_address_t * ap;
3212  vnet_main_t *vnm = vnet_get_main();
3214  u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
3215  uword j = 0;
3217  snat_det_map_t * dm;
3218  snat_det_session_t * ses;
3219 
3220  if (unformat (input, "detail"))
3221  verbose = 1;
3222  else if (unformat (input, "verbose"))
3223  verbose = 2;
3224 
3225  if (sm->static_mapping_only)
3226  {
3228  vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
3229  "tracking");
3230  else
3231  vlib_cli_output (vm, "NAT plugin mode: static mapping only");
3232  }
3233  else if (sm->deterministic)
3234  {
3235  vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
3236  }
3237  else
3238  {
3239  vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
3240  }
3241 
3242  if (verbose > 0)
3243  {
3244  pool_foreach (i, sm->interfaces,
3245  ({
3246  vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
3247  vnet_get_sw_interface (vnm, i->sw_if_index),
3248  (nat_interface_is_inside(i) &&
3249  nat_interface_is_outside(i)) ? "in out" :
3250  (nat_interface_is_inside(i) ? "in" : "out"));
3251  }));
3252 
3254  ({
3255  vlib_cli_output (vm, "%U output-feature %s",
3256  format_vnet_sw_interface_name, vnm,
3257  vnet_get_sw_interface (vnm, i->sw_if_index),
3258  (nat_interface_is_inside(i) &&
3259  nat_interface_is_outside(i)) ? "in out" :
3260  (nat_interface_is_inside(i) ? "in" : "out"));
3261  }));
3262 
3263  if (vec_len (sm->auto_add_sw_if_indices))
3264  {
3265  vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
3266  vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
3267  {
3269  vnet_get_sw_interface (vnm, *sw_if_index));
3270  }
3271  }
3272 
3274  {
3275  vlib_cli_output (vm, "NAT44 twice-nat pool addresses interfaces:");
3277  {
3279  vnet_get_sw_interface (vnm, *sw_if_index));
3280  }
3281  }
3282 
3283  vlib_cli_output (vm, "NAT44 pool addresses:");
3284  vec_foreach (ap, sm->addresses)
3285  {
3286  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3287  if (ap->fib_index != ~0)
3288  vlib_cli_output (vm, " tenant VRF: %u",
3290  else
3291  vlib_cli_output (vm, " tenant VRF independent");
3292 #define _(N, i, n, s) \
3293  vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
3295 #undef _
3296  }
3297 
3298  vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
3300  {
3301  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3302  if (ap->fib_index != ~0)
3303  vlib_cli_output (vm, " tenant VRF: %u",
3305  else
3306  vlib_cli_output (vm, " tenant VRF independent");
3307 #define _(N, i, n, s) \
3308  vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
3310 #undef _
3311  }
3312  }
3313 
3314  if (sm->num_workers > 1)
3315  {
3316  vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
3317  if (verbose > 0)
3318  {
3319  vec_foreach (worker, sm->workers)
3320  {
3322  vlib_worker_threads + *worker + sm->first_worker_index;
3323  vlib_cli_output (vm, " %s", w->name);
3324  }
3325  }
3326  }
3327 
3328  if (sm->deterministic)
3329  {
3330  vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
3331  vlib_cli_output (vm, "tcp-established timeout: %dsec",
3333  vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
3335  vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
3336  vlib_cli_output (vm, "%d deterministic mappings",
3337  pool_elts (sm->det_maps));
3338  if (verbose > 0)
3339  {
3340  pool_foreach (dm, sm->det_maps,
3341  ({
3342  vlib_cli_output (vm, "in %U/%d out %U/%d\n",
3343  format_ip4_address, &dm->in_addr, dm->in_plen,
3344  format_ip4_address, &dm->out_addr, dm->out_plen);
3345  vlib_cli_output (vm, " outside address sharing ratio: %d\n",
3346  dm->sharing_ratio);
3347  vlib_cli_output (vm, " number of ports per inside host: %d\n",
3348  dm->ports_per_host);
3349  vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
3350  if (verbose > 1)
3351  {
3352  vec_foreach_index (j, dm->sessions)
3353  {
3354  ses = vec_elt_at_index (dm->sessions, j);
3355  if (ses->in_port)
3356  vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
3357  &j);
3358  }
3359  }
3360  }));
3361  }
3362  }
3363  else
3364  {
3365  if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
3366  {
3367  vlib_cli_output (vm, "%d static mappings",
3368  pool_elts (sm->static_mappings));
3369 
3370  if (verbose > 0)
3371  {
3372  pool_foreach (m, sm->static_mappings,
3373  ({
3374  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3375  }));
3376  }
3377  }
3378  else
3379  {
3380  vec_foreach (tsm, sm->per_thread_data)
3381  {
3382  users_num += pool_elts (tsm->users);
3383  sessions_num += pool_elts (tsm->sessions);
3384  }
3385 
3386  vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3387  " %d static mappings, %d twice-nat addresses",
3388  users_num,
3389  vec_len (sm->addresses),
3390  sessions_num,
3391  pool_elts (sm->static_mappings),
3392  vec_len (sm->twice_nat_addresses));
3393 
3394  if (verbose > 0)
3395  {
3396  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3397  verbose - 1);
3398  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3399  verbose - 1);
3400  vec_foreach_index (j, sm->per_thread_data)
3401  {
3402  tsm = vec_elt_at_index (sm->per_thread_data, j);
3403 
3404  if (pool_elts (tsm->users) == 0)
3405  continue;
3406 
3408  vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3409  w->lcore_id);
3410  vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
3411  verbose - 1);
3412  vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
3413  verbose - 1);
3414  vlib_cli_output (vm, " %d list pool elements",
3415  pool_elts (tsm->list_pool));
3416 
3417  pool_foreach (u, tsm->users,
3418  ({
3419  vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
3420  verbose - 1);
3421  }));
3422  }
3423 
3424  if (pool_elts (sm->static_mappings))
3425  {
3426  vlib_cli_output (vm, "static mappings:");
3427  pool_foreach (m, sm->static_mappings,
3428  ({
3429  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3430  }));
3431  for (j = 0; j < vec_len (sm->to_resolve); j++)
3432  {
3433  rp = sm->to_resolve + j;
3434  vlib_cli_output (vm, "%U",
3436  }
3437  }
3438  }
3439  }
3440  }
3441 
3442  return 0;
3443 }
3444 
3445 VLIB_CLI_COMMAND (show_snat_command, static) = {
3446  .path = "show nat44",
3447  .short_help = "show nat44",
3448  .function = show_snat_command_fn,
3449 };
3450 
3451 
3452 static void
3454  uword opaque,
3455  u32 sw_if_index,
3456  ip4_address_t * address,
3457  u32 address_length,
3458  u32 if_address_index,
3459  u32 is_delete)
3460 {
3461  snat_main_t *sm = &snat_main;
3463  u32 *indices_to_delete = 0;
3464  ip4_address_t l_addr;
3465  int i, j;
3466  int rv;
3467  u8 twice_nat = 0;
3468  snat_address_t *addresses = sm->addresses;
3469 
3470  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3471  {
3472  if (sw_if_index == sm->auto_add_sw_if_indices[i])
3473  goto match;
3474  }
3475 
3476  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3477  {
3478  twice_nat = 1;
3479  addresses = sm->twice_nat_addresses;
3480  if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3481  goto match;
3482  }
3483 
3484  return;
3485 
3486 match:
3487  if (!is_delete)
3488  {
3489  /* Don't trip over lease renewal, static config */
3490  for (j = 0; j < vec_len(addresses); j++)
3491  if (addresses[j].addr.as_u32 == address->as_u32)
3492  return;
3493 
3494  snat_add_address (sm, address, ~0, twice_nat);
3495  /* Scan static map resolution vector */
3496  for (j = 0; j < vec_len (sm->to_resolve); j++)
3497  {
3498  rp = sm->to_resolve + j;
3499  /* On this interface? */
3500  if (rp->sw_if_index == sw_if_index)
3501  {
3502  /* Indetity mapping? */
3503  if (rp->l_addr.as_u32 == 0)
3504  l_addr.as_u32 = address[0].as_u32;
3505  else
3506  l_addr.as_u32 = rp->l_addr.as_u32;
3507  /* Add the static mapping */
3508  rv = snat_add_static_mapping (l_addr,
3509  address[0],
3510  rp->l_port,
3511  rp->e_port,
3512  rp->vrf_id,
3513  rp->addr_only,
3514  ~0 /* sw_if_index */,
3515  rp->proto,
3516  rp->is_add,
3517  0);
3518  if (rv)
3519  clib_warning ("snat_add_static_mapping returned %d",
3520  rv);
3521  vec_add1 (indices_to_delete, j);
3522  }
3523  }
3524  /* If we resolved any of the outstanding static mappings */
3525  if (vec_len(indices_to_delete))
3526  {
3527  /* Delete them */
3528  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3529  vec_delete(sm->to_resolve, 1, j);
3530  vec_free(indices_to_delete);
3531  }
3532  return;
3533  }
3534  else
3535  {
3536  (void) snat_del_address(sm, address[0], 1, twice_nat);
3537  return;
3538  }
3539 }
3540 
3541 
3542 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3543  u8 twice_nat)
3544 {
3545  ip4_main_t * ip4_main = sm->ip4_main;
3546  ip4_address_t * first_int_addr;
3548  u32 *indices_to_delete = 0;
3549  int i, j;
3550  u32 *auto_add_sw_if_indices =
3552 
3553  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3554  0 /* just want the address*/);
3555 
3556  for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3557  {
3558  if (auto_add_sw_if_indices[i] == sw_if_index)
3559  {
3560  if (is_del)
3561  {
3562  /* if have address remove it */
3563  if (first_int_addr)
3564  (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3565  else
3566  {
3567  for (j = 0; j < vec_len (sm->to_resolve); j++)
3568  {
3569  rp = sm->to_resolve + j;
3570  if (rp->sw_if_index == sw_if_index)
3571  vec_add1 (indices_to_delete, j);
3572  }
3573  if (vec_len(indices_to_delete))
3574  {
3575  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3576  vec_del1(sm->to_resolve, j);
3577  vec_free(indices_to_delete);
3578  }
3579  }
3580  if (twice_nat)
3582  else
3584  }
3585  else
3586  return VNET_API_ERROR_VALUE_EXIST;
3587 
3588  return 0;
3589  }
3590  }
3591 
3592  if (is_del)
3593  return VNET_API_ERROR_NO_SUCH_ENTRY;
3594 
3595  /* add to the auto-address list */
3596  if (twice_nat)
3597  vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3598  else
3599  vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3600 
3601  /* If the address is already bound - or static - add it now */
3602  if (first_int_addr)
3603  snat_add_address (sm, first_int_addr, ~0, twice_nat);
3604 
3605  return 0;
3606 }
3607 
3608 static clib_error_t *
3610  unformat_input_t * input,
3611  vlib_cli_command_t * cmd)
3612 {
3613  snat_main_t *sm = &snat_main;
3614  unformat_input_t _line_input, *line_input = &_line_input;
3615  u32 sw_if_index;
3616  int rv;
3617  int is_del = 0;
3618  clib_error_t *error = 0;
3619  u8 twice_nat = 0;
3620 
3621  /* Get a line of input. */
3622  if (!unformat_user (input, unformat_line_input, line_input))
3623  return 0;
3624 
3625  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3626  {
3627  if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3628  sm->vnet_main, &sw_if_index))
3629  ;
3630  else if (unformat (line_input, "twice-nat"))
3631  twice_nat = 1;
3632  else if (unformat (line_input, "del"))
3633  is_del = 1;
3634  else
3635  {
3636  error = clib_error_return (0, "unknown input '%U'",
3637  format_unformat_error, line_input);
3638  goto done;
3639  }
3640  }
3641 
3642  rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
3643 
3644  switch (rv)
3645  {
3646  case 0:
3647  break;
3648 
3649  default:
3650  error = clib_error_return (0, "snat_add_interface_address returned %d",
3651  rv);
3652  goto done;
3653  }
3654 
3655 done:
3656  unformat_free (line_input);
3657 
3658  return error;
3659 }
3660 
3661 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3662  .path = "nat44 add interface address",
3663  .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
3665 };
3666 
3667 int
3669  snat_protocol_t proto, u32 vrf_id, int is_in)
3670 {
3672  clib_bihash_kv_8_8_t kv, value;
3673  ip4_header_t ip;
3674  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3675  snat_session_key_t key;
3676  snat_session_t *s;
3677  clib_bihash_8_8_t *t;
3678  snat_user_key_t u_key;
3679  snat_user_t *u;
3680 
3681  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3682  if (sm->num_workers)
3683  tsm =
3685  sm->worker_in2out_cb (&ip, fib_index));
3686  else
3687  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3688 
3689  key.addr.as_u32 = addr->as_u32;
3690  key.port = clib_host_to_net_u16 (port);
3691  key.protocol = proto;
3692  key.fib_index = fib_index;
3693  kv.key = key.as_u64;
3694  t = is_in ? &tsm->in2out : &tsm->out2in;
3695  if (!clib_bihash_search_8_8 (t, &kv, &value))
3696  {
3697  s = pool_elt_at_index (tsm->sessions, value.value);
3698  kv.key = s->in2out.as_u64;
3699  clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3700  kv.key = s->out2in.as_u64;
3701  clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3702  u_key.addr = s->in2out.addr;
3703  u_key.fib_index = s->in2out.fib_index;
3704  kv.key = u_key.as_u64;
3705  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3706  {
3707  u = pool_elt_at_index (tsm->users, value.value);
3708  u->nsessions--;
3709  }
3710  clib_dlist_remove (tsm->list_pool, s->per_user_index);
3711  pool_put (tsm->sessions, s);
3712  return 0;
3713  }
3714 
3715  return VNET_API_ERROR_NO_SUCH_ENTRY;
3716 }
3717 
3718 static clib_error_t *
3720  unformat_input_t * input,
3721  vlib_cli_command_t * cmd)
3722 {
3723  snat_main_t *sm = &snat_main;
3724  unformat_input_t _line_input, *line_input = &_line_input;
3725  int is_in = 0;
3726  clib_error_t *error = 0;
3728  u32 port = 0, vrf_id = sm->outside_vrf_id;
3729  snat_protocol_t proto;
3730  int rv;
3731 
3732  /* Get a line of input. */
3733  if (!unformat_user (input, unformat_line_input, line_input))
3734  return 0;
3735 
3736  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3737  {
3738  if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3739  unformat_snat_protocol, &proto))
3740  ;
3741  else if (unformat (line_input, "in"))
3742  {
3743  is_in = 1;
3744  vrf_id = sm->inside_vrf_id;
3745  }
3746  else if (unformat (line_input, "vrf %u", &vrf_id))
3747  ;
3748  else
3749  {
3750  error = clib_error_return (0, "unknown input '%U'",
3751  format_unformat_error, line_input);
3752  goto done;
3753  }
3754  }
3755 
3756  rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3757 
3758  switch (rv)
3759  {
3760  case 0:
3761  break;
3762 
3763  default:
3764  error = clib_error_return (0, "nat44_del_session returned %d", rv);
3765  goto done;
3766  }
3767 
3768 done:
3769  unformat_free (line_input);
3770 
3771  return error;
3772 }
3773 
3774 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3775  .path = "nat44 del session",
3776  .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3777  .function = nat44_del_session_command_fn,
3778 };
3779 
3780 static clib_error_t *
3782  unformat_input_t * input,
3783  vlib_cli_command_t * cmd)
3784 {
3785  snat_main_t *sm = &snat_main;
3786  unformat_input_t _line_input, *line_input = &_line_input;
3787  clib_error_t *error = 0;
3788  u32 psid, psid_offset, psid_length;
3789 
3790  /* Get a line of input. */
3791  if (!unformat_user (input, unformat_line_input, line_input))
3792  return 0;
3793 
3794  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3795  {
3796  if (unformat (line_input, "default"))
3798  else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3799  &psid, &psid_offset, &psid_length))
3800  {
3802  sm->psid = (u16) psid;
3803  sm->psid_offset = (u16) psid_offset;
3804  sm->psid_length = (u16) psid_length;
3805  }
3806  else
3807  {
3808  error = clib_error_return (0, "unknown input '%U'",
3809  format_unformat_error, line_input);
3810  goto done;
3811  }
3812  }
3813 
3814 done:
3815  unformat_free (line_input);
3816 
3817  return error;
3818 };
3819 
3820 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3821  .path = "nat addr-port-assignment-alg",
3822  .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
3824 };
3825 
3826 static clib_error_t *
3828  unformat_input_t * input,
3829  vlib_cli_command_t * cmd)
3830 {
3831  snat_main_t *sm = &snat_main;
3832  unformat_input_t _line_input, *line_input = &_line_input;
3833  ip4_address_t in_addr, out_addr;
3834  u32 in_plen, out_plen;
3835  int is_add = 1, rv;
3836  clib_error_t *error = 0;
3837 
3838  /* Get a line of input. */
3839  if (!unformat_user (input, unformat_line_input, line_input))
3840  return 0;
3841 
3842  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3843  {
3844  if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3845  ;
3846  else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3847  ;
3848  else if (unformat (line_input, "del"))
3849  is_add = 0;
3850  else
3851  {
3852  error = clib_error_return (0, "unknown input '%U'",
3853  format_unformat_error, line_input);
3854  goto done;
3855  }
3856  }
3857 
3858  rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3859  is_add);
3860 
3861  if (rv)
3862  {
3863  error = clib_error_return (0, "snat_det_add_map return %d", rv);
3864  goto done;
3865  }
3866 
3867 done:
3868  unformat_free (line_input);
3869 
3870  return error;
3871 }
3872 
3873 /*?
3874  * @cliexpar
3875  * @cliexstart{snat deterministic add}
3876  * Create bijective mapping of inside address to outside address and port range
3877  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3878  * CGN deployments.
3879  * To create deterministic mapping between inside network 10.0.0.0/18 and
3880  * outside network 1.1.1.0/30 use:
3881  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3882  * @cliexend
3883 ?*/
3884 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3885  .path = "nat44 deterministic add",
3886  .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3887  .function = snat_det_map_command_fn,
3888 };
3889 
3890 static clib_error_t *
3892  unformat_input_t * input,
3893  vlib_cli_command_t * cmd)
3894 {
3895  snat_main_t *sm = &snat_main;
3896  unformat_input_t _line_input, *line_input = &_line_input;
3897  ip4_address_t in_addr, out_addr;
3898  u16 lo_port;
3899  snat_det_map_t * dm;
3900  clib_error_t *error = 0;
3901 
3902  /* Get a line of input. */
3903  if (!unformat_user (input, unformat_line_input, line_input))
3904  return 0;
3905 
3906  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3907  {
3908  if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3909  ;
3910  else
3911  {
3912  error = clib_error_return (0, "unknown input '%U'",
3913  format_unformat_error, line_input);
3914  goto done;
3915  }
3916  }
3917 
3918  dm = snat_det_map_by_user(sm, &in_addr);
3919  if (!dm)
3920  vlib_cli_output (vm, "no match");
3921  else
3922  {
3923  snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3924  vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3925  lo_port, lo_port + dm->ports_per_host - 1);
3926  }
3927 
3928 done:
3929  unformat_free (line_input);
3930 
3931  return error;
3932 }
3933 
3934 /*?
3935  * @cliexpar
3936  * @cliexstart{snat deterministic forward}
3937  * Return outside address and port range from inside address for deterministic
3938  * NAT.
3939  * To obtain outside address and port of inside host use:
3940  * vpp# nat44 deterministic forward 10.0.0.2
3941  * 1.1.1.0:<1054-1068>
3942  * @cliexend
3943 ?*/
3944 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3945  .path = "nat44 deterministic forward",
3946  .short_help = "nat44 deterministic forward <addr>",
3947  .function = snat_det_forward_command_fn,
3948 };
3949 
3950 static clib_error_t *
3952  unformat_input_t * input,
3953  vlib_cli_command_t * cmd)
3954 {
3955  snat_main_t *sm = &snat_main;
3956  unformat_input_t _line_input, *line_input = &_line_input;
3957  ip4_address_t in_addr, out_addr;
3958  u32 out_port;
3959  snat_det_map_t * dm;
3960  clib_error_t *error = 0;
3961 
3962  /* Get a line of input. */
3963  if (!unformat_user (input, unformat_line_input, line_input))
3964  return 0;
3965 
3966  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3967  {
3968  if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3969  ;
3970  else
3971  {
3972  error = clib_error_return (0, "unknown input '%U'",
3973  format_unformat_error, line_input);
3974  goto done;
3975  }
3976  }
3977 
3978  if (out_port < 1024 || out_port > 65535)
3979  {
3980  error = clib_error_return (0, "wrong port, must be <1024-65535>");
3981  goto done;
3982  }
3983 
3984  dm = snat_det_map_by_out(sm, &out_addr);
3985  if (!dm)
3986  vlib_cli_output (vm, "no match");
3987  else
3988  {
3989  snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3990  vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3991  }
3992 
3993 done:
3994  unformat_free (line_input);
3995 
3996  return error;
3997 }
3998 
3999 /*?
4000  * @cliexpar
4001  * @cliexstart{snat deterministic reverse}
4002  * Return inside address from outside address and port for deterministic NAT.
4003  * To obtain inside host address from outside address and port use:
4004  * #vpp nat44 deterministic reverse 1.1.1.1:1276
4005  * 10.0.16.16
4006  * @cliexend
4007 ?*/
4008 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
4009  .path = "nat44 deterministic reverse",
4010  .short_help = "nat44 deterministic reverse <addr>:<port>",
4011  .function = snat_det_reverse_command_fn,
4012 };
4013 
4014 static clib_error_t *
4016  unformat_input_t * input,
4017  vlib_cli_command_t * cmd)
4018 {
4019  snat_main_t *sm = &snat_main;
4020  unformat_input_t _line_input, *line_input = &_line_input;
4021  clib_error_t *error = 0;
4022 
4023  /* Get a line of input. */
4024  if (!unformat_user (input, unformat_line_input, line_input))
4025  return 0;
4026 
4027  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4028  {
4029  if (unformat (line_input, "udp %u", &sm->udp_timeout))
4030  ;
4031  else if (unformat (line_input, "tcp-established %u",
4033  ;
4034  else if (unformat (line_input, "tcp-transitory %u",
4035  &sm->tcp_transitory_timeout))
4036  ;
4037  else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
4038  ;
4039  else if (unformat (line_input, "reset"))
4040  {
4045  }
4046  else
4047  {
4048  error = clib_error_return (0, "unknown input '%U'",
4049  format_unformat_error, line_input);
4050  goto done;
4051  }
4052  }
4053 
4054 done:
4055  unformat_free (line_input);
4056 
4057  return error;
4058 }
4059 
4060 /*?
4061  * @cliexpar
4062  * @cliexstart{set snat deterministic timeout}
4063  * Set values of timeouts for deterministic NAT (in seconds), use:
4064  * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
4065  * tcp-transitory 250 icmp 90
4066  * To reset default values use:
4067  * vpp# set nat44 deterministic timeout reset
4068  * @cliexend
4069 ?*/
4070 VLIB_CLI_COMMAND (set_timeout_command, static) = {
4071  .path = "set nat44 deterministic timeout",
4072  .function = set_timeout_command_fn,
4073  .short_help =
4074  "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
4075  "tcp-transitory <sec> | icmp <sec> | reset]",
4076 };
4077 
4078 static clib_error_t *
4080  unformat_input_t * input,
4081  vlib_cli_command_t * cmd)
4082 {
4083  snat_main_t *sm = &snat_main;
4084  unformat_input_t _line_input, *line_input = &_line_input;
4085  ip4_address_t out_addr, ext_addr, in_addr;
4086  u32 out_port, ext_port;
4087  snat_det_map_t * dm;
4088  snat_det_session_t * ses;
4089  snat_det_out_key_t key;
4090  clib_error_t *error = 0;
4091 
4092  /* Get a line of input. */
4093  if (!unformat_user (input, unformat_line_input, line_input))
4094  return 0;
4095 
4096  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4097  {
4098  if (unformat (line_input, "%U:%d %U:%d",
4099  unformat_ip4_address, &out_addr, &out_port,
4100  unformat_ip4_address, &ext_addr, &ext_port))
4101  ;
4102  else
4103  {
4104  error = clib_error_return (0, "unknown input '%U'",
4105  format_unformat_error, line_input);
4106  goto done;
4107  }
4108  }
4109 
4110  unformat_free (line_input);
4111 
4112  dm = snat_det_map_by_out(sm, &out_addr);
4113  if (!dm)
4114  vlib_cli_output (vm, "no match");
4115  else
4116  {
4117  snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
4118  key.ext_host_addr = out_addr;
4119  key.ext_host_port = ntohs((u16)ext_port);
4120  key.out_port = ntohs((u16)out_port);
4121  ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
4122  if (!ses)
4123  vlib_cli_output (vm, "no match");
4124  else
4125  snat_det_ses_close(dm, ses);
4126  }
4127 
4128 done:
4129  unformat_free (line_input);
4130 
4131  return error;
4132 }
4133 
4134 /*?
4135  * @cliexpar
4136  * @cliexstart{snat deterministic close session out}
4137  * Close session using outside ip address and port
4138  * and external ip address and port, use:
4139  * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
4140  * @cliexend
4141 ?*/
4142 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
4143  .path = "nat44 deterministic close session out",
4144  .short_help = "nat44 deterministic close session out "
4145  "<out_addr>:<out_port> <ext_addr>:<ext_port>",
4146  .function = snat_det_close_session_out_fn,
4147 };
4148 
4149 static clib_error_t *
4151  unformat_input_t * input,
4152  vlib_cli_command_t * cmd)
4153 {
4154  snat_main_t *sm = &snat_main;
4155  unformat_input_t _line_input, *line_input = &_line_input;
4156  ip4_address_t in_addr, ext_addr;
4157  u32 in_port, ext_port;
4158  snat_det_map_t * dm;
4159  snat_det_session_t * ses;
4160  snat_det_out_key_t key;
4161  clib_error_t *error = 0;
4162 
4163  /* Get a line of input. */
4164  if (!unformat_user (input, unformat_line_input, line_input))
4165  return 0;
4166 
4167  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4168  {
4169  if (unformat (line_input, "%U:%d %U:%d",
4170  unformat_ip4_address, &in_addr, &in_port,
4171  unformat_ip4_address, &ext_addr, &ext_port))
4172  ;
4173  else
4174  {
4175  error = clib_error_return (0, "unknown input '%U'",
4176  format_unformat_error, line_input);
4177  goto done;
4178  }
4179  }
4180 
4181  unformat_free (line_input);
4182 
4183  dm = snat_det_map_by_user (sm, &in_addr);
4184  if (!dm)
4185  vlib_cli_output (vm, "no match");
4186  else
4187  {
4188  key.ext_host_addr = ext_addr;
4189  key.ext_host_port = ntohs ((u16)ext_port);
4190  ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
4191  if (!ses)
4192  vlib_cli_output (vm, "no match");
4193  else
4194  snat_det_ses_close(dm, ses);
4195  }
4196 
4197 done:
4198  unformat_free(line_input);
4199 
4200  return error;
4201 }
4202 
4203 /*?
4204  * @cliexpar
4205  * @cliexstart{snat deterministic close_session_in}
4206  * Close session using inside ip address and port
4207  * and external ip address and port, use:
4208  * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
4209  * @cliexend
4210 ?*/
4211 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
4212  .path = "nat44 deterministic close session in",
4213  .short_help = "nat44 deterministic close session in "
4214  "<in_addr>:<in_port> <ext_addr>:<ext_port>",
4215  .function = snat_det_close_session_in_fn,
4216 };
4217 
4218 static clib_error_t *
4220  unformat_input_t * input,
4221  vlib_cli_command_t * cmd)
4222 {
4223  snat_main_t *sm = &snat_main;
4224  unformat_input_t _line_input, *line_input = &_line_input;
4225  u8 forwarding_enable;
4226  u8 forwarding_enable_set = 0;
4227  clib_error_t *error = 0;
4228 
4229  /* Get a line of input. */
4230  if (!unformat_user (input, unformat_line_input, line_input))
4231  return clib_error_return (0, "'enable' or 'disable' expected");
4232 
4233  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4234  {
4235  if (!forwarding_enable_set && unformat (line_input, "enable"))
4236  {
4237  forwarding_enable = 1;
4238  forwarding_enable_set = 1;
4239  }
4240  else if (!forwarding_enable_set && unformat (line_input, "disable"))
4241  {
4242  forwarding_enable = 0;
4243  forwarding_enable_set = 1;
4244  }
4245  else
4246  {
4247  error = clib_error_return (0, "unknown input '%U'",
4248  format_unformat_error, line_input);
4249  goto done;
4250  }
4251  }
4252 
4253  if (!forwarding_enable_set)
4254  {
4255  error = clib_error_return (0, "'enable' or 'disable' expected");
4256  goto done;
4257  }
4258 
4259  sm->forwarding_enabled = forwarding_enable;
4260 
4261 done:
4262  unformat_free(line_input);
4263 
4264  return error;
4265 }
4266 
4267 /*?
4268  * @cliexpar
4269  * @cliexstart{nat44 forwarding}
4270  * Enable or disable forwarding
4271  * Forward packets which don't match existing translation
4272  * or static mapping instead of dropping them.
4273  * To enable forwarding, use:
4274  * vpp# nat44 forwarding enable
4275  * To disable forwarding, use:
4276  * vpp# nat44 forwarding disable
4277  * @cliexend
4278 ?*/
4279 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
4280  .path = "nat44 forwarding",
4281  .short_help = "nat44 forwarding enable|disable",
4282  .function = snat_forwarding_set_command_fn,
4283 };
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:3076
#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:1233
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:2228
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:1939
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:569
#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:3719
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:3827
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:281
#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
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:2282
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:1743
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:3609
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:3453
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:4150
#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:3116
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:507
u8 deterministic
Definition: nat.h:359
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Definition: nat.c:1345
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:2094
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:1509
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:2696
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:3015
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:1992
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:2320
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
format_function_t format_vnet_sw_interface_name
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:3891
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:3781
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:3202
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:2566
#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:2466
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:1699
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:1481
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:2371
#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:414
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:1823
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:1847
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:3150
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:3668
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:972
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: nat.c:1614
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:399
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:1831
#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:4015
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:4219
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:3951
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:3542
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:3155
u8 * format_snat_session(u8 *s, va_list *args)
Definition: nat.c:3026
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * format_det_map_ses(u8 *s, va_list *args)
Definition: nat.c:3172
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:2214
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:2635
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:4079
u32 next_worker
Definition: nat.h:297
int snat_set_workers(uword *bitmap)
Definition: nat.c:1570
#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:2247
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:2852
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:2998
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:2715
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