FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
snat.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 <snat/snat.h>
24 #include <snat/snat_det.h>
25 #include <snat/nat64.h>
26 #include <vnet/fib/fib_table.h>
27 #include <vnet/fib/ip4_fib.h>
28 
29 #include <vpp/app/version.h>
30 
32 
33 
34 /* Hook up input features */
35 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
36  .arc_name = "ip4-unicast",
37  .node_name = "snat-in2out",
38  .runs_before = VNET_FEATURES ("snat-out2in"),
39 };
40 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
41  .arc_name = "ip4-unicast",
42  .node_name = "snat-out2in",
43  .runs_before = VNET_FEATURES ("ip4-lookup"),
44 };
45 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
46  .arc_name = "ip4-unicast",
47  .node_name = "snat-det-in2out",
48  .runs_before = VNET_FEATURES ("snat-det-out2in"),
49 };
50 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
51  .arc_name = "ip4-unicast",
52  .node_name = "snat-det-out2in",
53  .runs_before = VNET_FEATURES ("ip4-lookup"),
54 };
55 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
56  .arc_name = "ip4-unicast",
57  .node_name = "snat-in2out-worker-handoff",
58  .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"),
59 };
60 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
61  .arc_name = "ip4-unicast",
62  .node_name = "snat-out2in-worker-handoff",
63  .runs_before = VNET_FEATURES ("ip4-lookup"),
64 };
65 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
66  .arc_name = "ip4-unicast",
67  .node_name = "snat-in2out-fast",
68  .runs_before = VNET_FEATURES ("snat-out2in-fast"),
69 };
70 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
71  .arc_name = "ip4-unicast",
72  .node_name = "snat-out2in-fast",
73  .runs_before = VNET_FEATURES ("ip4-lookup"),
74 };
75 
76 /* *INDENT-OFF* */
78  .version = VPP_BUILD_VER,
79  .description = "Network Address Translation",
80 };
81 /* *INDENT-ON* */
82 
83 /**
84  * @brief Add/del NAT address to FIB.
85  *
86  * Add the external NAT address to the FIB as receive entries. This ensures
87  * that VPP will reply to ARP for this address and we don't need to enable
88  * proxy ARP on the outside interface.
89  *
90  * @param addr IPv4 address.
91  * @param plen address prefix length
92  * @param sw_if_index Interface.
93  * @param is_add If 0 delete, otherwise add.
94  */
95 void
97  int is_add)
98 {
99  fib_prefix_t prefix = {
100  .fp_len = p_len,
101  .fp_proto = FIB_PROTOCOL_IP4,
102  .fp_addr = {
103  .ip4.as_u32 = addr->as_u32,
104  },
105  };
106  u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
107 
108  if (is_add)
110  &prefix,
116  NULL,
117  sw_if_index,
118  ~0,
119  1,
120  NULL,
122  else
123  fib_table_entry_delete(fib_index,
124  &prefix,
126 }
127 
129 {
130  snat_address_t * ap;
132 
133  if (vrf_id != ~0)
134  sm->vrf_mode = 1;
135 
136  /* Check if address already exists */
137  vec_foreach (ap, sm->addresses)
138  {
139  if (ap->addr.as_u32 == addr->as_u32)
140  return;
141  }
142 
143  vec_add2 (sm->addresses, ap, 1);
144  ap->addr = *addr;
146 #define _(N, i, n, s) \
147  clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535);
149 #undef _
150 
151  /* Add external address to FIB */
152  pool_foreach (i, sm->interfaces,
153  ({
154  if (i->is_inside)
155  continue;
156 
157  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
158  break;
159  }));
160 }
161 
164 {
166  pool_foreach (m, sm->static_mappings,
167  ({
168  if (m->external_addr.as_u32 == addr.as_u32)
169  return 1;
170  }));
171 
172  return 0;
173 }
174 
176 {
177  u32 v;
178 
179  v = clib_net_to_host_u32(a->as_u32) + 1;
180  a->as_u32 = clib_host_to_net_u32(v);
181 }
182 
183 static void
185  ip4_address_t l_addr,
186  u16 l_port,
187  u32 sw_if_index,
188  u16 e_port,
189  u32 vrf_id,
190  snat_protocol_t proto,
191  int addr_only,
192  int is_add)
193 {
195 
196  vec_add2 (sm->to_resolve, rp, 1);
197  rp->l_addr.as_u32 = l_addr.as_u32;
198  rp->l_port = l_port;
199  rp->sw_if_index = sw_if_index;
200  rp->e_port = e_port;
201  rp->vrf_id = vrf_id;
202  rp->proto = proto;
203  rp->addr_only = addr_only;
204  rp->is_add = is_add;
205 }
206 
207 /**
208  * @brief Add static mapping.
209  *
210  * Create static mapping between local addr+port and external addr+port.
211  *
212  * @param l_addr Local IPv4 address.
213  * @param e_addr External IPv4 address.
214  * @param l_port Local port number.
215  * @param e_port External port number.
216  * @param vrf_id VRF ID.
217  * @param addr_only If 0 address port and pair mapping, otherwise address only.
218  * @param sw_if_index External port instead of specific IP address.
219  * @param is_add If 0 delete static mapping, otherwise add.
220  *
221  * @returns
222  */
224  u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
225  u32 sw_if_index, snat_protocol_t proto, int is_add)
226 {
227  snat_main_t * sm = &snat_main;
229  snat_session_key_t m_key;
230  clib_bihash_kv_8_8_t kv, value;
231  snat_address_t *a = 0;
232  u32 fib_index = ~0;
233  uword * p;
234  snat_interface_t *interface;
235  int i;
236 
237  /* If the external address is a specific interface address */
238  if (sw_if_index != ~0)
239  {
240  ip4_address_t * first_int_addr;
241 
242  /* Might be already set... */
243  first_int_addr = ip4_interface_first_address
244  (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
245 
246  /* DHCP resolution required? */
247  if (first_int_addr == 0)
248  {
250  (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
251  addr_only, is_add);
252  return 0;
253  }
254  else
255  e_addr.as_u32 = first_int_addr->as_u32;
256  }
257 
258  m_key.addr = e_addr;
259  m_key.port = addr_only ? 0 : e_port;
260  m_key.protocol = addr_only ? 0 : proto;
261  m_key.fib_index = sm->outside_fib_index;
262  kv.key = m_key.as_u64;
263  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
264  m = 0;
265  else
266  m = pool_elt_at_index (sm->static_mappings, value.value);
267 
268  if (is_add)
269  {
270  if (m)
271  return VNET_API_ERROR_VALUE_EXIST;
272 
273  /* Convert VRF id to FIB index */
274  if (vrf_id != ~0)
275  {
276  p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
277  if (!p)
278  return VNET_API_ERROR_NO_SUCH_FIB;
279  fib_index = p[0];
280  }
281  /* If not specified use inside VRF id from SNAT plugin startup config */
282  else
283  {
284  fib_index = sm->inside_fib_index;
285  vrf_id = sm->inside_vrf_id;
286  }
287 
288  /* Find external address in allocated addresses and reserve port for
289  address and port pair mapping when dynamic translations enabled */
290  if (!addr_only && !(sm->static_mapping_only))
291  {
292  for (i = 0; i < vec_len (sm->addresses); i++)
293  {
294  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
295  {
296  a = sm->addresses + i;
297  /* External port must be unused */
298  switch (proto)
299  {
300 #define _(N, j, n, s) \
301  case SNAT_PROTOCOL_##N: \
302  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
303  return VNET_API_ERROR_INVALID_VALUE; \
304  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
305  if (e_port > 1024) \
306  a->busy_##n##_ports++; \
307  break;
309 #undef _
310  default:
311  clib_warning("unknown_protocol");
312  return VNET_API_ERROR_INVALID_VALUE_2;
313  }
314  break;
315  }
316  }
317  /* External address must be allocated */
318  if (!a)
319  return VNET_API_ERROR_NO_SUCH_ENTRY;
320  }
321 
322  pool_get (sm->static_mappings, m);
323  memset (m, 0, sizeof (*m));
324  m->local_addr = l_addr;
325  m->external_addr = e_addr;
326  m->addr_only = addr_only;
327  m->vrf_id = vrf_id;
328  m->fib_index = fib_index;
329  if (!addr_only)
330  {
331  m->local_port = l_port;
332  m->external_port = e_port;
333  m->proto = proto;
334  }
335 
336  m_key.addr = m->local_addr;
337  m_key.port = m->local_port;
338  m_key.protocol = m->proto;
339  m_key.fib_index = m->fib_index;
340  kv.key = m_key.as_u64;
341  kv.value = m - sm->static_mappings;
342  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
343 
344  m_key.addr = m->external_addr;
345  m_key.port = m->external_port;
346  m_key.fib_index = sm->outside_fib_index;
347  kv.key = m_key.as_u64;
348  kv.value = m - sm->static_mappings;
349  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
350 
351  /* Assign worker */
352  if (sm->workers)
353  {
354  snat_user_key_t w_key0;
355  snat_worker_key_t w_key1;
356 
357  w_key0.addr = m->local_addr;
358  w_key0.fib_index = m->fib_index;
359  kv.key = w_key0.as_u64;
360 
361  if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
362  {
363  kv.value = sm->first_worker_index +
364  sm->workers[sm->next_worker++ % vec_len (sm->workers)];
365 
366  clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
367  }
368  else
369  {
370  kv.value = value.value;
371  }
372 
373  w_key1.addr = m->external_addr;
374  w_key1.port = clib_host_to_net_u16 (m->external_port);
375  w_key1.fib_index = sm->outside_fib_index;
376  kv.key = w_key1.as_u64;
377  clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1);
378  }
379  }
380  else
381  {
382  if (!m)
383  return VNET_API_ERROR_NO_SUCH_ENTRY;
384 
385  /* Free external address port */
386  if (!addr_only && !(sm->static_mapping_only))
387  {
388  for (i = 0; i < vec_len (sm->addresses); i++)
389  {
390  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
391  {
392  a = sm->addresses + i;
393  switch (proto)
394  {
395 #define _(N, j, n, s) \
396  case SNAT_PROTOCOL_##N: \
397  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
398  if (e_port > 1024) \
399  a->busy_##n##_ports--; \
400  break;
402 #undef _
403  default:
404  clib_warning("unknown_protocol");
405  return VNET_API_ERROR_INVALID_VALUE_2;
406  }
407  break;
408  }
409  }
410  }
411 
412  m_key.addr = m->local_addr;
413  m_key.port = m->local_port;
414  m_key.protocol = m->proto;
415  m_key.fib_index = m->fib_index;
416  kv.key = m_key.as_u64;
417  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
418 
419  m_key.addr = m->external_addr;
420  m_key.port = m->external_port;
421  m_key.fib_index = sm->outside_fib_index;
422  kv.key = m_key.as_u64;
423  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
424 
425  /* Delete session(s) for static mapping if exist */
426  if (!(sm->static_mapping_only) ||
427  (sm->static_mapping_only && sm->static_mapping_connection_tracking))
428  {
429  snat_user_key_t u_key;
430  snat_user_t *u;
431  dlist_elt_t * head, * elt;
432  u32 elt_index, head_index, del_elt_index;
433  u32 ses_index;
434  u64 user_index;
435  snat_session_t * s;
437 
438  u_key.addr = m->local_addr;
439  u_key.fib_index = m->fib_index;
440  kv.key = u_key.as_u64;
441  if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
442  {
443  user_index = value.value;
444  if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
445  tsm = vec_elt_at_index (sm->per_thread_data, value.value);
446  else
447  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
448  u = pool_elt_at_index (tsm->users, user_index);
449  if (u->nstaticsessions)
450  {
451  head_index = u->sessions_per_user_list_head_index;
452  head = pool_elt_at_index (tsm->list_pool, head_index);
453  elt_index = head->next;
454  elt = pool_elt_at_index (tsm->list_pool, elt_index);
455  ses_index = elt->value;
456  while (ses_index != ~0)
457  {
458  s = pool_elt_at_index (tsm->sessions, ses_index);
459  del_elt_index = elt_index;
460  elt_index = elt->next;
461  elt = pool_elt_at_index (tsm->list_pool, elt_index);
462  ses_index = elt->value;
463 
464  if (!addr_only)
465  {
466  if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
467  (clib_net_to_host_u16 (s->out2in.port) != e_port))
468  continue;
469  }
470 
471  /* log NAT event */
472  snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
473  s->out2in.addr.as_u32,
474  s->in2out.protocol,
475  s->in2out.port,
476  s->out2in.port,
477  s->in2out.fib_index);
478 
479  value.key = s->in2out.as_u64;
480  clib_bihash_add_del_8_8 (&sm->in2out, &value, 0);
481  value.key = s->out2in.as_u64;
482  clib_bihash_add_del_8_8 (&sm->out2in, &value, 0);
483  pool_put (tsm->sessions, s);
484 
485  clib_dlist_remove (tsm->list_pool, del_elt_index);
486  pool_put_index (tsm->list_pool, del_elt_index);
487  u->nstaticsessions--;
488 
489  if (!addr_only)
490  break;
491  }
492  if (addr_only)
493  {
494  pool_put (tsm->users, u);
495  clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
496  }
497  }
498  }
499  }
500 
501  /* Delete static mapping from pool */
502  pool_put (sm->static_mappings, m);
503  }
504 
505  if (!addr_only)
506  return 0;
507 
508  /* Add/delete external address to FIB */
509  pool_foreach (interface, sm->interfaces,
510  ({
511  if (interface->is_inside)
512  continue;
513 
514  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
515  break;
516  }));
517 
518  return 0;
519 }
520 
522 {
523  snat_address_t *a = 0;
524  snat_session_t *ses;
525  u32 *ses_to_be_removed = 0, *ses_index;
526  clib_bihash_kv_8_8_t kv, value;
527  snat_user_key_t user_key;
528  snat_user_t *u;
531  snat_interface_t *interface;
532  int i;
533 
534  /* Find SNAT address */
535  for (i=0; i < vec_len (sm->addresses); i++)
536  {
537  if (sm->addresses[i].addr.as_u32 == addr.as_u32)
538  {
539  a = sm->addresses + i;
540  break;
541  }
542  }
543  if (!a)
544  return VNET_API_ERROR_NO_SUCH_ENTRY;
545 
546  if (delete_sm)
547  {
548  pool_foreach (m, sm->static_mappings,
549  ({
550  if (m->external_addr.as_u32 == addr.as_u32)
551  (void) snat_add_static_mapping (m->local_addr, m->external_addr,
552  m->local_port, m->external_port,
553  m->vrf_id, m->addr_only, ~0,
554  m->proto, 0);
555  }));
556  }
557  else
558  {
559  /* Check if address is used in some static mapping */
561  {
562  clib_warning ("address used in static mapping");
563  return VNET_API_ERROR_UNSPECIFIED;
564  }
565  }
566 
567  /* Delete sessions using address */
568  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
569  {
570  vec_foreach (tsm, sm->per_thread_data)
571  {
572  pool_foreach (ses, tsm->sessions, ({
573  if (ses->out2in.addr.as_u32 == addr.as_u32)
574  {
575  /* log NAT event */
576  snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
577  ses->out2in.addr.as_u32,
578  ses->in2out.protocol,
579  ses->in2out.port,
580  ses->out2in.port,
581  ses->in2out.fib_index);
582  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
583  kv.key = ses->in2out.as_u64;
584  clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
585  kv.key = ses->out2in.as_u64;
586  clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
587  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
588  user_key.addr = ses->in2out.addr;
589  user_key.fib_index = ses->in2out.fib_index;
590  kv.key = user_key.as_u64;
591  if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
592  {
593  u = pool_elt_at_index (tsm->users, value.value);
594  u->nsessions--;
595  }
596  }
597  }));
598 
599  vec_foreach (ses_index, ses_to_be_removed)
600  pool_put_index (tsm->sessions, ses_index[0]);
601 
602  vec_free (ses_to_be_removed);
603  }
604  }
605 
606  vec_del1 (sm->addresses, i);
607 
608  /* Delete external address from FIB */
609  pool_foreach (interface, sm->interfaces,
610  ({
611  if (interface->is_inside)
612  continue;
613 
614  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
615  break;
616  }));
617 
618  return 0;
619 }
620 
621 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
622 {
623  snat_main_t *sm = &snat_main;
625  const char * feature_name;
626  snat_address_t * ap;
628  snat_det_map_t * dm;
629 
630  if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
631  feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast";
632  else
633  {
634  if (sm->num_workers > 1 && !sm->deterministic)
635  feature_name = is_inside ? "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff";
636  else if (sm->deterministic)
637  feature_name = is_inside ? "snat-det-in2out" : "snat-det-out2in";
638  else
639  feature_name = is_inside ? "snat-in2out" : "snat-out2in";
640  }
641 
642  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
643  !is_del, 0, 0);
644 
645  if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
646  sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
647 
648  if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
649  sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
650 
651  pool_foreach (i, sm->interfaces,
652  ({
653  if (i->sw_if_index == sw_if_index)
654  {
655  if (is_del)
656  pool_put (sm->interfaces, i);
657  else
658  return VNET_API_ERROR_VALUE_EXIST;
659 
660  goto fib;
661  }
662  }));
663 
664  if (is_del)
665  return VNET_API_ERROR_NO_SUCH_ENTRY;
666 
667  pool_get (sm->interfaces, i);
668  i->sw_if_index = sw_if_index;
669  i->is_inside = is_inside;
670 
671  /* Add/delete external addresses to FIB */
672 fib:
673  if (is_inside)
674  return 0;
675 
676  vec_foreach (ap, sm->addresses)
677  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
678 
679  pool_foreach (m, sm->static_mappings,
680  ({
681  if (!(m->addr_only))
682  continue;
683 
684  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
685  }));
686 
687  pool_foreach (dm, sm->det_maps,
688  ({
689  snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
690  }));
691 
692  return 0;
693 }
694 
695 int snat_set_workers (uword * bitmap)
696 {
697  snat_main_t *sm = &snat_main;
698  int i;
699 
700  if (sm->num_workers < 2)
701  return VNET_API_ERROR_FEATURE_DISABLED;
702 
703  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
704  return VNET_API_ERROR_INVALID_WORKER;
705 
706  vec_free (sm->workers);
707  clib_bitmap_foreach (i, bitmap,
708  ({
709  vec_add1(sm->workers, i);
710  }));
711 
712  return 0;
713 }
714 
715 
716 static void
718  uword opaque,
719  u32 sw_if_index,
720  ip4_address_t * address,
721  u32 address_length,
722  u32 if_address_index,
723  u32 is_delete);
724 
726 {
727  snat_main_t * sm = &snat_main;
728  clib_error_t * error = 0;
729  ip4_main_t * im = &ip4_main;
730  ip_lookup_main_t * lm = &im->lookup_main;
731  uword *p;
734  uword *bitmap = 0;
735  u32 i;
737 
738  sm->vlib_main = vm;
739  sm->vnet_main = vnet_get_main();
740  sm->ip4_main = im;
741  sm->ip4_lookup_main = lm;
742  sm->api_main = &api_main;
743  sm->first_worker_index = 0;
744  sm->next_worker = 0;
745  sm->num_workers = 0;
746  sm->workers = 0;
747  sm->fq_in2out_index = ~0;
748  sm->fq_out2in_index = ~0;
749  sm->udp_timeout = SNAT_UDP_TIMEOUT;
750  sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
751  sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
752  sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
753 
754  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
755  if (p)
756  {
757  tr = (vlib_thread_registration_t *) p[0];
758  if (tr)
759  {
760  sm->num_workers = tr->count;
761  sm->first_worker_index = tr->first_index;
762  }
763  }
764 
765  /* Use all available workers by default */
766  if (sm->num_workers > 1)
767  {
768  for (i=0; i < sm->num_workers; i++)
769  bitmap = clib_bitmap_set (bitmap, i, 1);
770  snat_set_workers(bitmap);
771  clib_bitmap_free (bitmap);
772  }
773 
774  error = snat_api_init(vm, sm);
775  if (error)
776  return error;
777 
778  /* Set up the interface address add/del callback */
780  cb4.function_opaque = 0;
781 
783 
784  /* Init IPFIX logging */
786 
787  error = nat64_init(vm);
788 
789  return error;
790 }
791 
793 
795  snat_session_key_t * k,
796  u32 address_index)
797 {
798  snat_address_t *a;
799  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
800 
801  ASSERT (address_index < vec_len (sm->addresses));
802 
803  a = sm->addresses + address_index;
804 
805  switch (k->protocol)
806  {
807 #define _(N, i, n, s) \
808  case SNAT_PROTOCOL_##N: \
809  ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
810  port_host_byte_order) == 1); \
811  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
812  port_host_byte_order, 0); \
813  a->busy_##n##_ports--; \
814  break;
816 #undef _
817  default:
818  clib_warning("unknown_protocol");
819  return;
820  }
821 }
822 
823 /**
824  * @brief Match SNAT static mapping.
825  *
826  * @param sm SNAT main.
827  * @param match Address and port to match.
828  * @param mapping External or local address and port of the matched mapping.
829  * @param by_external If 0 match by local address otherwise match by external
830  * address.
831  * @param is_addr_only If matched mapping is address only
832  *
833  * @returns 0 if match found otherwise 1.
834  */
836  snat_session_key_t match,
837  snat_session_key_t * mapping,
838  u8 by_external,
839  u8 *is_addr_only)
840 {
841  clib_bihash_kv_8_8_t kv, value;
843  snat_session_key_t m_key;
844  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
845 
846  if (by_external)
847  mapping_hash = &sm->static_mapping_by_external;
848 
849  m_key.addr = match.addr;
850  m_key.port = clib_net_to_host_u16 (match.port);
851  m_key.protocol = match.protocol;
852  m_key.fib_index = match.fib_index;
853 
854  kv.key = m_key.as_u64;
855 
856  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
857  {
858  /* Try address only mapping */
859  m_key.port = 0;
860  m_key.protocol = 0;
861  kv.key = m_key.as_u64;
862  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
863  return 1;
864  }
865 
866  m = pool_elt_at_index (sm->static_mappings, value.value);
867 
868  if (by_external)
869  {
870  mapping->addr = m->local_addr;
871  /* Address only mapping doesn't change port */
872  mapping->port = m->addr_only ? match.port
873  : clib_host_to_net_u16 (m->local_port);
874  mapping->fib_index = m->fib_index;
875  }
876  else
877  {
878  mapping->addr = m->external_addr;
879  /* Address only mapping doesn't change port */
880  mapping->port = m->addr_only ? match.port
881  : clib_host_to_net_u16 (m->external_port);
882  mapping->fib_index = sm->outside_fib_index;
883  }
884 
885  if (PREDICT_FALSE(is_addr_only != 0))
886  *is_addr_only = m->addr_only;
887 
888  return 0;
889 }
890 
892  u32 fib_index,
893  snat_session_key_t * k,
894  u32 * address_indexp)
895 {
896  int i;
897  snat_address_t *a;
898  u32 portnum;
899 
900  for (i = 0; i < vec_len (sm->addresses); i++)
901  {
902  a = sm->addresses + i;
903  if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
904  continue;
905  switch (k->protocol)
906  {
907 #define _(N, j, n, s) \
908  case SNAT_PROTOCOL_##N: \
909  if (a->busy_##n##_ports < (65535-1024)) \
910  { \
911  while (1) \
912  { \
913  portnum = random_u32 (&sm->random_seed); \
914  portnum &= 0xFFFF; \
915  if (portnum < 1024) \
916  continue; \
917  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
918  continue; \
919  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
920  a->busy_##n##_ports++; \
921  k->addr = a->addr; \
922  k->port = clib_host_to_net_u16(portnum); \
923  *address_indexp = i; \
924  return 0; \
925  } \
926  } \
927  break;
929 #undef _
930  default:
931  clib_warning("unknown protocol");
932  return 1;
933  }
934 
935  }
936  /* Totally out of translations to use... */
938  return 1;
939 }
940 
941 
942 static clib_error_t *
944  unformat_input_t * input,
945  vlib_cli_command_t * cmd)
946 {
947  unformat_input_t _line_input, *line_input = &_line_input;
948  snat_main_t * sm = &snat_main;
949  ip4_address_t start_addr, end_addr, this_addr;
950  u32 start_host_order, end_host_order;
951  u32 vrf_id = ~0;
952  int i, count;
953  int is_add = 1;
954  int rv = 0;
955  clib_error_t *error = 0;
956 
957  /* Get a line of input. */
958  if (!unformat_user (input, unformat_line_input, line_input))
959  return 0;
960 
961  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
962  {
963  if (unformat (line_input, "%U - %U",
964  unformat_ip4_address, &start_addr,
965  unformat_ip4_address, &end_addr))
966  ;
967  else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
968  ;
969  else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
970  end_addr = start_addr;
971  else if (unformat (line_input, "del"))
972  is_add = 0;
973  else
974  {
975  error = clib_error_return (0, "unknown input '%U'",
976  format_unformat_error, line_input);
977  goto done;
978  }
979  }
980 
981  if (sm->static_mapping_only)
982  {
983  error = clib_error_return (0, "static mapping only mode");
984  goto done;
985  }
986 
987  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
988  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
989 
990  if (end_host_order < start_host_order)
991  {
992  error = clib_error_return (0, "end address less than start address");
993  goto done;
994  }
995 
996  count = (end_host_order - start_host_order) + 1;
997 
998  if (count > 1024)
999  clib_warning ("%U - %U, %d addresses...",
1000  format_ip4_address, &start_addr,
1001  format_ip4_address, &end_addr,
1002  count);
1003 
1004  this_addr = start_addr;
1005 
1006  for (i = 0; i < count; i++)
1007  {
1008  if (is_add)
1009  snat_add_address (sm, &this_addr, vrf_id);
1010  else
1011  rv = snat_del_address (sm, this_addr, 0);
1012 
1013  switch (rv)
1014  {
1015  case VNET_API_ERROR_NO_SUCH_ENTRY:
1016  error = clib_error_return (0, "S-NAT address not exist.");
1017  goto done;
1018  case VNET_API_ERROR_UNSPECIFIED:
1019  error = clib_error_return (0, "S-NAT address used in static mapping.");
1020  goto done;
1021  default:
1022  break;
1023  }
1024 
1025  increment_v4_address (&this_addr);
1026  }
1027 
1028 done:
1029  unformat_free (line_input);
1030 
1031  return error;
1032 }
1033 
1034 VLIB_CLI_COMMAND (add_address_command, static) = {
1035  .path = "snat add address",
1036  .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] "
1037  "[tenant-vrf <vrf-id>] [del]",
1038  .function = add_address_command_fn,
1039 };
1040 
1041 static clib_error_t *
1043  unformat_input_t * input,
1044  vlib_cli_command_t * cmd)
1045 {
1046  unformat_input_t _line_input, *line_input = &_line_input;
1047  vnet_main_t * vnm = vnet_get_main();
1048  clib_error_t * error = 0;
1049  u32 sw_if_index;
1050  u32 * inside_sw_if_indices = 0;
1051  u32 * outside_sw_if_indices = 0;
1052  int is_del = 0;
1053  int i;
1054 
1055  sw_if_index = ~0;
1056 
1057  /* Get a line of input. */
1058  if (!unformat_user (input, unformat_line_input, line_input))
1059  return 0;
1060 
1061  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1062  {
1063  if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1064  vnm, &sw_if_index))
1065  vec_add1 (inside_sw_if_indices, sw_if_index);
1066  else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1067  vnm, &sw_if_index))
1068  vec_add1 (outside_sw_if_indices, sw_if_index);
1069  else if (unformat (line_input, "del"))
1070  is_del = 1;
1071  else
1072  {
1073  error = clib_error_return (0, "unknown input '%U'",
1074  format_unformat_error, line_input);
1075  goto done;
1076  }
1077  }
1078 
1079  if (vec_len (inside_sw_if_indices))
1080  {
1081  for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1082  {
1083  sw_if_index = inside_sw_if_indices[i];
1084  snat_interface_add_del (sw_if_index, 1, is_del);
1085  }
1086  }
1087 
1088  if (vec_len (outside_sw_if_indices))
1089  {
1090  for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1091  {
1092  sw_if_index = outside_sw_if_indices[i];
1093  snat_interface_add_del (sw_if_index, 0, is_del);
1094  }
1095  }
1096 
1097 done:
1098  unformat_free (line_input);
1099  vec_free (inside_sw_if_indices);
1100  vec_free (outside_sw_if_indices);
1101 
1102  return error;
1103 }
1104 
1105 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1106  .path = "set interface snat",
1107  .function = snat_feature_command_fn,
1108  .short_help = "set interface snat in <intfc> out <intfc> [del]",
1109 };
1110 
1111 uword
1112 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1113 {
1114  u32 *r = va_arg (*args, u32 *);
1115 
1116  if (0);
1117 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1119 #undef _
1120  else
1121  return 0;
1122  return 1;
1123 }
1124 
1125 u8 *
1126 format_snat_protocol (u8 * s, va_list * args)
1127 {
1128  u32 i = va_arg (*args, u32);
1129  u8 *t = 0;
1130 
1131  switch (i)
1132  {
1133 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1135 #undef _
1136  default:
1137  s = format (s, "unknown");
1138  }
1139  s = format (s, "%s", t);
1140  return s;
1141 }
1142 
1143 static clib_error_t *
1145  unformat_input_t * input,
1146  vlib_cli_command_t * cmd)
1147 {
1148  unformat_input_t _line_input, *line_input = &_line_input;
1149  clib_error_t * error = 0;
1150  ip4_address_t l_addr, e_addr;
1151  u32 l_port = 0, e_port = 0, vrf_id = ~0;
1152  int is_add = 1;
1153  int addr_only = 1;
1154  u32 sw_if_index = ~0;
1155  vnet_main_t * vnm = vnet_get_main();
1156  int rv;
1157  snat_protocol_t proto;
1158  u8 proto_set = 0;
1159 
1160  /* Get a line of input. */
1161  if (!unformat_user (input, unformat_line_input, line_input))
1162  return 0;
1163 
1164  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1165  {
1166  if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1167  &l_port))
1168  addr_only = 0;
1169  else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1170  ;
1171  else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1172  &e_addr, &e_port))
1173  addr_only = 0;
1174  else if (unformat (line_input, "external %U", unformat_ip4_address,
1175  &e_addr))
1176  ;
1177  else if (unformat (line_input, "external %U %u",
1178  unformat_vnet_sw_interface, vnm, &sw_if_index,
1179  &e_port))
1180  addr_only = 0;
1181 
1182  else if (unformat (line_input, "external %U",
1183  unformat_vnet_sw_interface, vnm, &sw_if_index))
1184  ;
1185  else if (unformat (line_input, "vrf %u", &vrf_id))
1186  ;
1187  else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1188  proto_set = 1;
1189  else if (unformat (line_input, "del"))
1190  is_add = 0;
1191  else
1192  {
1193  error = clib_error_return (0, "unknown input: '%U'",
1194  format_unformat_error, line_input);
1195  goto done;
1196  }
1197  }
1198 
1199  if (!addr_only && !proto_set)
1200  {
1201  error = clib_error_return (0, "missing protocol");
1202  goto done;
1203  }
1204 
1205  rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1206  vrf_id, addr_only, sw_if_index, proto, is_add);
1207 
1208  switch (rv)
1209  {
1210  case VNET_API_ERROR_INVALID_VALUE:
1211  error = clib_error_return (0, "External port already in use.");
1212  goto done;
1213  case VNET_API_ERROR_NO_SUCH_ENTRY:
1214  if (is_add)
1215  error = clib_error_return (0, "External addres must be allocated.");
1216  else
1217  error = clib_error_return (0, "Mapping not exist.");
1218  goto done;
1219  case VNET_API_ERROR_NO_SUCH_FIB:
1220  error = clib_error_return (0, "No such VRF id.");
1221  goto done;
1222  case VNET_API_ERROR_VALUE_EXIST:
1223  error = clib_error_return (0, "Mapping already exist.");
1224  goto done;
1225  default:
1226  break;
1227  }
1228 
1229 done:
1230  unformat_free (line_input);
1231 
1232  return error;
1233 }
1234 
1235 /*?
1236  * @cliexpar
1237  * @cliexstart{snat add static mapping}
1238  * Static mapping allows hosts on the external network to initiate connection
1239  * to to the local network host.
1240  * To create static mapping between local host address 10.0.0.3 port 6303 and
1241  * external address 4.4.4.4 port 3606 for TCP protocol use:
1242  * vpp# snat add static mapping local tcp 10.0.0.3 6303 external 4.4.4.4 3606
1243  * If not runnig "static mapping only" S-NAT plugin mode use before:
1244  * vpp# snat add address 4.4.4.4
1245  * To create static mapping between local and external address use:
1246  * vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
1247  * @cliexend
1248 ?*/
1249 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1250  .path = "snat add static mapping",
1251  .function = add_static_mapping_command_fn,
1252  .short_help =
1253  "snat add static mapping local tcp|udp|icmp <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1254 };
1255 
1256 static clib_error_t *
1258  unformat_input_t * input,
1259  vlib_cli_command_t * cmd)
1260 {
1261  unformat_input_t _line_input, *line_input = &_line_input;
1262  uword *bitmap = 0;
1263  int rv = 0;
1264  clib_error_t *error = 0;
1265 
1266  /* Get a line of input. */
1267  if (!unformat_user (input, unformat_line_input, line_input))
1268  return 0;
1269 
1270  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1271  {
1272  if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1273  ;
1274  else
1275  {
1276  error = clib_error_return (0, "unknown input '%U'",
1277  format_unformat_error, line_input);
1278  goto done;
1279  }
1280  }
1281 
1282  if (bitmap == 0)
1283  {
1284  error = clib_error_return (0, "List of workers must be specified.");
1285  goto done;
1286  }
1287 
1288  rv = snat_set_workers(bitmap);
1289 
1290  clib_bitmap_free (bitmap);
1291 
1292  switch (rv)
1293  {
1294  case VNET_API_ERROR_INVALID_WORKER:
1295  error = clib_error_return (0, "Invalid worker(s).");
1296  goto done;
1297  case VNET_API_ERROR_FEATURE_DISABLED:
1298  error = clib_error_return (0,
1299  "Supported only if 2 or more workes available.");
1300  goto done;
1301  default:
1302  break;
1303  }
1304 
1305 done:
1306  unformat_free (line_input);
1307 
1308  return error;
1309 }
1310 
1311 /*?
1312  * @cliexpar
1313  * @cliexstart{set snat workers}
1314  * Set SNAT workers if 2 or more workers available, use:
1315  * vpp# set snat workers 0-2,5
1316  * @cliexend
1317 ?*/
1318 VLIB_CLI_COMMAND (set_workers_command, static) = {
1319  .path = "set snat workers",
1320  .function = set_workers_command_fn,
1321  .short_help =
1322  "set snat workers <workers-list>",
1323 };
1324 
1325 static clib_error_t *
1327  unformat_input_t * input,
1328  vlib_cli_command_t * cmd)
1329 {
1330  unformat_input_t _line_input, *line_input = &_line_input;
1331  u32 domain_id = 0;
1332  u32 src_port = 0;
1333  u8 enable = 1;
1334  int rv = 0;
1335  clib_error_t *error = 0;
1336 
1337  /* Get a line of input. */
1338  if (!unformat_user (input, unformat_line_input, line_input))
1339  return 0;
1340 
1341  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1342  {
1343  if (unformat (line_input, "domain %d", &domain_id))
1344  ;
1345  else if (unformat (line_input, "src-port %d", &src_port))
1346  ;
1347  else if (unformat (line_input, "disable"))
1348  enable = 0;
1349  else
1350  {
1351  error = clib_error_return (0, "unknown input '%U'",
1352  format_unformat_error, line_input);
1353  goto done;
1354  }
1355  }
1356 
1357  rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
1358 
1359  if (rv)
1360  {
1361  error = clib_error_return (0, "ipfix logging enable failed");
1362  goto done;
1363  }
1364 
1365 done:
1366  unformat_free (line_input);
1367 
1368  return error;
1369 }
1370 
1371 /*?
1372  * @cliexpar
1373  * @cliexstart{snat ipfix logging}
1374  * To enable SNAT IPFIX logging use:
1375  * vpp# snat ipfix logging
1376  * To set IPFIX exporter use:
1377  * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
1378  * @cliexend
1379 ?*/
1380 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
1381  .path = "snat ipfix logging",
1383  .short_help = "snat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
1384 };
1385 
1386 static u32
1388 {
1389  snat_main_t *sm = &snat_main;
1390  snat_user_key_t key0;
1391  clib_bihash_kv_8_8_t kv0, value0;
1392  u32 next_worker_index = 0;
1393 
1394  key0.addr = ip0->src_address;
1395  key0.fib_index = rx_fib_index0;
1396 
1397  kv0.key = key0.as_u64;
1398 
1399  /* Ever heard of of the "user" before? */
1400  if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0))
1401  {
1402  /* No, assign next available worker (RR) */
1403  next_worker_index = sm->first_worker_index;
1404  if (vec_len (sm->workers))
1405  {
1406  next_worker_index +=
1407  sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
1408  }
1409 
1410  /* add non-traslated packets worker lookup */
1411  kv0.value = next_worker_index;
1412  clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
1413  }
1414  else
1415  next_worker_index = value0.value;
1416 
1417  return next_worker_index;
1418 }
1419 
1420 static u32
1422 {
1423  snat_main_t *sm = &snat_main;
1424  snat_worker_key_t key0;
1425  clib_bihash_kv_8_8_t kv0, value0;
1426  udp_header_t * udp0;
1427  u32 next_worker_index = 0;
1428 
1429  udp0 = ip4_next_header (ip0);
1430 
1431  key0.addr = ip0->dst_address;
1432  key0.port = udp0->dst_port;
1433  key0.fib_index = rx_fib_index0;
1434 
1435  if (PREDICT_FALSE(ip0->protocol == IP_PROTOCOL_ICMP))
1436  {
1437  icmp46_header_t * icmp0 = (icmp46_header_t *) udp0;
1438  icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1);
1439  key0.port = echo0->identifier;
1440  }
1441 
1442  kv0.key = key0.as_u64;
1443 
1444  /* Ever heard of of the "user" before? */
1445  if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
1446  {
1447  key0.port = 0;
1448  kv0.key = key0.as_u64;
1449 
1450  if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
1451  {
1452  /* No, assign next available worker (RR) */
1453  next_worker_index = sm->first_worker_index;
1454  if (vec_len (sm->workers))
1455  {
1456  next_worker_index +=
1457  sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
1458  }
1459  }
1460  else
1461  {
1462  /* Static mapping without port */
1463  next_worker_index = value0.value;
1464  }
1465 
1466  /* Add to translated packets worker lookup */
1467  kv0.value = next_worker_index;
1468  clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
1469  }
1470  else
1471  next_worker_index = value0.value;
1472 
1473  return next_worker_index;
1474 }
1475 
1476 static clib_error_t *
1478 {
1479  snat_main_t * sm = &snat_main;
1480  u32 translation_buckets = 1024;
1481  u32 translation_memory_size = 128<<20;
1482  u32 user_buckets = 128;
1483  u32 user_memory_size = 64<<20;
1484  u32 max_translations_per_user = 100;
1485  u32 outside_vrf_id = 0;
1486  u32 inside_vrf_id = 0;
1487  u32 static_mapping_buckets = 1024;
1488  u32 static_mapping_memory_size = 64<<20;
1489  u8 static_mapping_only = 0;
1490  u8 static_mapping_connection_tracking = 0;
1492 
1493  sm->deterministic = 0;
1494 
1495  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1496  {
1497  if (unformat (input, "translation hash buckets %d", &translation_buckets))
1498  ;
1499  else if (unformat (input, "translation hash memory %d",
1500  &translation_memory_size));
1501  else if (unformat (input, "user hash buckets %d", &user_buckets))
1502  ;
1503  else if (unformat (input, "user hash memory %d",
1504  &user_memory_size))
1505  ;
1506  else if (unformat (input, "max translations per user %d",
1507  &max_translations_per_user))
1508  ;
1509  else if (unformat (input, "outside VRF id %d",
1510  &outside_vrf_id))
1511  ;
1512  else if (unformat (input, "inside VRF id %d",
1513  &inside_vrf_id))
1514  ;
1515  else if (unformat (input, "static mapping only"))
1516  {
1517  static_mapping_only = 1;
1518  if (unformat (input, "connection tracking"))
1519  static_mapping_connection_tracking = 1;
1520  }
1521  else if (unformat (input, "deterministic"))
1522  sm->deterministic = 1;
1523  else
1524  return clib_error_return (0, "unknown input '%U'",
1525  format_unformat_error, input);
1526  }
1527 
1528  /* for show commands, etc. */
1529  sm->translation_buckets = translation_buckets;
1530  sm->translation_memory_size = translation_memory_size;
1531  sm->user_buckets = user_buckets;
1532  sm->user_memory_size = user_memory_size;
1533  sm->max_translations_per_user = max_translations_per_user;
1534  sm->outside_vrf_id = outside_vrf_id;
1535  sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1536  outside_vrf_id);
1537  sm->inside_vrf_id = inside_vrf_id;
1538  sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1539  inside_vrf_id);
1540  sm->static_mapping_only = static_mapping_only;
1541  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
1542 
1543  if (sm->deterministic)
1544  {
1545  sm->in2out_node_index = snat_det_in2out_node.index;
1546  sm->out2in_node_index = snat_det_out2in_node.index;
1547  sm->icmp_match_in2out_cb = icmp_match_in2out_det;
1548  sm->icmp_match_out2in_cb = icmp_match_out2in_det;
1549  }
1550  else
1551  {
1552  sm->worker_in2out_cb = snat_get_worker_in2out_cb;
1553  sm->worker_out2in_cb = snat_get_worker_out2in_cb;
1554  sm->in2out_node_index = snat_in2out_node.index;
1555  sm->out2in_node_index = snat_out2in_node.index;
1556  if (!static_mapping_only ||
1557  (static_mapping_only && static_mapping_connection_tracking))
1558  {
1559  sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
1560  sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
1561 
1562  clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
1563  user_memory_size);
1564 
1565  clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
1566  user_memory_size);
1567 
1568  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1569 
1570  clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
1571  translation_memory_size);
1572 
1573  clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
1574  translation_memory_size);
1575 
1576  clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
1577  user_memory_size);
1578  }
1579  else
1580  {
1581  sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
1582  sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
1583  }
1584  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1585  "static_mapping_by_local", static_mapping_buckets,
1586  static_mapping_memory_size);
1587 
1588  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1589  "static_mapping_by_external", static_mapping_buckets,
1590  static_mapping_memory_size);
1591  }
1592 
1593  return 0;
1594 }
1595 
1597 
1598 u8 * format_snat_session_state (u8 * s, va_list * args)
1599 {
1600  u32 i = va_arg (*args, u32);
1601  u8 *t = 0;
1602 
1603  switch (i)
1604  {
1605 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
1607 #undef _
1608  default:
1609  t = format (t, "unknown");
1610  }
1611  s = format (s, "%s", t);
1612  return s;
1613 }
1614 
1615 u8 * format_snat_key (u8 * s, va_list * args)
1616 {
1617  snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
1618  char * protocol_string = "unknown";
1619  static char *protocol_strings[] = {
1620  "UDP",
1621  "TCP",
1622  "ICMP",
1623  };
1624 
1625  if (key->protocol < ARRAY_LEN(protocol_strings))
1626  protocol_string = protocol_strings[key->protocol];
1627 
1628  s = format (s, "%U proto %s port %d fib %d",
1629  format_ip4_address, &key->addr, protocol_string,
1630  clib_net_to_host_u16 (key->port), key->fib_index);
1631  return s;
1632 }
1633 
1634 u8 * format_snat_session (u8 * s, va_list * args)
1635 {
1636  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
1637  snat_session_t * sess = va_arg (*args, snat_session_t *);
1638 
1639  s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
1640  s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
1641  s = format (s, " last heard %.2f\n", sess->last_heard);
1642  s = format (s, " total pkts %d, total bytes %lld\n",
1643  sess->total_pkts, sess->total_bytes);
1644  if (snat_is_session_static (sess))
1645  s = format (s, " static translation\n");
1646  else
1647  s = format (s, " dynamic translation\n");
1648 
1649  return s;
1650 }
1651 
1652 u8 * format_snat_user (u8 * s, va_list * args)
1653 {
1655  snat_user_t * u = va_arg (*args, snat_user_t *);
1656  int verbose = va_arg (*args, int);
1657  dlist_elt_t * head, * elt;
1658  u32 elt_index, head_index;
1659  u32 session_index;
1660  snat_session_t * sess;
1661 
1662  s = format (s, "%U: %d dynamic translations, %d static translations\n",
1664 
1665  if (verbose == 0)
1666  return s;
1667 
1668  if (u->nsessions || u->nstaticsessions)
1669  {
1670  head_index = u->sessions_per_user_list_head_index;
1671  head = pool_elt_at_index (sm->list_pool, head_index);
1672 
1673  elt_index = head->next;
1674  elt = pool_elt_at_index (sm->list_pool, elt_index);
1675  session_index = elt->value;
1676 
1677  while (session_index != ~0)
1678  {
1679  sess = pool_elt_at_index (sm->sessions, session_index);
1680 
1681  s = format (s, " %U\n", format_snat_session, sm, sess);
1682 
1683  elt_index = elt->next;
1684  elt = pool_elt_at_index (sm->list_pool, elt_index);
1685  session_index = elt->value;
1686  }
1687  }
1688 
1689  return s;
1690 }
1691 
1692 u8 * format_snat_static_mapping (u8 * s, va_list * args)
1693 {
1694  snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
1695 
1696  if (m->addr_only)
1697  s = format (s, "local %U external %U vrf %d",
1700  m->vrf_id);
1701  else
1702  s = format (s, "%U local %U:%d external %U:%d vrf %d",
1706  m->vrf_id);
1707 
1708  return s;
1709 }
1710 
1711 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
1712 {
1714  vnet_main_t *vnm = vnet_get_main();
1715 
1716  if (m->addr_only)
1717  s = format (s, "local %U external %U vrf %d",
1721  m->vrf_id);
1722  else
1723  s = format (s, "%U local %U:%d external %U:%d vrf %d",
1725  format_ip4_address, &m->l_addr, m->l_port,
1728  m->vrf_id);
1729 
1730  return s;
1731 }
1732 
1733 u8 * format_det_map_ses (u8 * s, va_list * args)
1734 {
1735  snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
1736  ip4_address_t in_addr, out_addr;
1737  u32 in_offset, out_offset;
1738  snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
1739  u32 * i = va_arg (*args, u32 *);
1740 
1741  u32 user_index = *i / SNAT_DET_SES_PER_USER;
1742  in_addr.as_u32 = clib_host_to_net_u32 (
1743  clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
1744  in_offset = clib_net_to_host_u32(in_addr.as_u32) -
1745  clib_net_to_host_u32(det_map->in_addr.as_u32);
1746  out_offset = in_offset / det_map->sharing_ratio;
1747  out_addr.as_u32 = clib_host_to_net_u32(
1748  clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
1749  s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
1750  format_ip4_address, &in_addr,
1751  clib_net_to_host_u16 (ses->in_port),
1752  format_ip4_address, &out_addr,
1753  clib_net_to_host_u16 (ses->out.out_port),
1755  clib_net_to_host_u16 (ses->out.ext_host_port),
1757  ses->expire);
1758 
1759  return s;
1760 }
1761 
1762 static clib_error_t *
1764  unformat_input_t * input,
1765  vlib_cli_command_t * cmd)
1766 {
1767  int verbose = 0;
1768  snat_main_t * sm = &snat_main;
1769  snat_user_t * u;
1772  snat_address_t * ap;
1773  vnet_main_t *vnm = vnet_get_main();
1775  u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
1776  uword j = 0;
1778  snat_det_map_t * dm;
1779  snat_det_session_t * ses;
1780 
1781  if (unformat (input, "detail"))
1782  verbose = 1;
1783  else if (unformat (input, "verbose"))
1784  verbose = 2;
1785 
1786  if (sm->static_mapping_only)
1787  {
1788  if (sm->static_mapping_connection_tracking)
1789  vlib_cli_output (vm, "SNAT mode: static mapping only connection "
1790  "tracking");
1791  else
1792  vlib_cli_output (vm, "SNAT mode: static mapping only");
1793  }
1794  else if (sm->deterministic)
1795  {
1796  vlib_cli_output (vm, "SNAT mode: deterministic mapping");
1797  }
1798  else
1799  {
1800  vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
1801  }
1802 
1803  if (verbose > 0)
1804  {
1805  pool_foreach (i, sm->interfaces,
1806  ({
1807  vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
1808  vnet_get_sw_interface (vnm, i->sw_if_index),
1809  i->is_inside ? "in" : "out");
1810  }));
1811 
1812  if (vec_len (sm->auto_add_sw_if_indices))
1813  {
1814  vlib_cli_output (vm, "SNAT pool addresses interfaces:");
1815  vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
1816  {
1818  vnet_get_sw_interface (vnm, *sw_if_index));
1819  }
1820  }
1821 
1822  vec_foreach (ap, sm->addresses)
1823  {
1824  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
1825  if (ap->fib_index != ~0)
1826  vlib_cli_output (vm, " tenant VRF: %u",
1828  else
1829  vlib_cli_output (vm, " tenant VRF independent");
1830 #define _(N, i, n, s) \
1831  vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
1833 #undef _
1834  }
1835  }
1836 
1837  if (sm->num_workers > 1)
1838  {
1839  vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
1840  if (verbose > 0)
1841  {
1842  vec_foreach (worker, sm->workers)
1843  {
1845  vlib_worker_threads + *worker + sm->first_worker_index;
1846  vlib_cli_output (vm, " %s", w->name);
1847  }
1848  }
1849  }
1850 
1851  if (sm->deterministic)
1852  {
1853  vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
1854  vlib_cli_output (vm, "tcp-established timeout: %dsec",
1855  sm->tcp_established_timeout);
1856  vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
1857  sm->tcp_transitory_timeout);
1858  vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
1859  vlib_cli_output (vm, "%d deterministic mappings",
1860  pool_elts (sm->det_maps));
1861  if (verbose > 0)
1862  {
1863  pool_foreach (dm, sm->det_maps,
1864  ({
1865  vlib_cli_output (vm, "in %U/%d out %U/%d\n",
1866  format_ip4_address, &dm->in_addr, dm->in_plen,
1867  format_ip4_address, &dm->out_addr, dm->out_plen);
1868  vlib_cli_output (vm, " outside address sharing ratio: %d\n",
1869  dm->sharing_ratio);
1870  vlib_cli_output (vm, " number of ports per inside host: %d\n",
1871  dm->ports_per_host);
1872  vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
1873  if (verbose > 1)
1874  {
1875  vec_foreach_index (j, dm->sessions)
1876  {
1877  ses = vec_elt_at_index (dm->sessions, j);
1878  if (ses->in_port)
1879  vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
1880  &j);
1881  }
1882  }
1883  }));
1884  }
1885  }
1886  else
1887  {
1888  if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1889  {
1890  vlib_cli_output (vm, "%d static mappings",
1891  pool_elts (sm->static_mappings));
1892 
1893  if (verbose > 0)
1894  {
1895  pool_foreach (m, sm->static_mappings,
1896  ({
1897  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1898  }));
1899  }
1900  }
1901  else
1902  {
1903  vec_foreach (tsm, sm->per_thread_data)
1904  {
1905  users_num += pool_elts (tsm->users);
1906  sessions_num += pool_elts (tsm->sessions);
1907  }
1908 
1909  vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
1910  " %d static mappings",
1911  users_num,
1912  vec_len (sm->addresses),
1913  sessions_num,
1914  pool_elts (sm->static_mappings));
1915 
1916  if (verbose > 0)
1917  {
1918  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
1919  verbose - 1);
1920  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
1921  verbose - 1);
1922  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
1923  verbose - 1);
1924  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
1925  verbose - 1);
1926  vec_foreach_index (j, sm->per_thread_data)
1927  {
1928  tsm = vec_elt_at_index (sm->per_thread_data, j);
1929 
1930  if (pool_elts (tsm->users) == 0)
1931  continue;
1932 
1934  vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
1935  w->lcore_id);
1936  vlib_cli_output (vm, " %d list pool elements",
1937  pool_elts (tsm->list_pool));
1938 
1939  pool_foreach (u, tsm->users,
1940  ({
1941  vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
1942  verbose - 1);
1943  }));
1944  }
1945 
1946  if (pool_elts (sm->static_mappings))
1947  {
1948  vlib_cli_output (vm, "static mappings:");
1949  pool_foreach (m, sm->static_mappings,
1950  ({
1951  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1952  }));
1953  for (j = 0; j < vec_len (sm->to_resolve); j++)
1954  {
1955  rp = sm->to_resolve + j;
1956  vlib_cli_output (vm, "%U",
1958  }
1959  }
1960  }
1961  }
1962  }
1963  return 0;
1964 }
1965 
1966 VLIB_CLI_COMMAND (show_snat_command, static) = {
1967  .path = "show snat",
1968  .short_help = "show snat",
1969  .function = show_snat_command_fn,
1970 };
1971 
1972 
1973 static void
1975  uword opaque,
1976  u32 sw_if_index,
1977  ip4_address_t * address,
1978  u32 address_length,
1979  u32 if_address_index,
1980  u32 is_delete)
1981 {
1982  snat_main_t *sm = &snat_main;
1984  u32 *indices_to_delete = 0;
1985  int i, j;
1986  int rv;
1987 
1988  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
1989  {
1990  if (sw_if_index == sm->auto_add_sw_if_indices[i])
1991  {
1992  if (!is_delete)
1993  {
1994  /* Don't trip over lease renewal, static config */
1995  for (j = 0; j < vec_len(sm->addresses); j++)
1996  if (sm->addresses[j].addr.as_u32 == address->as_u32)
1997  return;
1998 
1999  snat_add_address (sm, address, ~0);
2000  /* Scan static map resolution vector */
2001  for (j = 0; j < vec_len (sm->to_resolve); j++)
2002  {
2003  rp = sm->to_resolve + j;
2004  /* On this interface? */
2005  if (rp->sw_if_index == sw_if_index)
2006  {
2007  /* Add the static mapping */
2008  rv = snat_add_static_mapping (rp->l_addr,
2009  address[0],
2010  rp->l_port,
2011  rp->e_port,
2012  rp->vrf_id,
2013  rp->addr_only,
2014  ~0 /* sw_if_index */,
2015  rp->proto,
2016  rp->is_add);
2017  if (rv)
2018  clib_warning ("snat_add_static_mapping returned %d",
2019  rv);
2020  vec_add1 (indices_to_delete, j);
2021  }
2022  }
2023  /* If we resolved any of the outstanding static mappings */
2024  if (vec_len(indices_to_delete))
2025  {
2026  /* Delete them */
2027  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2028  vec_delete(sm->to_resolve, 1, j);
2029  vec_free(indices_to_delete);
2030  }
2031  return;
2032  }
2033  else
2034  {
2035  (void) snat_del_address(sm, address[0], 1);
2036  return;
2037  }
2038  }
2039  }
2040 }
2041 
2042 
2043 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
2044 {
2045  ip4_main_t * ip4_main = sm->ip4_main;
2046  ip4_address_t * first_int_addr;
2048  u32 *indices_to_delete = 0;
2049  int i, j;
2050 
2051  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2052  0 /* just want the address*/);
2053 
2054  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2055  {
2056  if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2057  {
2058  if (is_del)
2059  {
2060  /* if have address remove it */
2061  if (first_int_addr)
2062  (void) snat_del_address (sm, first_int_addr[0], 1);
2063  else
2064  {
2065  for (j = 0; j < vec_len (sm->to_resolve); j++)
2066  {
2067  rp = sm->to_resolve + j;
2068  if (rp->sw_if_index == sw_if_index)
2069  vec_add1 (indices_to_delete, j);
2070  }
2071  if (vec_len(indices_to_delete))
2072  {
2073  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2074  vec_del1(sm->to_resolve, j);
2075  vec_free(indices_to_delete);
2076  }
2077  }
2078  vec_del1(sm->auto_add_sw_if_indices, i);
2079  }
2080  else
2081  return VNET_API_ERROR_VALUE_EXIST;
2082 
2083  return 0;
2084  }
2085  }
2086 
2087  if (is_del)
2088  return VNET_API_ERROR_NO_SUCH_ENTRY;
2089 
2090  /* add to the auto-address list */
2091  vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2092 
2093  /* If the address is already bound - or static - add it now */
2094  if (first_int_addr)
2095  snat_add_address (sm, first_int_addr, ~0);
2096 
2097  return 0;
2098 }
2099 
2100 static clib_error_t *
2102  unformat_input_t * input,
2103  vlib_cli_command_t * cmd)
2104 {
2105  snat_main_t *sm = &snat_main;
2106  unformat_input_t _line_input, *line_input = &_line_input;
2107  u32 sw_if_index;
2108  int rv;
2109  int is_del = 0;
2110  clib_error_t *error = 0;
2111 
2112  /* Get a line of input. */
2113  if (!unformat_user (input, unformat_line_input, line_input))
2114  return 0;
2115 
2116  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2117  {
2118  if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2119  sm->vnet_main, &sw_if_index))
2120  ;
2121  else if (unformat (line_input, "del"))
2122  is_del = 1;
2123  else
2124  {
2125  error = clib_error_return (0, "unknown input '%U'",
2126  format_unformat_error, line_input);
2127  goto done;
2128  }
2129  }
2130 
2131  rv = snat_add_interface_address (sm, sw_if_index, is_del);
2132 
2133  switch (rv)
2134  {
2135  case 0:
2136  break;
2137 
2138  default:
2139  error = clib_error_return (0, "snat_add_interface_address returned %d",
2140  rv);
2141  goto done;
2142  }
2143 
2144 done:
2145  unformat_free (line_input);
2146 
2147  return error;
2148 }
2149 
2150 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2151  .path = "snat add interface address",
2152  .short_help = "snat add interface address <interface> [del]",
2154 };
2155 
2156 static clib_error_t *
2158  unformat_input_t * input,
2159  vlib_cli_command_t * cmd)
2160 {
2161  snat_main_t *sm = &snat_main;
2162  unformat_input_t _line_input, *line_input = &_line_input;
2163  ip4_address_t in_addr, out_addr;
2164  u32 in_plen, out_plen;
2165  int is_add = 1, rv;
2166  clib_error_t *error = 0;
2167 
2168  /* Get a line of input. */
2169  if (!unformat_user (input, unformat_line_input, line_input))
2170  return 0;
2171 
2172  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2173  {
2174  if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
2175  ;
2176  else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
2177  ;
2178  else if (unformat (line_input, "del"))
2179  is_add = 0;
2180  else
2181  {
2182  error = clib_error_return (0, "unknown input '%U'",
2183  format_unformat_error, line_input);
2184  goto done;
2185  }
2186  }
2187 
2188  unformat_free (line_input);
2189 
2190  rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
2191  is_add);
2192 
2193  if (rv)
2194  {
2195  error = clib_error_return (0, "snat_det_add_map return %d", rv);
2196  goto done;
2197  }
2198 
2199 done:
2200  unformat_free (line_input);
2201 
2202  return error;
2203 }
2204 
2205 /*?
2206  * @cliexpar
2207  * @cliexstart{snat deterministic add}
2208  * Create bijective mapping of inside address to outside address and port range
2209  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
2210  * CGN deployments.
2211  * To create deterministic mapping between inside network 10.0.0.0/18 and
2212  * outside network 1.1.1.0/30 use:
2213  * # vpp# snat deterministic add in 10.0.0.0/18 out 1.1.1.0/30
2214  * @cliexend
2215 ?*/
2216 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
2217  .path = "snat deterministic add",
2218  .short_help = "snat deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
2219  .function = snat_det_map_command_fn,
2220 };
2221 
2222 static clib_error_t *
2224  unformat_input_t * input,
2225  vlib_cli_command_t * cmd)
2226 {
2227  snat_main_t *sm = &snat_main;
2228  unformat_input_t _line_input, *line_input = &_line_input;
2229  ip4_address_t in_addr, out_addr;
2230  u16 lo_port;
2231  snat_det_map_t * dm;
2232  clib_error_t *error = 0;
2233 
2234  /* Get a line of input. */
2235  if (!unformat_user (input, unformat_line_input, line_input))
2236  return 0;
2237 
2238  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2239  {
2240  if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
2241  ;
2242  else
2243  {
2244  error = clib_error_return (0, "unknown input '%U'",
2245  format_unformat_error, line_input);
2246  goto done;
2247  }
2248  }
2249 
2250  unformat_free (line_input);
2251 
2252  dm = snat_det_map_by_user(sm, &in_addr);
2253  if (!dm)
2254  vlib_cli_output (vm, "no match");
2255  else
2256  {
2257  snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
2258  vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
2259  lo_port, lo_port + dm->ports_per_host - 1);
2260  }
2261 
2262 done:
2263  unformat_free (line_input);
2264 
2265  return error;
2266 }
2267 
2268 /*?
2269  * @cliexpar
2270  * @cliexstart{snat deterministic forward}
2271  * Return outside address and port range from inside address for deterministic
2272  * NAT.
2273  * To obtain outside address and port of inside host use:
2274  * vpp# snat deterministic forward 10.0.0.2
2275  * 1.1.1.0:<1054-1068>
2276  * @cliexend
2277 ?*/
2278 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
2279  .path = "snat deterministic forward",
2280  .short_help = "snat deterministic forward <addr>",
2281  .function = snat_det_forward_command_fn,
2282 };
2283 
2284 static clib_error_t *
2286  unformat_input_t * input,
2287  vlib_cli_command_t * cmd)
2288 {
2289  snat_main_t *sm = &snat_main;
2290  unformat_input_t _line_input, *line_input = &_line_input;
2291  ip4_address_t in_addr, out_addr;
2292  u32 out_port;
2293  snat_det_map_t * dm;
2294  clib_error_t *error = 0;
2295 
2296  /* Get a line of input. */
2297  if (!unformat_user (input, unformat_line_input, line_input))
2298  return 0;
2299 
2300  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2301  {
2302  if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
2303  ;
2304  else
2305  {
2306  error = clib_error_return (0, "unknown input '%U'",
2307  format_unformat_error, line_input);
2308  }
2309  }
2310 
2311  unformat_free (line_input);
2312 
2313  if (out_port < 1024 || out_port > 65535)
2314  {
2315  error = clib_error_return (0, "wrong port, must be <1024-65535>");
2316  goto done;
2317  }
2318 
2319  dm = snat_det_map_by_out(sm, &out_addr);
2320  if (!dm)
2321  vlib_cli_output (vm, "no match");
2322  else
2323  {
2324  snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
2325  vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
2326  }
2327 
2328 done:
2329  unformat_free (line_input);
2330 
2331  return error;
2332 }
2333 
2334 /*?
2335  * @cliexpar
2336  * @cliexstart{snat deterministic reverse}
2337  * Return inside address from outside address and port for deterministic NAT.
2338  * To obtain inside host address from outside address and port use:
2339  * #vpp snat deterministic reverse 1.1.1.1:1276
2340  * 10.0.16.16
2341  * @cliexend
2342 ?*/
2343 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
2344  .path = "snat deterministic reverse",
2345  .short_help = "snat deterministic reverse <addr>:<port>",
2346  .function = snat_det_reverse_command_fn,
2347 };
2348 
2349 static clib_error_t *
2351  unformat_input_t * input,
2352  vlib_cli_command_t * cmd)
2353 {
2354  snat_main_t *sm = &snat_main;
2355  unformat_input_t _line_input, *line_input = &_line_input;
2356  clib_error_t *error = 0;
2357 
2358  /* Get a line of input. */
2359  if (!unformat_user (input, unformat_line_input, line_input))
2360  return 0;
2361 
2362  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2363  {
2364  if (unformat (line_input, "udp %u", &sm->udp_timeout))
2365  ;
2366  else if (unformat (line_input, "tcp-established %u",
2367  &sm->tcp_established_timeout))
2368  ;
2369  else if (unformat (line_input, "tcp-transitory %u",
2370  &sm->tcp_transitory_timeout))
2371  ;
2372  else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
2373  ;
2374  else if (unformat (line_input, "reset"))
2375  {
2376  sm->udp_timeout = SNAT_UDP_TIMEOUT;
2377  sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
2378  sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
2379  sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
2380  }
2381  else
2382  {
2383  error = clib_error_return (0, "unknown input '%U'",
2384  format_unformat_error, line_input);
2385  goto done;
2386  }
2387  }
2388 
2389  unformat_free (line_input);
2390 
2391 done:
2392  unformat_free (line_input);
2393 
2394  return error;
2395 }
2396 
2397 /*?
2398  * @cliexpar
2399  * @cliexstart{set snat deterministic timeout}
2400  * Set values of timeouts for deterministic NAT (in seconds), use:
2401  * vpp# set snat deterministic timeout udp 120 tcp-established 7500
2402  * tcp-transitory 250 icmp 90
2403  * To reset default values use:
2404  * vpp# set snat deterministic timeout reset
2405  * @cliexend
2406 ?*/
2407 VLIB_CLI_COMMAND (set_timeout_command, static) = {
2408  .path = "set snat deterministic timeout",
2409  .function = set_timeout_command_fn,
2410  .short_help =
2411  "set snat deterministic timeout [udp <sec> | tcp-established <sec> "
2412  "tcp-transitory <sec> | icmp <sec> | reset]",
2413 };
2414 
2415 static clib_error_t *
2417  unformat_input_t * input,
2418  vlib_cli_command_t * cmd)
2419 {
2420  snat_main_t *sm = &snat_main;
2421  unformat_input_t _line_input, *line_input = &_line_input;
2422  ip4_address_t out_addr, ext_addr, in_addr;
2423  u16 out_port, ext_port;
2424  snat_det_map_t * dm;
2425  snat_det_session_t * ses;
2426  snat_det_out_key_t key;
2427  clib_error_t *error = 0;
2428 
2429  /* Get a line of input. */
2430  if (!unformat_user (input, unformat_line_input, line_input))
2431  return 0;
2432 
2433  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2434  {
2435  if (unformat (line_input, "%U:%d %U:%d",
2436  unformat_ip4_address, &out_addr, &out_port,
2437  unformat_ip4_address, &ext_addr, &ext_port))
2438  ;
2439  else
2440  {
2441  error = clib_error_return (0, "unknown input '%U'",
2442  format_unformat_error, line_input);
2443  goto done;
2444  }
2445  }
2446 
2447  unformat_free (line_input);
2448 
2449  dm = snat_det_map_by_out(sm, &out_addr);
2450  if (!dm)
2451  vlib_cli_output (vm, "no match");
2452  else
2453  {
2454  snat_det_reverse(dm, &ext_addr, out_port, &in_addr);
2455  key.ext_host_addr = out_addr;
2456  key.ext_host_port = ntohs(ext_port);
2457  key.out_port = ntohs(out_port);
2458  ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
2459  if (!ses)
2460  vlib_cli_output (vm, "no match");
2461  else
2462  snat_det_ses_close(dm, ses);
2463  }
2464 
2465 done:
2466  unformat_free (line_input);
2467 
2468  return error;
2469 }
2470 
2471 /*?
2472  * @cliexpar
2473  * @cliexstart{snat deterministic close session out}
2474  * Close session using outside ip address and port
2475  * and external ip address and port, use:
2476  * vpp# snat deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
2477  * @cliexend
2478 ?*/
2479 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
2480  .path = "snat deterministic close session out",
2481  .short_help = "snat deterministic close session out "
2482  "<out_addr>:<out_port> <ext_addr>:<ext_port>",
2483  .function = snat_det_close_session_out_fn,
2484 };
2485 
2486 static clib_error_t *
2488  unformat_input_t * input,
2489  vlib_cli_command_t * cmd)
2490 {
2491  snat_main_t *sm = &snat_main;
2492  unformat_input_t _line_input, *line_input = &_line_input;
2493  ip4_address_t in_addr, ext_addr;
2494  u16 in_port, ext_port;
2495  snat_det_map_t * dm;
2496  snat_det_session_t * ses;
2497  snat_det_out_key_t key;
2498  clib_error_t *error = 0;
2499 
2500  /* Get a line of input. */
2501  if (!unformat_user (input, unformat_line_input, line_input))
2502  return 0;
2503 
2504  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2505  {
2506  if (unformat (line_input, "%U:%d %U:%d",
2507  unformat_ip4_address, &in_addr, &in_port,
2508  unformat_ip4_address, &ext_addr, &ext_port))
2509  ;
2510  else
2511  {
2512  error = clib_error_return (0, "unknown input '%U'",
2513  format_unformat_error, line_input);
2514  goto done;
2515  }
2516  }
2517 
2518  unformat_free (line_input);
2519 
2520  dm = snat_det_map_by_user (sm, &in_addr);
2521  if (!dm)
2522  vlib_cli_output (vm, "no match");
2523  else
2524  {
2525  key.ext_host_addr = ext_addr;
2526  key.ext_host_port = ntohs (ext_port);
2527  ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key);
2528  if (!ses)
2529  vlib_cli_output (vm, "no match");
2530  else
2531  snat_det_ses_close(dm, ses);
2532  }
2533 
2534 done:
2535  unformat_free(line_input);
2536 
2537  return error;
2538 }
2539 
2540 /*?
2541  * @cliexpar
2542  * @cliexstart{snat deterministic close_session_in}
2543  * Close session using inside ip address and port
2544  * and external ip address and port, use:
2545  * vpp# snat deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
2546  * @cliexend
2547 ?*/
2548 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
2549  .path = "snat deterministic close session in",
2550  .short_help = "snat deterministic close session in "
2551  "<in_addr>:<in_port> <ext_addr>:<ext_port>",
2552  .function = snat_det_close_session_in_fn,
2553 };
ip4_address_t external_addr
Definition: snat.h:188
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
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, fib_protocol_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:754
u32 next
Definition: dlist.h:30
#define vec_foreach_index(var, v)
Iterate over vector indices.
u32 sessions_per_user_list_head_index
Definition: snat.h:152
void snat_add_address(snat_main_t *sm, ip4_address_t *addr, u32 vrf_id)
Definition: snat.c:128
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
u16 ext_host_port
Definition: snat.h:60
#define SNAT_UDP_TIMEOUT
Definition: snat.h:32
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:117
u8 * format_snat_session_state(u8 *s, va_list *args)
Definition: snat.c:1598
a
Definition: bitmap.h:516
ip4_address_t src_address
Definition: ip4_packet.h:164
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation.
Definition: in2out.c:569
u16 fib_index
Definition: snat.h:86
u32 nsessions
Definition: snat.h:153
int snat_alloc_outside_address_and_port(snat_main_t *sm, u32 fib_index, snat_session_key_t *k, u32 *address_indexp)
Definition: snat.c:891
#define NULL
Definition: clib.h:55
snat_protocol_t proto
Definition: snat.h:194
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:684
static void snat_det_reverse(snat_det_map_t *dm, ip4_address_t *out_addr, u16 out_port, ip4_address_t *in_addr)
Definition: snat_det.h:90
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1390
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
static snat_det_map_t * snat_det_map_by_out(snat_main_t *sm, ip4_address_t *out_addr)
Definition: snat_det.h:60
u32 nstaticsessions
Definition: snat.h:154
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
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
u8 * format_snat_static_map_to_resolve(u8 *s, va_list *args)
Definition: snat.c:1711
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
ip_lookup_main_t lookup_main
Definition: ip4.h:85
static void snat_det_forward(snat_det_map_t *dm, ip4_address_t *in_addr, ip4_address_t *out_addr, u16 *lo_port)
Definition: snat_det.h:75
void snat_ipfix_logging_init(vlib_main_t *vm)
Initialize SNAT IPFIX logging.
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
int snat_ipfix_logging_enable_disable(int enable, u32 domain_id, u16 src_port)
Enable/disable SNAT IPFIX logging.
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
static u32 snat_get_worker_in2out_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: snat.c:1387
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.
snat_main_t snat_main
Definition: snat.c:31
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
dlist_elt_t * list_pool
Definition: snat.h:221
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: snat.c:725
static clib_error_t * add_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:943
static clib_error_t * set_timeout_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2350
u8 * format_snat_key(u8 *s, va_list *args)
Definition: snat.c:1615
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:221
format_function_t format_ip4_address
Definition: format.h:79
void increment_v4_address(ip4_address_t *a)
Definition: snat.c:175
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: snat.c:184
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
unformat_function_t unformat_ip4_address
Definition: format.h:76
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:84
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u32 table_id
Definition: ip4_fib.h:51
ip4_address_t ext_host_addr
Definition: snat.h:59
ip4_address_t dst_address
Definition: ip4_packet.h:164
#define SNAT_ICMP_TIMEOUT
Definition: snat.h:37
int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del)
Definition: snat.c:2043
u8 * format_snat_user(u8 *s, va_list *args)
Definition: snat.c:1652
ip4_address_t addr
Definition: snat.h:150
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: snat.c:1974
A high priority source a plugin can use.
Definition: fib_entry.h:58
#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:160
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned long u64
Definition: types.h:89
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
static clib_error_t * snat_det_forward_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2223
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: snat.c:1326
u16 fp_len
The mask length.
Definition: fib_types.h:164
ip4_address_t local_addr
Definition: snat.h:187
uword unformat_snat_protocol(unformat_input_t *input, va_list *args)
Definition: snat.c:1112
snat_protocol_t proto
Definition: snat.h:208
unformat_function_t unformat_line_input
Definition: format.h:281
#define SNAT_TCP_TRANSITORY_TIMEOUT
Definition: snat.h:34
Definition: fib_entry.h:238
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:35
#define hash_get(h, key)
Definition: hash.h:248
format_function_t format_vnet_sw_interface_name
Definition: fib_entry.h:237
#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:397
deterministic NAT definitions
static uword clib_bitmap_last_set(uword *ai)
Return the higest numbered set bit in a bitmap.
Definition: bitmap.h:402
u64 key
the key
Definition: bihash_8_8.h:32
static u32 snat_get_worker_out2in_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: snat.c:1421
#define v
Definition: acl.c:320
struct _unformat_input_t unformat_input_t
static int is_snat_address_used_in_static_mapping(snat_main_t *sm, ip4_address_t addr)
Definition: snat.c:162
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:805
int snat_del_address(snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
Definition: snat.c:521
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:81
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)
Match SNAT static mapping.
Definition: snat.c:835
ip4_address_t addr
Definition: snat.h:84
static clib_error_t * snat_add_interface_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2101
u8 * format_snat_session(u8 *s, va_list *args)
Definition: snat.c:1634
#define SNAT_DET_SES_PER_USER
Definition: snat_det.h:30
VNET_FEATURE_INIT(ip4_snat_in2out, static)
u64 value
the value
Definition: bihash_8_8.h:33
snat_user_t * users
Definition: snat.h:215
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation and create session if needed...
Definition: in2out.c:477
api_main_t api_main
Definition: api_shared.c:35
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
static clib_error_t * show_snat_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1763
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:86
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static clib_error_t * add_static_mapping_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1144
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:835
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:70
static ip4_fib_t * ip4_fib_get(u32 index)
Get the FIB at the given index.
Definition: ip4_fib.h:105
u8 * format_snat_protocol(u8 *s, va_list *args)
Definition: snat.c:1126
#define clib_warning(format, args...)
Definition: error.h:59
int snat_set_workers(uword *bitmap)
Definition: snat.c:695
u32 sharing_ratio
Definition: snat.h:179
ip4_address_t out_addr
Definition: snat.h:177
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)
Add static mapping.
Definition: snat.c:223
static clib_error_t * snat_config(vlib_main_t *vm, unformat_input_t *input)
Definition: snat.c:1477
static u32 ip4_fib_index_from_table_id(u32 table_id)
Definition: ip4_fib.h:135
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:30
#define ARRAY_LEN(x)
Definition: clib.h:59
ip4_address_t addr
Definition: snat.h:45
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation and create session if needed...
Definition: out2in.c:1702
clib_error_t * snat_api_init(vlib_main_t *vm, snat_main_t *sm)
Definition: snat_api.c:1850
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
snat_protocol_t
Definition: snat.h:98
void snat_ipfix_logging_addresses_exhausted(u32 pool_id)
Generate NAT addresses exhausted event.
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:255
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static clib_error_t * snat_det_map_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2157
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:785
ip4_address_t l_addr
Definition: snat.h:203
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: snat.c:96
IPv4 main type.
Definition: ip4.h:83
u8 * format_snat_static_mapping(u8 *s, va_list *args)
Definition: snat.c:1692
u64 as_u64
Definition: snat.h:75
u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation and create session if needed...
Definition: in2out.c:2251
ip4_address_t addr
Definition: snat.h:72
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation and create session if needed...
Definition: out2in.c:288
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1041
ip4_address_t in_addr
Definition: snat.h:175
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
uword * thread_registrations_by_name
Definition: threads.h:261
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u8 * format_det_map_ses(u8 *s, va_list *args)
Definition: snat.c:1733
ip4_address_t addr
Definition: snat.h:158
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: snat_det.h:129
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: snat_det.h:112
#define VNET_FEATURES(...)
Definition: feature.h:368
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: snat_det.c:40
u32 value
Definition: dlist.h:32
u64 uword
Definition: types.h:112
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
Definition: in2out.c:90
clib_error_t * nat64_init(vlib_main_t *vm)
Initialize NAT64.
Definition: nat64.c:51
NAT64 global declarations.
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static snat_det_map_t * snat_det_map_by_user(snat_main_t *sm, ip4_address_t *user_addr)
Definition: snat_det.h:45
u16 ports_per_host
Definition: snat.h:180
Definition: fib_entry.h:234
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
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
snat_det_out_key_t out
Definition: snat.h:169
static clib_error_t * snat_det_close_session_out_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2416
u32 fib_index
Definition: snat.h:73
void snat_free_outside_address_and_port(snat_main_t *sm, snat_session_key_t *k, u32 address_index)
Definition: snat.c:794
#define hash_get_mem(h, key)
Definition: hash.h:268
static void snat_det_ses_close(snat_det_map_t *dm, snat_det_session_t *ses)
Definition: snat_det.h:179
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1168
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, 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 packet SNAT translation.
Definition: out2in.c:398
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define vec_foreach(var, vec)
Vector iterator.
VLIB_PLUGIN_REGISTER()
vhost_vring_addr_t addr
Definition: vhost-user.h:82
static clib_error_t * snat_det_close_session_in_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2487
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Definition: snat.c:621
static clib_error_t * snat_det_reverse_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:2285
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
snat_session_t * sessions
Definition: snat.h:218
static clib_error_t * snat_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1042
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: snat.h:375
static clib_error_t * set_workers_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1257
#define SNAT_TCP_ESTABLISHED_TIMEOUT
Definition: snat.h:35
u32 fib_index
Definition: snat.h:159
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
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:225
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109