FD.io VPP  v17.01.1-3-gc6833f8
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/plugin/plugin.h>
20 #include <vlibapi/api.h>
21 #include <snat/snat.h>
22 
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
25 #include <vlibsocket/api.h>
26 
28 
29 /* define message IDs */
30 #include <snat/snat_msg_enum.h>
31 
32 /* define message structures */
33 #define vl_typedefs
34 #include <snat/snat_all_api_h.h>
35 #undef vl_typedefs
36 
37 /* define generated endian-swappers */
38 #define vl_endianfun
39 #include <snat/snat_all_api_h.h>
40 #undef vl_endianfun
41 
42 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
43 
44 /* Get the API version number */
45 #define vl_api_version(n,v) static u32 api_version=(v);
46 #include <snat/snat_all_api_h.h>
47 #undef vl_api_version
48 
49 /* Macro to finish up custom dump fns */
50 #define FINISH \
51  vec_add1 (s, 0); \
52  vl_print (handle, (char *)s); \
53  vec_free (s); \
54  return handle;
55 
56 /*
57  * A handy macro to set up a message reply.
58  * Assumes that the following variables are available:
59  * mp - pointer to request message
60  * rmp - pointer to reply message type
61  * rv - return value
62  */
63 
64 #define REPLY_MACRO(t) \
65 do { \
66  unix_shared_memory_queue_t * q = \
67  vl_api_client_index_to_input_queue (mp->client_index); \
68  if (!q) \
69  return; \
70  \
71  rmp = vl_msg_api_alloc (sizeof (*rmp)); \
72  rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base); \
73  rmp->context = mp->context; \
74  rmp->retval = ntohl(rv); \
75  \
76  vl_msg_api_send_shmem (q, (u8 *)&rmp); \
77 } while(0);
78 
79 #define REPLY_MACRO2(t, body) \
80 do { \
81  unix_shared_memory_queue_t * q = \
82  vl_api_client_index_to_input_queue (mp->client_index); \
83  if (!q) \
84  return; \
85  \
86  rmp = vl_msg_api_alloc (sizeof (*rmp)); \
87  rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base); \
88  rmp->context = mp->context; \
89  rmp->retval = ntohl(rv); \
90  do {body;} while (0); \
91  vl_msg_api_send_shmem (q, (u8 *)&rmp); \
92 } while(0);
93 
94 
95 /* Hook up input features */
96 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
97  .arc_name = "ip4-unicast",
98  .node_name = "snat-in2out",
99  .runs_before = VNET_FEATURES ("snat-out2in"),
100 };
101 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
102  .arc_name = "ip4-unicast",
103  .node_name = "snat-out2in",
104  .runs_before = VNET_FEATURES ("ip4-lookup"),
105 };
106 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
107  .arc_name = "ip4-unicast",
108  .node_name = "snat-in2out-worker-handoff",
109  .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"),
110 };
111 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
112  .arc_name = "ip4-unicast",
113  .node_name = "snat-out2in-worker-handoff",
114  .runs_before = VNET_FEATURES ("ip4-lookup"),
115 };
116 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
117  .arc_name = "ip4-unicast",
118  .node_name = "snat-in2out-fast",
119  .runs_before = VNET_FEATURES ("snat-out2in-fast"),
120 };
121 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
122  .arc_name = "ip4-unicast",
123  .node_name = "snat-out2in-fast",
124  .runs_before = VNET_FEATURES ("ip4-lookup"),
125 };
126 
127 
128 /*
129  * This routine exists to convince the vlib plugin framework that
130  * we haven't accidentally copied a random .dll into the plugin directory.
131  *
132  * Also collects global variable pointers passed from the vpp engine
133  */
134 
135 clib_error_t *
137  int from_early_init)
138 {
139  snat_main_t * sm = &snat_main;
140  clib_error_t * error = 0;
141 
142  sm->vlib_main = vm;
143  sm->vnet_main = h->vnet_main;
144  sm->ethernet_main = h->ethernet_main;
145 
146  return error;
147 }
148 
149 /*$$$$$ move to an installed header file */
150 #if (1 || CLIB_DEBUG > 0) /* "trust, but verify" */
151 
152 #define VALIDATE_SW_IF_INDEX(mp) \
153  do { u32 __sw_if_index = ntohl(mp->sw_if_index); \
154  vnet_main_t *__vnm = vnet_get_main(); \
155  if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
156  __sw_if_index)) { \
157  rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
158  goto bad_sw_if_index; \
159  } \
160 } while(0);
161 
162 #define BAD_SW_IF_INDEX_LABEL \
163 do { \
164 bad_sw_if_index: \
165  ; \
166 } while (0);
167 
168 #define VALIDATE_RX_SW_IF_INDEX(mp) \
169  do { u32 __rx_sw_if_index = ntohl(mp->rx_sw_if_index); \
170  vnet_main_t *__vnm = vnet_get_main(); \
171  if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
172  __rx_sw_if_index)) { \
173  rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
174  goto bad_rx_sw_if_index; \
175  } \
176 } while(0);
177 
178 #define BAD_RX_SW_IF_INDEX_LABEL \
179 do { \
180 bad_rx_sw_if_index: \
181  ; \
182 } while (0);
183 
184 #define VALIDATE_TX_SW_IF_INDEX(mp) \
185  do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index); \
186  vnet_main_t *__vnm = vnet_get_main(); \
187  if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
188  __tx_sw_if_index)) { \
189  rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
190  goto bad_tx_sw_if_index; \
191  } \
192 } while(0);
193 
194 #define BAD_TX_SW_IF_INDEX_LABEL \
195 do { \
196 bad_tx_sw_if_index: \
197  ; \
198 } while (0);
199 
200 #else
201 
202 #define VALIDATE_SW_IF_INDEX(mp)
203 #define BAD_SW_IF_INDEX_LABEL
204 #define VALIDATE_RX_SW_IF_INDEX(mp)
205 #define BAD_RX_SW_IF_INDEX_LABEL
206 #define VALIDATE_TX_SW_IF_INDEX(mp)
207 #define BAD_TX_SW_IF_INDEX_LABEL
208 
209 #endif /* CLIB_DEBUG > 0 */
210 
212 {
213  snat_address_t * ap;
214 
215  /* Check if address already exists */
216  vec_foreach (ap, sm->addresses)
217  {
218  if (ap->addr.as_u32 == addr->as_u32)
219  return;
220  }
221 
222  vec_add2 (sm->addresses, ap, 1);
223  ap->addr = *addr;
224  clib_bitmap_alloc (ap->busy_port_bitmap, 65535);
225 }
226 
229 {
232  ({
233  if (m->external_addr.as_u32 == addr.as_u32)
234  return 1;
235  }));
236 
237  return 0;
238 }
239 
241 {
242  snat_address_t *a = 0;
243  snat_session_t *ses;
244  u32 *ses_to_be_removed = 0, *ses_index;
245  clib_bihash_kv_8_8_t kv, value;
246  snat_user_key_t user_key;
247  snat_user_t *u;
249 
250  int i;
251 
252  /* Find SNAT address */
253  for (i=0; i < vec_len (sm->addresses); i++)
254  {
255  if (sm->addresses[i].addr.as_u32 == addr.as_u32)
256  {
257  a = sm->addresses + i;
258  break;
259  }
260  }
261  if (!a)
262  return VNET_API_ERROR_NO_SUCH_ENTRY;
263 
264  /* Check if address is used in some static mapping */
266  {
267  clib_warning ("address used in static mapping");
268  return VNET_API_ERROR_UNSPECIFIED;
269  }
270 
271  /* Delete sessions using address */
272  if (a->busy_ports)
273  {
274  vec_foreach (tsm, sm->per_thread_data)
275  {
276  pool_foreach (ses, tsm->sessions, ({
277  if (ses->out2in.addr.as_u32 == addr.as_u32)
278  {
279  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
280  kv.key = ses->in2out.as_u64;
281  clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
282  kv.key = ses->out2in.as_u64;
283  clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
284  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
285  user_key.addr = ses->in2out.addr;
286  user_key.fib_index = ses->in2out.fib_index;
287  kv.key = user_key.as_u64;
288  if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
289  {
290  u = pool_elt_at_index (tsm->users, value.value);
291  u->nsessions--;
292  }
293  }
294  }));
295 
296  vec_foreach (ses_index, ses_to_be_removed)
297  pool_put_index (tsm->sessions, ses_index[0]);
298 
299  vec_free (ses_to_be_removed);
300  }
301  }
302 
303  vec_del1 (sm->addresses, i);
304 
305  return 0;
306 }
307 
309 {
310  u32 v;
311 
312  v = clib_net_to_host_u32(a->as_u32) + 1;
313  a->as_u32 = clib_host_to_net_u32(v);
314 }
315 
316 /**
317  * @brief Add static mapping.
318  *
319  * Create static mapping between local addr+port and external addr+port.
320  *
321  * @param l_addr Local IPv4 address.
322  * @param e_addr External IPv4 address.
323  * @param l_port Local port number.
324  * @param e_port External port number.
325  * @param vrf_id VRF ID.
326  * @param addr_only If 0 address port and pair mapping, otherwise address only.
327  * @param is_add If 0 delete static mapping, otherwise add.
328  *
329  * @returns
330  */
332  u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
333  int is_add)
334 {
335  snat_main_t * sm = &snat_main;
338  clib_bihash_kv_8_8_t kv, value;
339  snat_address_t *a = 0;
340  u32 fib_index = ~0;
341  uword * p;
342  int i;
343 
344  /* If outside FIB index is not resolved yet */
345  if (sm->outside_fib_index == ~0)
346  {
348  if (!p)
349  return VNET_API_ERROR_NO_SUCH_FIB;
350  sm->outside_fib_index = p[0];
351  }
352 
353  m_key.addr = e_addr;
354  m_key.port = addr_only ? 0 : e_port;
355  m_key.fib_index = sm->outside_fib_index;
356  kv.key = m_key.as_u64;
357  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
358  m = 0;
359  else
360  m = pool_elt_at_index (sm->static_mappings, value.value);
361 
362  if (is_add)
363  {
364  if (m)
365  return VNET_API_ERROR_VALUE_EXIST;
366 
367  /* Convert VRF id to FIB index */
368  if (vrf_id != ~0)
369  {
370  p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
371  if (!p)
372  return VNET_API_ERROR_NO_SUCH_FIB;
373  fib_index = p[0];
374  }
375  /* If not specified use inside VRF id from SNAT plugin startup config */
376  else
377  {
378  if (sm->inside_fib_index == ~0)
379  {
381  if (!p)
382  return VNET_API_ERROR_NO_SUCH_FIB;
383  fib_index = p[0];
384  sm->inside_fib_index = fib_index;
385  }
386  else
387  fib_index = sm->inside_fib_index;
388 
389  vrf_id = sm->inside_vrf_id;
390  }
391 
392  /* Find external address in allocated addresses and reserve port for
393  address and port pair mapping when dynamic translations enabled */
394  if (!addr_only && !(sm->static_mapping_only))
395  {
396  for (i = 0; i < vec_len (sm->addresses); i++)
397  {
398  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
399  {
400  a = sm->addresses + i;
401  /* External port must be unused */
403  return VNET_API_ERROR_INVALID_VALUE;
405  if (e_port > 1024)
406  a->busy_ports++;
407 
408  break;
409  }
410  }
411  /* External address must be allocated */
412  if (!a)
413  return VNET_API_ERROR_NO_SUCH_ENTRY;
414  }
415 
416  pool_get (sm->static_mappings, m);
417  memset (m, 0, sizeof (*m));
418  m->local_addr = l_addr;
419  m->external_addr = e_addr;
420  m->addr_only = addr_only;
421  m->vrf_id = vrf_id;
422  m->fib_index = fib_index;
423  if (!addr_only)
424  {
425  m->local_port = l_port;
426  m->external_port = e_port;
427  }
428 
429  m_key.addr = m->local_addr;
430  m_key.port = m->local_port;
431  m_key.fib_index = m->fib_index;
432  kv.key = m_key.as_u64;
433  kv.value = m - sm->static_mappings;
434  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
435 
436  m_key.addr = m->external_addr;
437  m_key.port = m->external_port;
438  m_key.fib_index = sm->outside_fib_index;
439  kv.key = m_key.as_u64;
440  kv.value = m - sm->static_mappings;
441  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
442 
443  /* Assign worker */
444  if (sm->workers)
445  {
446  snat_user_key_t w_key0;
448 
449  w_key0.addr = m->local_addr;
450  w_key0.fib_index = m->fib_index;
451  kv.key = w_key0.as_u64;
452 
453  if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
454  {
455  kv.value = sm->first_worker_index +
456  sm->workers[sm->next_worker++ % vec_len (sm->workers)];
457 
458  clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
459  }
460  else
461  {
462  kv.value = value.value;
463  }
464 
465  w_key1.addr = m->external_addr;
466  w_key1.port = clib_host_to_net_u16 (m->external_port);
467  w_key1.fib_index = sm->outside_fib_index;
468  kv.key = w_key1.as_u64;
469  clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1);
470  }
471  }
472  else
473  {
474  if (!m)
475  return VNET_API_ERROR_NO_SUCH_ENTRY;
476 
477  /* Free external address port */
478  if (!addr_only && !(sm->static_mapping_only))
479  {
480  for (i = 0; i < vec_len (sm->addresses); i++)
481  {
482  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
483  {
484  a = sm->addresses + i;
486  a->busy_ports--;
487 
488  break;
489  }
490  }
491  }
492 
493  m_key.addr = m->local_addr;
494  m_key.port = m->local_port;
495  m_key.fib_index = m->fib_index;
496  kv.key = m_key.as_u64;
497  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
498 
499  m_key.addr = m->external_addr;
500  m_key.port = m->external_port;
501  m_key.fib_index = sm->outside_fib_index;
502  kv.key = m_key.as_u64;
503  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
504 
505  /* Delete session(s) for static mapping if exist */
506  if (!(sm->static_mapping_only) ||
508  {
509  snat_user_key_t u_key;
510  snat_user_t *u;
511  dlist_elt_t * head, * elt;
512  u32 elt_index, head_index, del_elt_index;
513  u32 ses_index;
514  u64 user_index;
515  snat_session_t * s;
517 
518  u_key.addr = m->local_addr;
519  u_key.fib_index = m->fib_index;
520  kv.key = u_key.as_u64;
521  if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
522  {
523  user_index = value.value;
524  if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
525  tsm = vec_elt_at_index (sm->per_thread_data, value.value);
526  else
528  u = pool_elt_at_index (tsm->users, user_index);
529  if (u->nstaticsessions)
530  {
531  head_index = u->sessions_per_user_list_head_index;
532  head = pool_elt_at_index (tsm->list_pool, head_index);
533  elt_index = head->next;
534  elt = pool_elt_at_index (tsm->list_pool, elt_index);
535  ses_index = elt->value;
536  while (ses_index != ~0)
537  {
538  s = pool_elt_at_index (tsm->sessions, ses_index);
539  del_elt_index = elt_index;
540  elt_index = elt->next;
541  elt = pool_elt_at_index (tsm->list_pool, elt_index);
542  ses_index = elt->value;
543 
544  if (!addr_only)
545  {
546  if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
547  (clib_net_to_host_u16 (s->out2in.port) != e_port))
548  continue;
549  }
550 
551  value.key = s->in2out.as_u64;
552  clib_bihash_add_del_8_8 (&sm->in2out, &value, 0);
553  value.key = s->out2in.as_u64;
554  clib_bihash_add_del_8_8 (&sm->out2in, &value, 0);
555  pool_put (tsm->sessions, s);
556 
557  clib_dlist_remove (tsm->list_pool, del_elt_index);
558  pool_put_index (tsm->list_pool, del_elt_index);
559  u->nstaticsessions--;
560 
561  if (!addr_only)
562  break;
563  }
564  if (addr_only)
565  {
566  pool_put (tsm->users, u);
567  clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
568  }
569  }
570  }
571  }
572 
573  /* Delete static mapping from pool */
574  pool_put (sm->static_mappings, m);
575  }
576 
577  return 0;
578 }
579 
580 static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
581 {
582  snat_main_t *sm = &snat_main;
584  const char * feature_name;
585 
587  feature_name = is_inside ? "snat-in2out-fast" : "snat-out2in-fast";
588  else
589  {
590  if (sm->num_workers > 1)
591  feature_name = is_inside ? "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff";
592  else
593  feature_name = is_inside ? "snat-in2out" : "snat-out2in";
594  }
595 
596  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
597  !is_del, 0, 0);
598 
599  if (sm->fq_in2out_index == ~0)
601 
602  if (sm->fq_out2in_index == ~0)
604 
605  pool_foreach (i, sm->interfaces,
606  ({
607  if (i->sw_if_index == sw_if_index)
608  {
609  if (is_del)
610  pool_put (sm->interfaces, i);
611  else
612  return VNET_API_ERROR_VALUE_EXIST;
613 
614  return 0;
615  }
616  }));
617 
618  if (is_del)
619  return VNET_API_ERROR_NO_SUCH_ENTRY;
620 
621  pool_get (sm->interfaces, i);
622  i->sw_if_index = sw_if_index;
623  i->is_inside = is_inside;
624 
625  return 0;
626 }
627 
628 static int snat_set_workers (uword * bitmap)
629 {
630  snat_main_t *sm = &snat_main;
631  int i;
632 
633  if (sm->num_workers < 2)
634  return VNET_API_ERROR_FEATURE_DISABLED;
635 
636  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
637  return VNET_API_ERROR_INVALID_WORKER;
638 
639  vec_free (sm->workers);
640  clib_bitmap_foreach (i, bitmap,
641  ({
642  vec_add1(sm->workers, i);
643  }));
644 
645  return 0;
646 }
647 
648 static void
651 {
652  snat_main_t * sm = &snat_main;
654  ip4_address_t this_addr;
655  u32 start_host_order, end_host_order;
656  int i, count;
657  int rv = 0;
658  u32 * tmp;
659 
660  if (mp->is_ip4 != 1)
661  {
662  rv = VNET_API_ERROR_UNIMPLEMENTED;
663  goto send_reply;
664  }
665 
666  if (sm->static_mapping_only)
667  {
668  rv = VNET_API_ERROR_FEATURE_DISABLED;
669  goto send_reply;
670  }
671 
672  tmp = (u32 *) mp->first_ip_address;
673  start_host_order = clib_host_to_net_u32 (tmp[0]);
674  tmp = (u32 *) mp->last_ip_address;
675  end_host_order = clib_host_to_net_u32 (tmp[0]);
676 
677  count = (end_host_order - start_host_order) + 1;
678 
679  if (count > 1024)
680  clib_warning ("%U - %U, %d addresses...",
683  count);
684 
685  memcpy (&this_addr.as_u8, mp->first_ip_address, 4);
686 
687  for (i = 0; i < count; i++)
688  {
689  if (mp->is_add)
690  snat_add_address (sm, &this_addr);
691  else
692  rv = snat_del_address (sm, this_addr);
693 
694  if (rv)
695  goto send_reply;
696 
697  increment_v4_address (&this_addr);
698  }
699 
700  send_reply:
701  REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
702 }
703 
706 {
707  u8 * s;
708 
709  s = format (0, "SCRIPT: snat_add_address_range ");
710  s = format (s, "%U ", format_ip4_address, mp->first_ip_address);
711  if (memcmp (mp->first_ip_address, mp->last_ip_address, 4))
712  {
713  s = format (s, " - %U ", format_ip4_address, mp->last_ip_address);
714  }
715  FINISH;
716 }
717 
718 static void
721 {
723  snat_main_t * sm = &snat_main;
724 
725  rmp = vl_msg_api_alloc (sizeof (*rmp));
726  memset (rmp, 0, sizeof (*rmp));
727  rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base);
728  rmp->is_ip4 = 1;
729  clib_memcpy (rmp->ip_address, &(a->addr), 4);
730  rmp->context = context;
731 
732  vl_msg_api_send_shmem (q, (u8 *) & rmp);
733 }
734 
735 static void
738 {
740  snat_main_t * sm = &snat_main;
741  snat_address_t * a;
742 
744  if (q == 0)
745  return;
746 
747  vec_foreach (a, sm->addresses)
749 }
750 
752 (vl_api_snat_address_dump_t *mp, void * handle)
753 {
754  u8 *s;
755 
756  s = format (0, "SCRIPT: snat_address_dump ");
757 
758  FINISH;
759 }
760 
761 static void
764 {
765  snat_main_t * sm = &snat_main;
767  u8 is_del = mp->is_add == 0;
768  u32 sw_if_index = ntohl(mp->sw_if_index);
769  int rv = 0;
770 
772 
773  rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del);
774 
776 
777  REPLY_MACRO(VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY);
778 }
779 
782 {
783  u8 * s;
784 
785  s = format (0, "SCRIPT: snat_interface_add_del_feature ");
786  s = format (s, "sw_if_index %d %s %s",
787  clib_host_to_net_u32(mp->sw_if_index),
788  mp->is_inside ? "in":"out",
789  mp->is_add ? "" : "del");
790 
791  FINISH;
792 }
793 
794 static void
797 {
799  snat_main_t * sm = &snat_main;
800 
801  rmp = vl_msg_api_alloc (sizeof (*rmp));
802  memset (rmp, 0, sizeof (*rmp));
803  rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_DETAILS+sm->msg_id_base);
804  rmp->sw_if_index = ntohl (i->sw_if_index);
805  rmp->is_inside = i->is_inside;
806  rmp->context = context;
807 
808  vl_msg_api_send_shmem (q, (u8 *) & rmp);
809 }
810 
811 static void
814 {
816  snat_main_t * sm = &snat_main;
818 
820  if (q == 0)
821  return;
822 
823  pool_foreach (i, sm->interfaces,
824  ({
825  send_snat_interface_details(i, q, mp->context);
826  }));
827 }
828 
830 (vl_api_snat_interface_dump_t *mp, void * handle)
831 {
832  u8 *s;
833 
834  s = format (0, "SCRIPT: snat_interface_dump ");
835 
836  FINISH;
837 }static void
838 
841 {
842  snat_main_t * sm = &snat_main;
844  ip4_address_t local_addr, external_addr;
845  u16 local_port = 0, external_port = 0;
846  u32 vrf_id;
847  int rv = 0;
848 
849  if (mp->is_ip4 != 1)
850  {
851  rv = VNET_API_ERROR_UNIMPLEMENTED;
852  goto send_reply;
853  }
854 
855  memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
856  memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
857  if (mp->addr_only == 0)
858  {
859  local_port = clib_net_to_host_u16 (mp->local_port);
860  external_port = clib_net_to_host_u16 (mp->external_port);
861  }
862  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
863 
864  rv = snat_add_static_mapping(local_addr, external_addr, local_port,
865  external_port, vrf_id, mp->addr_only,
866  mp->is_add);
867 
868  send_reply:
869  REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
870 }
871 
874 {
875  u8 * s;
876 
877  s = format (0, "SCRIPT: snat_add_static_mapping ");
878  s = format (s, "local_addr %U external_addr %U ",
881 
882  if (mp->addr_only == 0)
883  s = format (s, "local_port %d external_port %d ",
884  clib_net_to_host_u16 (mp->local_port),
885  clib_net_to_host_u16 (mp->external_port));
886 
887  if (mp->vrf_id != ~0)
888  s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
889 
890  FINISH;
891 }
892 
893 static void
896 {
898  snat_main_t * sm = &snat_main;
899 
900  rmp = vl_msg_api_alloc (sizeof (*rmp));
901  memset (rmp, 0, sizeof (*rmp));
902  rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base);
903  rmp->is_ip4 = 1;
904  rmp->addr_only = m->addr_only;
905  clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4);
907  rmp->local_port = htons (m->local_port);
908  rmp->external_port = htons (m->external_port);
909  rmp->vrf_id = htonl (m->vrf_id);
910  rmp->context = context;
911 
912  vl_msg_api_send_shmem (q, (u8 *) & rmp);
913 }
914 
915 static void
918 {
920  snat_main_t * sm = &snat_main;
922 
924  if (q == 0)
925  return;
926 
928  ({
929  send_snat_static_mapping_details (m, q, mp->context);
930  }));
931 }
932 
935 {
936  u8 *s;
937 
938  s = format (0, "SCRIPT: snat_static_mapping_dump ");
939 
940  FINISH;
941 }
942 
943 static void
946 {
948  snat_main_t * sm = &snat_main;
949  int rv = 0;
950 
951  REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY,
952  ({
953  rmp->vpe_pid = ntohl (getpid());
954  }));
955 }
956 
958 (vl_api_snat_control_ping_t *mp, void * handle)
959 {
960  u8 *s;
961 
962  s = format (0, "SCRIPT: snat_control_ping ");
963 
964  FINISH;
965 }
966 
967 static void
970 {
972  snat_main_t * sm = &snat_main;
973  int rv = 0;
974 
975  REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY,
976  ({
977  rmp->translation_buckets = htonl (sm->translation_buckets);
979  rmp->user_buckets = htonl (sm->user_buckets);
980  rmp->user_memory_size = htonl (sm->user_memory_size);
982  rmp->outside_vrf_id = htonl (sm->outside_vrf_id);
983  rmp->inside_vrf_id = htonl (sm->inside_vrf_id);
987  }));
988 }
989 
991 (vl_api_snat_show_config_t *mp, void * handle)
992 {
993  u8 *s;
994 
995  s = format (0, "SCRIPT: snat_show_config ");
996 
997  FINISH;
998 }
999 
1000 static void
1003 {
1004  snat_main_t * sm = &snat_main;
1006  int rv = 0;
1007  uword *bitmap = 0;
1008  u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1009 
1010  if (sm->num_workers < 2)
1011  {
1012  rv = VNET_API_ERROR_FEATURE_DISABLED;
1013  goto send_reply;
1014  }
1015 
1016  bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask));
1017  rv = snat_set_workers(bitmap);
1018  clib_bitmap_free (bitmap);
1019 
1020  send_reply:
1021  REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY);
1022 }
1023 
1025 (vl_api_snat_set_workers_t *mp, void * handle)
1026 {
1027  u8 * s;
1028  uword *bitmap = 0;
1029  u8 first = 1;
1030  int i;
1031  u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1032 
1033  s = format (0, "SCRIPT: snat_set_workers ");
1034  bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask));
1035  clib_bitmap_foreach (i, bitmap,
1036  ({
1037  if (first)
1038  s = format (s, "%d", i);
1039  else
1040  s = format (s, ",%d", i);
1041  first = 0;
1042  }));
1043  clib_bitmap_free (bitmap);
1044  FINISH;
1045 }
1046 
1047 static void
1049 (u32 worker_index, unix_shared_memory_queue_t * q, u32 context)
1050 {
1052  snat_main_t * sm = &snat_main;
1054  vlib_worker_threads + worker_index + sm->first_worker_index;
1055 
1056  rmp = vl_msg_api_alloc (sizeof (*rmp));
1057  memset (rmp, 0, sizeof (*rmp));
1058  rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base);
1059  rmp->context = context;
1060  rmp->worker_index = htonl (worker_index);
1061  rmp->lcore_id = htonl (w->lcore_id);
1062  strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
1063 
1064  vl_msg_api_send_shmem (q, (u8 *) & rmp);
1065 }
1066 
1067 static void
1070 {
1072  snat_main_t * sm = &snat_main;
1073  u32 * worker_index;
1074 
1076  if (q == 0)
1077  return;
1078 
1079  vec_foreach (worker_index, sm->workers)
1080  {
1081  send_snat_worker_details(*worker_index, q, mp->context);
1082  }
1083 }
1084 
1086 (vl_api_snat_worker_dump_t *mp, void * handle)
1087 {
1088  u8 *s;
1089 
1090  s = format (0, "SCRIPT: snat_worker_dump ");
1091 
1092  FINISH;
1093 }
1094 
1095 /* List of message types that this plugin understands */
1096 #define foreach_snat_plugin_api_msg \
1097 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \
1098 _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature) \
1099 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping) \
1100 _(SNAT_CONTROL_PING, snat_control_ping) \
1101 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump) \
1102 _(SNAT_SHOW_CONFIG, snat_show_config) \
1103 _(SNAT_ADDRESS_DUMP, snat_address_dump) \
1104 _(SNAT_INTERFACE_DUMP, snat_interface_dump) \
1105 _(SNAT_SET_WORKERS, snat_set_workers) \
1106 _(SNAT_WORKER_DUMP, snat_worker_dump)
1107 
1108 /* Set up the API message handling tables */
1109 static clib_error_t *
1111 {
1112  snat_main_t * sm __attribute__ ((unused)) = &snat_main;
1113 #define _(N,n) \
1114  vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \
1115  #n, \
1116  vl_api_##n##_t_handler, \
1117  vl_noop_handler, \
1118  vl_api_##n##_t_endian, \
1119  vl_api_##n##_t_print, \
1120  sizeof(vl_api_##n##_t), 1);
1122 #undef _
1123 
1124  return 0;
1125 }
1126 
1127 #define vl_msg_name_crc_list
1128 #include <snat/snat_all_api_h.h>
1129 #undef vl_msg_name_crc_list
1130 
1131 static void
1133 {
1134 #define _(id,n,crc) \
1135  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1136  foreach_vl_msg_name_crc_snat;
1137 #undef _
1138 }
1139 
1141 {
1142 #define _(n,f) sm->api_main->msg_print_handlers \
1143  [VL_API_##n + sm->msg_id_base] \
1144  = (void *) vl_api_##f##_t_print;
1146 #undef _
1147 }
1148 
1150 {
1151  snat_main_t * sm = &snat_main;
1152  clib_error_t * error = 0;
1153  ip4_main_t * im = &ip4_main;
1154  ip_lookup_main_t * lm = &im->lookup_main;
1155  u8 * name;
1156  uword *p;
1159  uword *bitmap = 0;
1160  u32 i;
1161 
1162  name = format (0, "snat_%08x%c", api_version, 0);
1163 
1164  /* Ask for a correctly-sized block of API message decode slots */
1166  ((char *) name, VL_MSG_FIRST_AVAILABLE);
1167 
1168  sm->vlib_main = vm;
1169  sm->vnet_main = vnet_get_main();
1170  sm->ip4_main = im;
1171  sm->ip4_lookup_main = lm;
1172  sm->api_main = &api_main;
1173  sm->first_worker_index = 0;
1174  sm->next_worker = 0;
1175  sm->num_workers = 0;
1176  sm->workers = 0;
1177  sm->fq_in2out_index = ~0;
1178  sm->fq_out2in_index = ~0;
1179 
1180  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1181  if (p)
1182  {
1183  tr = (vlib_thread_registration_t *) p[0];
1184  if (tr)
1185  {
1186  sm->num_workers = tr->count;
1187  sm->first_worker_index = tr->first_index;
1188  }
1189  }
1190 
1191  /* Use all available workers by default */
1192  if (sm->num_workers > 1)
1193  {
1194  for (i=0; i < sm->num_workers; i++)
1195  bitmap = clib_bitmap_set (bitmap, i, 1);
1196  snat_set_workers(bitmap);
1197  clib_bitmap_free (bitmap);
1198  }
1199 
1200  error = snat_plugin_api_hookup (vm);
1201 
1202  /* Add our API messages to the global name_crc hash table */
1204 
1206  vec_free(name);
1207 
1208  return error;
1209 }
1210 
1212 
1214  snat_session_key_t * k,
1215  u32 address_index)
1216 {
1217  snat_address_t *a;
1218  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1219 
1220  ASSERT (address_index < vec_len (sm->addresses));
1221 
1222  a = sm->addresses + address_index;
1223 
1225  port_host_byte_order) == 1);
1226 
1227  clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0);
1228  a->busy_ports--;
1229 }
1230 
1231 /**
1232  * @brief Match SNAT static mapping.
1233  *
1234  * @param sm SNAT main.
1235  * @param match Address and port to match.
1236  * @param mapping External or local address and port of the matched mapping.
1237  * @param by_external If 0 match by local address otherwise match by external
1238  * address.
1239  *
1240  * @returns 0 if match found otherwise 1.
1241  */
1243  snat_session_key_t match,
1244  snat_session_key_t * mapping,
1245  u8 by_external)
1246 {
1247  clib_bihash_kv_8_8_t kv, value;
1250  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1251 
1252  if (by_external)
1253  mapping_hash = &sm->static_mapping_by_external;
1254 
1255  m_key.addr = match.addr;
1256  m_key.port = clib_net_to_host_u16 (match.port);
1257  m_key.fib_index = match.fib_index;
1258 
1259  kv.key = m_key.as_u64;
1260 
1261  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1262  {
1263  /* Try address only mapping */
1264  m_key.port = 0;
1265  kv.key = m_key.as_u64;
1266  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1267  return 1;
1268  }
1269 
1270  m = pool_elt_at_index (sm->static_mappings, value.value);
1271 
1272  if (by_external)
1273  {
1274  mapping->addr = m->local_addr;
1275  /* Address only mapping doesn't change port */
1276  mapping->port = m->addr_only ? match.port
1277  : clib_host_to_net_u16 (m->local_port);
1278  mapping->fib_index = m->fib_index;
1279  }
1280  else
1281  {
1282  mapping->addr = m->external_addr;
1283  /* Address only mapping doesn't change port */
1284  mapping->port = m->addr_only ? match.port
1285  : clib_host_to_net_u16 (m->external_port);
1286  mapping->fib_index = sm->outside_fib_index;
1287  }
1288 
1289  return 0;
1290 }
1291 
1293  snat_session_key_t * k,
1294  u32 * address_indexp)
1295 {
1296  int i;
1297  snat_address_t *a;
1298  u32 portnum;
1299 
1300  for (i = 0; i < vec_len (sm->addresses); i++)
1301  {
1302  if (sm->addresses[i].busy_ports < (65535-1024))
1303  {
1304  a = sm->addresses + i;
1305 
1306  while (1)
1307  {
1308  portnum = random_u32 (&sm->random_seed);
1309  portnum &= 0xFFFF;
1310  if (portnum < 1024)
1311  continue;
1312  if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum))
1313  continue;
1314  clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1);
1315  a->busy_ports++;
1316  /* Caller sets protocol and fib index */
1317  k->addr = a->addr;
1318  k->port = clib_host_to_net_u16(portnum);
1319  *address_indexp = i;
1320  return 0;
1321  }
1322  }
1323  }
1324  /* Totally out of translations to use... */
1325  return 1;
1326 }
1327 
1328 
1329 static clib_error_t *
1331  unformat_input_t * input,
1332  vlib_cli_command_t * cmd)
1333 {
1334  unformat_input_t _line_input, *line_input = &_line_input;
1335  snat_main_t * sm = &snat_main;
1336  ip4_address_t start_addr, end_addr, this_addr;
1337  u32 start_host_order, end_host_order;
1338  int i, count;
1339  int is_add = 1;
1340  int rv = 0;
1341 
1342  /* Get a line of input. */
1343  if (!unformat_user (input, unformat_line_input, line_input))
1344  return 0;
1345 
1346  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1347  {
1348  if (unformat (line_input, "%U - %U",
1349  unformat_ip4_address, &start_addr,
1350  unformat_ip4_address, &end_addr))
1351  ;
1352  else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1353  end_addr = start_addr;
1354  else if (unformat (line_input, "del"))
1355  is_add = 0;
1356  else
1357  return clib_error_return (0, "unknown input '%U'",
1358  format_unformat_error, input);
1359  }
1360  unformat_free (line_input);
1361 
1362  if (sm->static_mapping_only)
1363  return clib_error_return (0, "static mapping only mode");
1364 
1365  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1366  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1367 
1368  if (end_host_order < start_host_order)
1369  return clib_error_return (0, "end address less than start address");
1370 
1371  count = (end_host_order - start_host_order) + 1;
1372 
1373  if (count > 1024)
1374  clib_warning ("%U - %U, %d addresses...",
1375  format_ip4_address, &start_addr,
1376  format_ip4_address, &end_addr,
1377  count);
1378 
1379  this_addr = start_addr;
1380 
1381  for (i = 0; i < count; i++)
1382  {
1383  if (is_add)
1384  snat_add_address (sm, &this_addr);
1385  else
1386  rv = snat_del_address (sm, this_addr);
1387 
1388  switch (rv)
1389  {
1390  case VNET_API_ERROR_NO_SUCH_ENTRY:
1391  return clib_error_return (0, "S-NAT address not exist.");
1392  break;
1393  case VNET_API_ERROR_UNSPECIFIED:
1394  return clib_error_return (0, "S-NAT address used in static mapping.");
1395  break;
1396  default:
1397  break;
1398  }
1399 
1400  increment_v4_address (&this_addr);
1401  }
1402 
1403  return 0;
1404 }
1405 
1407  .path = "snat add address",
1408  .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
1409  .function = add_address_command_fn,
1410 };
1411 
1412 static clib_error_t *
1414  unformat_input_t * input,
1415  vlib_cli_command_t * cmd)
1416 {
1417  unformat_input_t _line_input, *line_input = &_line_input;
1418  vnet_main_t * vnm = vnet_get_main();
1419  clib_error_t * error = 0;
1420  u32 sw_if_index;
1421  u32 * inside_sw_if_indices = 0;
1422  u32 * outside_sw_if_indices = 0;
1423  int is_del = 0;
1424  int i;
1425 
1426  sw_if_index = ~0;
1427 
1428  /* Get a line of input. */
1429  if (!unformat_user (input, unformat_line_input, line_input))
1430  return 0;
1431 
1432  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1433  {
1434  if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1435  vnm, &sw_if_index))
1436  vec_add1 (inside_sw_if_indices, sw_if_index);
1437  else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1438  vnm, &sw_if_index))
1439  vec_add1 (outside_sw_if_indices, sw_if_index);
1440  else if (unformat (line_input, "del"))
1441  is_del = 1;
1442  else
1443  return clib_error_return (0, "unknown input '%U'",
1444  format_unformat_error, input);
1445  }
1446  unformat_free (line_input);
1447 
1448  if (vec_len (inside_sw_if_indices))
1449  {
1450  for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1451  {
1452  sw_if_index = inside_sw_if_indices[i];
1453  snat_interface_add_del (sw_if_index, 1, is_del);
1454  }
1455  }
1456 
1457  if (vec_len (outside_sw_if_indices))
1458  {
1459  for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1460  {
1461  sw_if_index = outside_sw_if_indices[i];
1462  snat_interface_add_del (sw_if_index, 0, is_del);
1463  }
1464  }
1465 
1466  vec_free (inside_sw_if_indices);
1467  vec_free (outside_sw_if_indices);
1468 
1469  return error;
1470 }
1471 
1473  .path = "set interface snat",
1474  .function = snat_feature_command_fn,
1475  .short_help = "set interface snat in <intfc> out <intfc> [del]",
1476 };
1477 
1478 static clib_error_t *
1480  unformat_input_t * input,
1481  vlib_cli_command_t * cmd)
1482 {
1483  unformat_input_t _line_input, *line_input = &_line_input;
1484  clib_error_t * error = 0;
1485  ip4_address_t l_addr, e_addr;
1486  u32 l_port = 0, e_port = 0, vrf_id = ~0;
1487  int is_add = 1;
1488  int addr_only = 1;
1489  int rv;
1490 
1491  /* Get a line of input. */
1492  if (!unformat_user (input, unformat_line_input, line_input))
1493  return 0;
1494 
1495  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1496  {
1497  if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1498  &l_port))
1499  addr_only = 0;
1500  else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1501  ;
1502  else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1503  &e_addr, &e_port))
1504  addr_only = 0;
1505  else if (unformat (line_input, "external %U", unformat_ip4_address,
1506  &e_addr))
1507  ;
1508  else if (unformat (line_input, "vrf %u", &vrf_id))
1509  ;
1510  else if (unformat (line_input, "del"))
1511  is_add = 0;
1512  else
1513  return clib_error_return (0, "unknown input: '%U'",
1514  format_unformat_error, line_input);
1515  }
1516  unformat_free (line_input);
1517 
1518  rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1519  vrf_id, addr_only, is_add);
1520 
1521  switch (rv)
1522  {
1523  case VNET_API_ERROR_INVALID_VALUE:
1524  return clib_error_return (0, "External port already in use.");
1525  break;
1526  case VNET_API_ERROR_NO_SUCH_ENTRY:
1527  if (is_add)
1528  return clib_error_return (0, "External addres must be allocated.");
1529  else
1530  return clib_error_return (0, "Mapping not exist.");
1531  break;
1532  case VNET_API_ERROR_NO_SUCH_FIB:
1533  return clib_error_return (0, "No such VRF id.");
1534  case VNET_API_ERROR_VALUE_EXIST:
1535  return clib_error_return (0, "Mapping already exist.");
1536  default:
1537  break;
1538  }
1539 
1540  return error;
1541 }
1542 
1543 /*?
1544  * @cliexpar
1545  * @cliexstart{snat add static mapping}
1546  * Static mapping allows hosts on the external network to initiate connection
1547  * to to the local network host.
1548  * To create static mapping between local host address 10.0.0.3 port 6303 and
1549  * external address 4.4.4.4 port 3606 use:
1550  * vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606
1551  * If not runnig "static mapping only" S-NAT plugin mode use before:
1552  * vpp# snat add address 4.4.4.4
1553  * To create static mapping between local and external address use:
1554  * vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
1555  * @cliexend
1556 ?*/
1558  .path = "snat add static mapping",
1559  .function = add_static_mapping_command_fn,
1560  .short_help =
1561  "snat add static mapping local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1562 };
1563 
1564 static clib_error_t *
1566  unformat_input_t * input,
1567  vlib_cli_command_t * cmd)
1568 {
1569  unformat_input_t _line_input, *line_input = &_line_input;
1570  uword *bitmap = 0;
1571  int rv = 0;
1572 
1573  /* Get a line of input. */
1574  if (!unformat_user (input, unformat_line_input, line_input))
1575  return 0;
1576 
1577  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1578  {
1579  if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1580  ;
1581  else
1582  return clib_error_return (0, "unknown input '%U'",
1583  format_unformat_error, input);
1584  }
1585  unformat_free (line_input);
1586 
1587  if (bitmap == 0)
1588  return clib_error_return (0, "List of workers must be specified.");
1589 
1590  rv = snat_set_workers(bitmap);
1591 
1592  clib_bitmap_free (bitmap);
1593 
1594  switch (rv)
1595  {
1596  case VNET_API_ERROR_INVALID_WORKER:
1597  return clib_error_return (0, "Invalid worker(s).");
1598  break;
1599  case VNET_API_ERROR_FEATURE_DISABLED:
1600  return clib_error_return (0,
1601  "Supported only if 2 or more workes available.");
1602  break;
1603  default:
1604  break;
1605  }
1606 
1607  return 0;
1608 }
1609 
1610 /*?
1611  * @cliexpar
1612  * @cliexstart{set snat workers}
1613  * Set SNAT workers if 2 or more workers available, use:
1614  * vpp# set snat workers 0-2,5
1615  * @cliexend
1616 ?*/
1618  .path = "set snat workers",
1619  .function = set_workers_command_fn,
1620  .short_help =
1621  "set snat workers <workers-list>",
1622 };
1623 
1624 static clib_error_t *
1626 {
1627  snat_main_t * sm = &snat_main;
1628  u32 translation_buckets = 1024;
1629  u32 translation_memory_size = 128<<20;
1630  u32 user_buckets = 128;
1631  u32 user_memory_size = 64<<20;
1632  u32 max_translations_per_user = 100;
1633  u32 outside_vrf_id = 0;
1634  u32 inside_vrf_id = 0;
1635  u32 static_mapping_buckets = 1024;
1636  u32 static_mapping_memory_size = 64<<20;
1637  u8 static_mapping_only = 0;
1638  u8 static_mapping_connection_tracking = 0;
1640 
1641  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1642  {
1643  if (unformat (input, "translation hash buckets %d", &translation_buckets))
1644  ;
1645  else if (unformat (input, "translation hash memory %d",
1646  &translation_memory_size));
1647  else if (unformat (input, "user hash buckets %d", &user_buckets))
1648  ;
1649  else if (unformat (input, "user hash memory %d",
1650  &user_memory_size))
1651  ;
1652  else if (unformat (input, "max translations per user %d",
1653  &max_translations_per_user))
1654  ;
1655  else if (unformat (input, "outside VRF id %d",
1656  &outside_vrf_id))
1657  ;
1658  else if (unformat (input, "inside VRF id %d",
1659  &inside_vrf_id))
1660  ;
1661  else if (unformat (input, "static mapping only"))
1662  {
1663  static_mapping_only = 1;
1664  if (unformat (input, "connection tracking"))
1665  static_mapping_connection_tracking = 1;
1666  }
1667  else
1668  return clib_error_return (0, "unknown input '%U'",
1669  format_unformat_error, input);
1670  }
1671 
1672  /* for show commands, etc. */
1673  sm->translation_buckets = translation_buckets;
1674  sm->translation_memory_size = translation_memory_size;
1675  sm->user_buckets = user_buckets;
1676  sm->user_memory_size = user_memory_size;
1677  sm->max_translations_per_user = max_translations_per_user;
1678  sm->outside_vrf_id = outside_vrf_id;
1679  sm->outside_fib_index = ~0;
1680  sm->inside_vrf_id = inside_vrf_id;
1681  sm->inside_fib_index = ~0;
1682  sm->static_mapping_only = static_mapping_only;
1683  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
1684 
1685  if (!static_mapping_only ||
1686  (static_mapping_only && static_mapping_connection_tracking))
1687  {
1688  clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
1689  user_memory_size);
1690 
1691  clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
1692  user_memory_size);
1693 
1694  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1695 
1696  clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
1697  translation_memory_size);
1698 
1699  clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
1700  translation_memory_size);
1701 
1702  clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
1703  user_memory_size);
1704  }
1705  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1706  "static_mapping_by_local", static_mapping_buckets,
1707  static_mapping_memory_size);
1708 
1709  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1710  "static_mapping_by_external", static_mapping_buckets,
1711  static_mapping_memory_size);
1712  return 0;
1713 }
1714 
1716 
1717 u8 * format_snat_key (u8 * s, va_list * args)
1718 {
1719  snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
1720  char * protocol_string = "unknown";
1721  static char *protocol_strings[] = {
1722  "UDP",
1723  "TCP",
1724  "ICMP",
1725  };
1726 
1727  if (key->protocol < ARRAY_LEN(protocol_strings))
1728  protocol_string = protocol_strings[key->protocol];
1729 
1730  s = format (s, "%U proto %s port %d fib %d",
1731  format_ip4_address, &key->addr, protocol_string,
1732  clib_net_to_host_u16 (key->port), key->fib_index);
1733  return s;
1734 }
1735 
1736 u8 * format_snat_session (u8 * s, va_list * args)
1737 {
1738  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
1739  snat_session_t * sess = va_arg (*args, snat_session_t *);
1740 
1741  s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
1742  s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
1743  s = format (s, " last heard %.2f\n", sess->last_heard);
1744  s = format (s, " total pkts %d, total bytes %lld\n",
1745  sess->total_pkts, sess->total_bytes);
1746  if (snat_is_session_static (sess))
1747  s = format (s, " static translation\n");
1748  else
1749  s = format (s, " dynamic translation\n");
1750 
1751  return s;
1752 }
1753 
1754 u8 * format_snat_user (u8 * s, va_list * args)
1755 {
1757  snat_user_t * u = va_arg (*args, snat_user_t *);
1758  int verbose = va_arg (*args, int);
1759  dlist_elt_t * head, * elt;
1760  u32 elt_index, head_index;
1761  u32 session_index;
1762  snat_session_t * sess;
1763 
1764  s = format (s, "%U: %d dynamic translations, %d static translations\n",
1766 
1767  if (verbose == 0)
1768  return s;
1769 
1770  if (u->nsessions || u->nstaticsessions)
1771  {
1772  head_index = u->sessions_per_user_list_head_index;
1773  head = pool_elt_at_index (sm->list_pool, head_index);
1774 
1775  elt_index = head->next;
1776  elt = pool_elt_at_index (sm->list_pool, elt_index);
1777  session_index = elt->value;
1778 
1779  while (session_index != ~0)
1780  {
1781  sess = pool_elt_at_index (sm->sessions, session_index);
1782 
1783  s = format (s, " %U\n", format_snat_session, sm, sess);
1784 
1785  elt_index = elt->next;
1786  elt = pool_elt_at_index (sm->list_pool, elt_index);
1787  session_index = elt->value;
1788  }
1789  }
1790 
1791  return s;
1792 }
1793 
1794 u8 * format_snat_static_mapping (u8 * s, va_list * args)
1795 {
1796  snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
1797 
1798  if (m->addr_only)
1799  s = format (s, "local %U external %U vrf %d",
1802  m->vrf_id);
1803  else
1804  s = format (s, "local %U:%d external %U:%d vrf %d",
1807  m->vrf_id);
1808 
1809  return s;
1810 }
1811 
1812 static clib_error_t *
1814  unformat_input_t * input,
1815  vlib_cli_command_t * cmd)
1816 {
1817  int verbose = 0;
1818  snat_main_t * sm = &snat_main;
1819  snat_user_t * u;
1822  snat_address_t * ap;
1823  vnet_main_t *vnm = vnet_get_main();
1825  u32 users_num = 0, sessions_num = 0, *worker;
1826  uword j = 0;
1827 
1828  if (unformat (input, "detail"))
1829  verbose = 1;
1830  else if (unformat (input, "verbose"))
1831  verbose = 2;
1832 
1833  if (sm->static_mapping_only)
1834  {
1836  vlib_cli_output (vm, "SNAT mode: static mapping only connection "
1837  "tracking");
1838  else
1839  vlib_cli_output (vm, "SNAT mode: static mapping only");
1840  }
1841  else
1842  {
1843  vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
1844  }
1845 
1846  if (verbose > 0)
1847  {
1848  pool_foreach (i, sm->interfaces,
1849  ({
1850  vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
1851  vnet_get_sw_interface (vnm, i->sw_if_index),
1852  i->is_inside ? "in" : "out");
1853  }));
1854 
1855  vec_foreach (ap, sm->addresses)
1856  {
1857  u8 * s = format (0, "");
1858  vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
1860  ({
1861  s = format (s, " %d", j);
1862  }));
1863  vlib_cli_output (vm, " %d busy ports:%v", ap->busy_ports, s);
1864  }
1865  }
1866 
1867  if (sm->num_workers > 1)
1868  {
1869  vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
1870  if (verbose > 0)
1871  {
1872  vec_foreach (worker, sm->workers)
1873  {
1875  vlib_worker_threads + *worker + sm->first_worker_index;
1876  vlib_cli_output (vm, " %v", w->name);
1877  }
1878  }
1879  }
1880 
1882  {
1883  vlib_cli_output (vm, "%d static mappings",
1884  pool_elts (sm->static_mappings));
1885 
1886  if (verbose > 0)
1887  {
1888  pool_foreach (m, sm->static_mappings,
1889  ({
1890  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1891  }));
1892  }
1893  }
1894  else
1895  {
1896  vec_foreach (tsm, sm->per_thread_data)
1897  {
1898  users_num += pool_elts (tsm->users);
1899  sessions_num += pool_elts (tsm->sessions);
1900  }
1901 
1902  vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
1903  " %d static mappings",
1904  users_num,
1905  vec_len (sm->addresses),
1906  sessions_num,
1907  pool_elts (sm->static_mappings));
1908 
1909  if (verbose > 0)
1910  {
1911  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
1912  verbose - 1);
1913  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
1914  verbose - 1);
1915  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
1916  verbose - 1);
1917  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
1918  verbose - 1);
1920  {
1921  tsm = vec_elt_at_index (sm->per_thread_data, j);
1922 
1923  if (pool_elts (tsm->users) == 0)
1924  continue;
1925 
1927  vlib_cli_output (vm, "Thread %d (%v at lcore %u):", j, w->name,
1928  w->lcore_id);
1929  vlib_cli_output (vm, " %d list pool elements",
1930  pool_elts (tsm->list_pool));
1931 
1932  pool_foreach (u, tsm->users,
1933  ({
1934  vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
1935  verbose - 1);
1936  }));
1937  }
1938 
1939  if (pool_elts (sm->static_mappings))
1940  {
1941  vlib_cli_output (vm, "static mappings:");
1942  pool_foreach (m, sm->static_mappings,
1943  ({
1944  vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1945  }));
1946  }
1947  }
1948  }
1949 
1950  return 0;
1951 }
1952 
1954  .path = "show snat",
1955  .short_help = "show snat",
1956  .function = show_snat_command_fn,
1957 };
ip4_address_t external_addr
Definition: snat.h:121
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
u32 translation_memory_size
Definition: snat.h:193
u32 next
Definition: dlist.h:30
clib_bihash_8_8_t static_mapping_by_external
Definition: snat.h:171
static void * vl_api_snat_worker_dump_t_print(vl_api_snat_worker_dump_t *mp, void *handle)
Definition: snat.c:1086
Add/del S-NAT address range.
Definition: snat.api:31
static vlib_cli_command_t set_interface_snat_command
(constructor) VLIB_CLI_COMMAND (set_interface_snat_command)
Definition: snat.c:1472
#define vec_foreach_index(var, v)
Iterate over vector indices.
u32 sessions_per_user_list_head_index
Definition: snat.h:108
u32 max_translations_per_user
Definition: snat.h:196
static void vl_api_snat_interface_add_del_feature_t_handler(vl_api_snat_interface_add_del_feature_t *mp)
Definition: snat.c:763
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static void * vl_api_snat_add_static_mapping_t_print(vl_api_snat_add_static_mapping_t *mp, void *handle)
Definition: snat.c:873
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
vlib_main_t * vlib_main
Definition: snat.h:206
Set S-NAT workers reply.
Definition: snat.api:258
#define REPLY_MACRO2(t, body)
Definition: snat.c:79
a
Definition: bitmap.h:516
static void * vl_api_snat_interface_add_del_feature_t_print(vl_api_snat_interface_add_del_feature_t *mp, void *handle)
Definition: snat.c:781
u32 busy_ports
Definition: snat.h:115
void vl_msg_api_send_shmem(unix_shared_memory_queue_t *q, u8 *elem)
u32 nsessions
Definition: snat.h:109
static void vl_api_snat_add_address_range_t_handler(vl_api_snat_add_address_range_t *mp)
Definition: snat.c:650
clib_bihash_8_8_t out2in
Definition: snat.h:147
u8 static_mapping_connection_tracking
Definition: snat.h:191
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1453
ip_lookup_main_t * ip4_lookup_main
Definition: snat.h:209
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
u32 nstaticsessions
Definition: snat.h:110
unix_shared_memory_queue_t * vl_api_client_index_to_input_queue(u32 index)
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
static void send_snat_worker_details(u32 worker_index, unix_shared_memory_queue_t *q, u32 context)
Definition: snat.c:1049
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
ip_lookup_main_t lookup_main
Definition: ip4.h:97
void snat_add_address(snat_main_t *sm, ip4_address_t *addr)
Definition: snat.c:211
unformat_function_t unformat_vnet_sw_interface
snat_main_t snat_main
Definition: snat.c:27
u32 fq_out2in_index
Definition: snat.h:187
#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:142
format_function_t format_ip4_address
Definition: format.h:79
u32 * workers
Definition: snat.h:162
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: snat.c:1149
static uword clib_bitmap_get_no_check(uword *ai, uword i)
Gets the ith bit value from a bitmap Does not sanity-check the bit position.
Definition: bitmap.h:212
snat_interface_t * interfaces
Definition: snat.h:177
u32 inside_vrf_id
Definition: snat.h:199
static clib_error_t * add_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1330
static void vl_api_snat_add_static_mapping_t_handler(vl_api_snat_add_static_mapping_t *mp)
Definition: snat.c:840
static uword clib_bitmap_set_no_check(uword *a, uword i, uword new_value)
Sets the ith bit of a bitmap to new_value.
Definition: bitmap.h:141
ethernet_main_t * ethernet_main
Definition: plugin.h:27
static void vl_api_snat_control_ping_t_handler(vl_api_snat_control_ping_t *mp)
Definition: snat.c:945
api_main_t api_main
Definition: api_shared.c:39
u32 random_seed
Definition: snat.h:183
static int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Definition: snat.c:580
u8 * format_snat_key(u8 *s, va_list *args)
Definition: snat.c:1717
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
static void * vl_api_snat_control_ping_t_print(vl_api_snat_control_ping_t *mp, void *handle)
Definition: snat.c:958
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
snat_main_per_thread_data_t * per_thread_data
Definition: snat.h:165
u8 * format_snat_user(u8 *s, va_list *args)
Definition: snat.c:1754
ip4_address_t addr
Definition: snat.h:107
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external)
Match SNAT static mapping.
Definition: snat.c:1242
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define foreach_snat_plugin_api_msg
Definition: snat.c:1096
ip4_main_t * ip4_main
Definition: snat.h:208
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
snat_static_mapping_t * static_mappings
Definition: snat.h:174
#define VALIDATE_SW_IF_INDEX(mp)
Definition: snat.c:152
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
static clib_error_t * snat_plugin_api_hookup(vlib_main_t *vm)
Definition: snat.c:1110
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
ip4_address_t local_addr
Definition: snat.h:120
Control ping from the client to the server response.
Definition: snat.api:196
unformat_function_t unformat_ip4_address
Definition: format.h:76
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
clib_bihash_8_8_t worker_by_in
Definition: snat.h:154
#define REPLY_MACRO(t)
Definition: snat.c:64
S-NAT static mapping details response.
Definition: snat.api:169
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:54
#define hash_get(h, key)
Definition: hash.h:248
#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:369
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:112
Dump S-NAT workers.
Definition: snat.api:267
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:35
u32 translation_buckets
Definition: snat.h:192
#define v
Definition: acl.c:314
static void send_snat_static_mapping_details(snat_static_mapping_t *m, unix_shared_memory_queue_t *q, u32 context)
Definition: snat.c:895
static int is_snat_address_used_in_static_mapping(snat_main_t *sm, ip4_address_t addr)
Definition: snat.c:227
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
Set S-NAT workers.
Definition: snat.api:247
Enable/disable S-NAT feature on the interface reply.
Definition: snat.api:90
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:118
int snat_del_address(snat_main_t *sm, ip4_address_t addr)
Definition: snat.c:240
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:765
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:78
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
static void * vl_api_snat_address_dump_t_print(vl_api_snat_address_dump_t *mp, void *handle)
Definition: snat.c:752
static void increment_v4_address(ip4_address_t *a)
Definition: snat.c:308
u8 * format_snat_session(u8 *s, va_list *args)
Definition: snat.c:1736
Dump S-NAT static mappings.
Definition: snat.api:154
VNET_FEATURE_INIT(ip4_snat_in2out, static)
#define clib_bitmap_alloc(v, n_bits)
Allocate a bitmap with the supplied number of bits.
Definition: bitmap.h:109
static void * vl_api_snat_set_workers_t_print(vl_api_snat_set_workers_t *mp, void *handle)
Definition: snat.c:1025
u64 value
the value
Definition: bihash_8_8.h:36
snat_user_t * users
Definition: snat.h:136
void * vl_msg_api_alloc(int nbytes)
api_main_t * api_main
Definition: snat.h:211
static clib_error_t * show_snat_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1813
static void * vl_api_snat_static_mapping_dump_t_print(vl_api_snat_static_mapping_dump_t *mp, void *handle)
Definition: snat.c:934
u8 static_mapping_only
Definition: snat.h:190
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:84
clib_bihash_8_8_t user_hash
Definition: snat.h:151
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
snat_address_t * addresses
Definition: snat.h:180
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:1479
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
Dump interfaces with S-NAT feature.
Definition: snat.api:99
u16 msg_id_base
Definition: jvpp_snat.h:28
int snat_alloc_outside_address_and_port(snat_main_t *sm, snat_session_key_t *k, u32 *address_indexp)
Definition: snat.c:1292
#define FINISH
Definition: snat.c:50
#define clib_memcpy(a, b, c)
Definition: string.h:69
clib_error_t * vlib_plugin_register(vlib_main_t *vm, vnet_plugin_handoff_t *h, int from_early_init)
Definition: snat.c:136
static void send_snat_interface_details(snat_interface_t *i, unix_shared_memory_queue_t *q, u32 context)
Definition: snat.c:796
static uword * clib_bitmap_set_multiple(uword *bitmap, uword i, uword value, uword n_bits)
sets the ith through ith + n_bits bits in a bitmap
Definition: bitmap.h:275
static clib_error_t * snat_config(vlib_main_t *vm, unformat_input_t *input)
Definition: snat.c:1625
u32 inside_fib_index
Definition: snat.h:200
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
#define ARRAY_LEN(x)
Definition: clib.h:59
ip4_address_t addr
Definition: snat.h:37
u32 sw_if_index
Definition: snat.h:130
clib_bihash_8_8_t static_mapping_by_local
Definition: snat.h:168
S-NAT address details response.
Definition: snat.api:64
Add S-NAT address range reply.
Definition: snat.api:45
Add/delete S-NAT static mapping.
Definition: snat.api:127
Enable/disable S-NAT feature on the interface.
Definition: snat.api:77
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:228
#define ASSERT(truth)
Dump S-NAT addresses.
Definition: snat.api:54
unsigned int u32
Definition: types.h:88
u32 num_workers
Definition: snat.h:159
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static void vl_api_snat_set_workers_t_handler(vl_api_snat_set_workers_t *mp)
Definition: snat.c:1002
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, int is_add)
Add static mapping.
Definition: snat.c:331
IPv4 main type.
Definition: ip4.h:95
u8 * format_snat_static_mapping(u8 *s, va_list *args)
Definition: snat.c:1794
u64 as_u64
Definition: snat.h:54
static void vl_api_snat_show_config_t_handler(vl_api_snat_show_config_t *mp)
Definition: snat.c:969
clib_bihash_8_8_t in2out
Definition: snat.h:148
ip4_address_t addr
Definition: snat.h:51
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
uword * thread_registrations_by_name
Definition: threads.h:274
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
#define BAD_SW_IF_INDEX_LABEL
Definition: snat.c:162
u32 next_worker
Definition: snat.h:161
ip4_address_t addr
Definition: snat.h:114
#define VNET_FEATURES(...)
Definition: feature.h:363
static vlib_cli_command_t show_snat_command
(constructor) VLIB_CLI_COMMAND (show_snat_command)
Definition: snat.c:1953
u32 value
Definition: dlist.h:32
u64 uword
Definition: types.h:112
static void vl_api_snat_static_mapping_dump_t_handler(vl_api_snat_static_mapping_dump_t *mp)
Definition: snat.c:917
u32 fq_in2out_index
Definition: snat.h:186
S-NAT workers details response.
Definition: snat.api:278
u32 user_buckets
Definition: snat.h:194
unsigned short u16
Definition: types.h:57
static void vl_api_snat_interface_dump_t_handler(vl_api_snat_interface_dump_t *mp)
Definition: snat.c:813
vnet_main_t * vnet_main
Definition: snat.h:207
uword * busy_port_bitmap
Definition: snat.h:116
u32 outside_fib_index
Definition: snat.h:198
static void * vl_api_snat_add_address_range_t_print(vl_api_snat_add_address_range_t *mp, void *handle)
Definition: snat.c:705
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u32 first_worker_index
Definition: snat.h:160
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 vlib_cli_command_t add_address_command
(constructor) VLIB_CLI_COMMAND (add_address_command)
Definition: snat.c:1406
static void * vl_api_snat_show_config_t_print(vl_api_snat_show_config_t *mp, void *handle)
Definition: snat.c:991
u32 fib_index
Definition: snat.h:52
u32 user_memory_size
Definition: snat.h:195
void snat_free_outside_address_and_port(snat_main_t *sm, snat_session_key_t *k, u32 address_index)
Definition: snat.c:1213
vnet_main_t * vnet_main
Definition: plugin.h:26
static vlib_cli_command_t add_static_mapping_command
(constructor) VLIB_CLI_COMMAND (add_static_mapping_command)
Definition: snat.c:1557
ip4_address_t addr
Definition: snat.h:63
S-NAT interface details response.
Definition: snat.api:109
#define hash_get_mem(h, key)
Definition: hash.h:268
static void send_snat_address_details(snat_address_t *a, unix_shared_memory_queue_t *q, u32 context)
Definition: snat.c:720
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
Show S-NAT plugin startup config reply.
Definition: snat.api:227
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1099
Control ping from client to api server request.
Definition: snat.api:184
static void vl_api_snat_worker_dump_t_handler(vl_api_snat_worker_dump_t *mp)
Definition: snat.c:1069
#define vec_foreach(var, vec)
Vector iterator.
static void vl_api_snat_address_dump_t_handler(vl_api_snat_address_dump_t *mp)
Definition: snat.c:737
static void plugin_custom_dump_configure(snat_main_t *sm)
Definition: snat.c:1140
u16 vl_msg_api_get_msg_ids(char *name, int n)
Definition: api_shared.c:1309
vhost_vring_addr_t addr
Definition: vhost-user.h:81
#define clib_error_return(e, args...)
Definition: error.h:111
Add/delete S-NAT static mapping reply.
Definition: snat.api:145
static vlib_cli_command_t set_workers_command
(constructor) VLIB_CLI_COMMAND (set_workers_command)
Definition: snat.c:1617
struct _unformat_input_t unformat_input_t
ethernet_main_t * ethernet_main
Definition: snat.h:210
static void * vl_api_snat_interface_dump_t_print(vl_api_snat_interface_dump_t *mp, void *handle)
Definition: snat.c:830
#define BITS(x)
Definition: clib.h:58
Show S-NAT plugin startup config.
Definition: snat.api:208
unformat_function_t unformat_line_input
Definition: format.h:281
snat_session_t * sessions
Definition: snat.h:139
static clib_error_t * snat_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1413
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: snat.h:246
static void setup_message_id_table(snat_main_t *sm, api_main_t *am)
Definition: snat.c:1132
static clib_error_t * set_workers_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: snat.c:1565
u32 outside_vrf_id
Definition: snat.h:197
clib_bihash_8_8_t worker_by_out
Definition: snat.h:157
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:238
static int snat_set_workers(uword *bitmap)
Definition: snat.c:628
struct _unix_shared_memory_queue unix_shared_memory_queue_t
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109