FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
nat.c
Go to the documentation of this file.
1 /*
2  * snat.c - simple nat plugin
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
22 #include <nat/nat.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/nat_ipfix_logging.h>
25 #include <nat/nat_det.h>
26 #include <nat/nat64.h>
27 #include <nat/nat66.h>
28 #include <nat/dslite.h>
29 #include <nat/nat_reass.h>
30 #include <vnet/fib/fib_table.h>
31 #include <vnet/fib/ip4_fib.h>
32 
33 #include <vpp/app/version.h>
34 
36 
37 
38 /* Hook up input features */
39 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
40  .arc_name = "ip4-unicast",
41  .node_name = "nat44-in2out",
42  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
43 };
44 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
45  .arc_name = "ip4-unicast",
46  .node_name = "nat44-out2in",
47  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
48 };
49 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
50  .arc_name = "ip4-unicast",
51  .node_name = "nat44-classify",
52  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
53 };
54 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
55  .arc_name = "ip4-unicast",
56  .node_name = "nat44-det-in2out",
57  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
58 };
59 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
60  .arc_name = "ip4-unicast",
61  .node_name = "nat44-det-out2in",
62  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
63 };
64 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
65  .arc_name = "ip4-unicast",
66  .node_name = "nat44-det-classify",
67  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
68 };
69 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
70  .arc_name = "ip4-unicast",
71  .node_name = "nat44-in2out-worker-handoff",
72  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
73 };
74 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
75  .arc_name = "ip4-unicast",
76  .node_name = "nat44-out2in-worker-handoff",
77  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
78 };
79 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
80  .arc_name = "ip4-unicast",
81  .node_name = "nat44-handoff-classify",
82  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
83 };
84 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
85  .arc_name = "ip4-unicast",
86  .node_name = "nat44-in2out-fast",
87  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
88 };
89 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
90  .arc_name = "ip4-unicast",
91  .node_name = "nat44-out2in-fast",
92  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
93 };
94 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
95  .arc_name = "ip4-unicast",
96  .node_name = "nat44-hairpin-dst",
97  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
98 };
99 
100 /* Hook up output features */
101 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
102  .arc_name = "ip4-output",
103  .node_name = "nat44-in2out-output",
104  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
105 };
106 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
107  .arc_name = "ip4-output",
108  .node_name = "nat44-in2out-output-worker-handoff",
109  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
110 };
111 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
112  .arc_name = "ip4-output",
113  .node_name = "nat44-hairpin-src",
114  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
115 };
116 
117 /* Hook up ip4-local features */
118 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
119 {
120  .arc_name = "ip4-local",
121  .node_name = "nat44-hairpinning",
122  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
123 };
124 
125 
126 /* *INDENT-OFF* */
128  .version = VPP_BUILD_VER,
129  .description = "Network Address Translation",
130 };
131 /* *INDENT-ON* */
132 
136 
137 typedef enum {
142 
143 void
144 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
145 {
146  snat_session_key_t key;
148  nat_ed_ses_key_t ed_key;
149  clib_bihash_kv_16_8_t ed_kv;
150  int i;
151  snat_address_t *a;
153  vec_elt_at_index (sm->per_thread_data, thread_index);
154 
155  /* Endpoint dependent session lookup tables */
156  if (is_ed_session (s))
157  {
158  ed_key.l_addr = s->out2in.addr;
159  ed_key.r_addr = s->ext_host_addr;
160  ed_key.fib_index = s->out2in.fib_index;
162  {
163  ed_key.proto = s->in2out.port;
164  ed_key.r_port = 0;
165  ed_key.l_port = 0;
166  }
167  else
168  {
169  ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
170  ed_key.l_port = s->out2in.port;
171  ed_key.r_port = s->ext_host_port;
172  }
173  ed_kv.key[0] = ed_key.as_u64[0];
174  ed_kv.key[1] = ed_key.as_u64[1];
175  if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
176  clib_warning ("out2in_ed key del failed");
177 
178  ed_key.l_addr = s->in2out.addr;
179  ed_key.fib_index = s->in2out.fib_index;
180  if (!snat_is_unk_proto_session (s))
181  ed_key.l_port = s->in2out.port;
182  if (is_twice_nat_session (s))
183  {
184  ed_key.r_addr = s->ext_host_nat_addr;
185  ed_key.r_port = s->ext_host_nat_port;
186  }
187  ed_kv.key[0] = ed_key.as_u64[0];
188  ed_kv.key[1] = ed_key.as_u64[1];
189  if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
190  clib_warning ("in2out_ed key del failed");
191  }
192 
194  return;
195 
196  /* log NAT event */
197  snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
198  s->out2in.addr.as_u32,
199  s->in2out.protocol,
200  s->in2out.port,
201  s->out2in.port,
202  s->in2out.fib_index);
203 
204  /* Twice NAT address and port for external host */
205  if (is_twice_nat_session (s))
206  {
207  for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
208  {
209  key.protocol = s->in2out.protocol;
210  key.port = s->ext_host_nat_port;
211  a = sm->twice_nat_addresses + i;
212  if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
213  {
215  thread_index, &key, i);
216  break;
217  }
218  }
219  }
220 
221  if (is_ed_session (s))
222  return;
223 
224  /* Session lookup tables */
225  kv.key = s->in2out.as_u64;
226  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
227  clib_warning ("in2out key del failed");
228  kv.key = s->out2in.as_u64;
229  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
230  clib_warning ("out2in key del failed");
231 
232  if (snat_is_session_static (s))
233  return;
234 
235  if (s->outside_address_index != ~0)
237  &s->out2in, s->outside_address_index);
238 }
239 
240 snat_user_t *
242  u32 thread_index)
243 {
244  snat_user_t *u = 0;
245  snat_user_key_t user_key;
246  clib_bihash_kv_8_8_t kv, value;
247  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
248  dlist_elt_t * per_user_list_head_elt;
249 
250  user_key.addr.as_u32 = addr->as_u32;
251  user_key.fib_index = fib_index;
252  kv.key = user_key.as_u64;
253 
254  /* Ever heard of the "user" = src ip4 address before? */
255  if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
256  {
257  /* no, make a new one */
258  pool_get (tsm->users, u);
259  memset (u, 0, sizeof (*u));
260  u->addr.as_u32 = addr->as_u32;
261  u->fib_index = fib_index;
262 
263  pool_get (tsm->list_pool, per_user_list_head_elt);
264 
265  u->sessions_per_user_list_head_index = per_user_list_head_elt -
266  tsm->list_pool;
267 
269 
270  kv.value = u - tsm->users;
271 
272  /* add user */
273  if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
274  clib_warning ("user_hash keay add failed");
275  }
276  else
277  {
278  u = pool_elt_at_index (tsm->users, value.value);
279  }
280 
281  return u;
282 }
283 
284 snat_session_t *
286 {
287  snat_session_t *s;
288  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
289  u32 oldest_per_user_translation_list_index, session_index;
290  dlist_elt_t * oldest_per_user_translation_list_elt;
291  dlist_elt_t * per_user_translation_list_elt;
292 
293  /* Over quota? Recycle the least recently used translation */
295  {
296  oldest_per_user_translation_list_index =
299 
300  ASSERT (oldest_per_user_translation_list_index != ~0);
301 
302  /* Add it back to the end of the LRU list */
305  oldest_per_user_translation_list_index);
306  /* Get the list element */
307  oldest_per_user_translation_list_elt =
309  oldest_per_user_translation_list_index);
310 
311  /* Get the session index from the list element */
312  session_index = oldest_per_user_translation_list_elt->value;
313 
314  /* Get the session */
315  s = pool_elt_at_index (tsm->sessions, session_index);
316  nat_free_session_data (sm, s, thread_index);
317  s->outside_address_index = ~0;
318  s->flags = 0;
319  s->total_bytes = 0;
320  s->total_pkts = 0;
321  }
322  else
323  {
324  pool_get (tsm->sessions, s);
325  memset (s, 0, sizeof (*s));
326  s->outside_address_index = ~0;
327 
328  /* Create list elts */
329  pool_get (tsm->list_pool, per_user_translation_list_elt);
331  per_user_translation_list_elt - tsm->list_pool);
332 
333  per_user_translation_list_elt->value = s - tsm->sessions;
334  s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
335  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
336 
338  s->per_user_list_head_index,
339  per_user_translation_list_elt - tsm->list_pool);
340  }
341 
342  return s;
343 }
344 
345 static inline uword
347  vlib_node_runtime_t * node,
348  vlib_frame_t * frame)
349 {
350  u32 n_left_from, * from, * to_next;
351  nat44_classify_next_t next_index;
352  snat_main_t *sm = &snat_main;
353 
354  from = vlib_frame_vector_args (frame);
355  n_left_from = frame->n_vectors;
356  next_index = node->cached_next_index;
357 
358  while (n_left_from > 0)
359  {
360  u32 n_left_to_next;
361 
362  vlib_get_next_frame (vm, node, next_index,
363  to_next, n_left_to_next);
364 
365  while (n_left_from > 0 && n_left_to_next > 0)
366  {
367  u32 bi0;
368  vlib_buffer_t *b0;
370  ip4_header_t *ip0;
371  snat_address_t *ap;
372  snat_session_key_t m_key0;
373  clib_bihash_kv_8_8_t kv0, value0;
374 
375  /* speculatively enqueue b0 to the current next frame */
376  bi0 = from[0];
377  to_next[0] = bi0;
378  from += 1;
379  to_next += 1;
380  n_left_from -= 1;
381  n_left_to_next -= 1;
382 
383  b0 = vlib_get_buffer (vm, bi0);
384  ip0 = vlib_buffer_get_current (b0);
385 
386  vec_foreach (ap, sm->addresses)
387  {
388  if (ip0->dst_address.as_u32 == ap->addr.as_u32)
389  {
391  goto enqueue0;
392  }
393  }
394 
396  {
397  m_key0.addr = ip0->dst_address;
398  m_key0.port = 0;
399  m_key0.protocol = 0;
400  m_key0.fib_index = sm->outside_fib_index;
401  kv0.key = m_key0.as_u64;
402  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
403  {
405  goto enqueue0;
406  }
407  udp_header_t * udp0 = ip4_next_header (ip0);
408  m_key0.port = clib_net_to_host_u16 (udp0->dst_port);
409  m_key0.protocol = ip_proto_to_snat_proto (ip0->protocol);
410  kv0.key = m_key0.as_u64;
411  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
413  }
414 
415  enqueue0:
416  /* verify speculative enqueue, maybe switch current next frame */
417  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
418  to_next, n_left_to_next,
419  bi0, next0);
420  }
421 
422  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
423  }
424 
425  return frame->n_vectors;
426 }
427 
428 static uword
430  vlib_node_runtime_t * node,
431  vlib_frame_t * frame)
432 {
433  return nat44_classify_node_fn_inline (vm, node, frame);
434 };
435 
437  .function = nat44_classify_node_fn,
438  .name = "nat44-classify",
439  .vector_size = sizeof (u32),
440  .type = VLIB_NODE_TYPE_INTERNAL,
441  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
442  .next_nodes = {
443  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
444  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
445  },
446 };
447 
450 
451 static uword
453  vlib_node_runtime_t * node,
454  vlib_frame_t * frame)
455 {
456  return nat44_classify_node_fn_inline (vm, node, frame);
457 };
458 
460  .function = nat44_det_classify_node_fn,
461  .name = "nat44-det-classify",
462  .vector_size = sizeof (u32),
463  .type = VLIB_NODE_TYPE_INTERNAL,
464  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
465  .next_nodes = {
466  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
467  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
468  },
469 };
470 
473 
474 static uword
476  vlib_node_runtime_t * node,
477  vlib_frame_t * frame)
478 {
479  return nat44_classify_node_fn_inline (vm, node, frame);
480 };
481 
483  .function = nat44_handoff_classify_node_fn,
484  .name = "nat44-handoff-classify",
485  .vector_size = sizeof (u32),
486  .type = VLIB_NODE_TYPE_INTERNAL,
487  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
488  .next_nodes = {
489  [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
490  [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
491  },
492 };
493 
496 
497 /**
498  * @brief Add/del NAT address to FIB.
499  *
500  * Add the external NAT address to the FIB as receive entries. This ensures
501  * that VPP will reply to ARP for this address and we don't need to enable
502  * proxy ARP on the outside interface.
503  *
504  * @param addr IPv4 address.
505  * @param plen address prefix length
506  * @param sw_if_index Interface.
507  * @param is_add If 0 delete, otherwise add.
508  */
509 void
511  int is_add)
512 {
513  fib_prefix_t prefix = {
514  .fp_len = p_len,
515  .fp_proto = FIB_PROTOCOL_IP4,
516  .fp_addr = {
517  .ip4.as_u32 = addr->as_u32,
518  },
519  };
520  u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
521 
522  if (is_add)
524  &prefix,
530  NULL,
531  sw_if_index,
532  ~0,
533  1,
534  NULL,
536  else
537  fib_table_entry_delete(fib_index,
538  &prefix,
540 }
541 
543  u8 twice_nat)
544 {
545  snat_address_t * ap;
548 
549  /* Check if address already exists */
550  vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
551  {
552  if (ap->addr.as_u32 == addr->as_u32)
553  return;
554  }
555 
556  if (twice_nat)
557  vec_add2 (sm->twice_nat_addresses, ap, 1);
558  else
559  vec_add2 (sm->addresses, ap, 1);
560 
561  ap->addr = *addr;
562  if (vrf_id != ~0)
563  ap->fib_index =
566  else
567  ap->fib_index = ~0;
568 #define _(N, i, n, s) \
569  clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
570  ap->busy_##n##_ports = 0; \
571  vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
573 #undef _
574 
575  if (twice_nat)
576  return;
577 
578  /* Add external address to FIB */
579  pool_foreach (i, sm->interfaces,
580  ({
581  if (nat_interface_is_inside(i) || sm->out2in_dpo)
582  continue;
583 
584  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
585  break;
586  }));
588  ({
589  if (nat_interface_is_inside(i) || sm->out2in_dpo)
590  continue;
591 
592  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
593  break;
594  }));
595 }
596 
599 {
602  ({
603  if (m->external_addr.as_u32 == addr.as_u32)
604  return 1;
605  }));
606 
607  return 0;
608 }
609 
611 {
612  u32 v;
613 
614  v = clib_net_to_host_u32(a->as_u32) + 1;
615  a->as_u32 = clib_host_to_net_u32(v);
616 }
617 
618 static void
620  ip4_address_t l_addr,
621  u16 l_port,
622  u32 sw_if_index,
623  u16 e_port,
624  u32 vrf_id,
625  snat_protocol_t proto,
626  int addr_only,
627  int is_add,
628  u8 * tag)
629 {
631 
632  vec_add2 (sm->to_resolve, rp, 1);
633  rp->l_addr.as_u32 = l_addr.as_u32;
634  rp->l_port = l_port;
635  rp->sw_if_index = sw_if_index;
636  rp->e_port = e_port;
637  rp->vrf_id = vrf_id;
638  rp->proto = proto;
639  rp->addr_only = addr_only;
640  rp->is_add = is_add;
641  rp->tag = vec_dup (tag);
642 }
643 
644 /**
645  * @brief Add static mapping.
646  *
647  * Create static mapping between local addr+port and external addr+port.
648  *
649  * @param l_addr Local IPv4 address.
650  * @param e_addr External IPv4 address.
651  * @param l_port Local port number.
652  * @param e_port External port number.
653  * @param vrf_id VRF ID.
654  * @param addr_only If 0 address port and pair mapping, otherwise address only.
655  * @param sw_if_index External port instead of specific IP address.
656  * @param is_add If 0 delete static mapping, otherwise add.
657  * @param twice_nat If 1 translate external host address and port.
658  * @param out2in_only If 1 rule match only out2in direction
659  * @param tag - opaque string tag
660  *
661  * @returns
662  */
664  u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
665  u32 sw_if_index, snat_protocol_t proto, int is_add,
666  u8 twice_nat, u8 out2in_only, u8 * tag)
667 {
668  snat_main_t * sm = &snat_main;
670  snat_session_key_t m_key;
671  clib_bihash_kv_8_8_t kv, value;
672  snat_address_t *a = 0;
673  u32 fib_index = ~0;
674  uword * p;
675  snat_interface_t *interface;
676  int i;
678  snat_user_key_t u_key;
679  snat_user_t *u;
680  dlist_elt_t * head, * elt;
681  u32 elt_index, head_index;
682  u32 ses_index;
683  u64 user_index;
684  snat_session_t * s;
685  snat_static_map_resolve_t *rp, *rp_match = 0;
686 
687  /* If the external address is a specific interface address */
688  if (sw_if_index != ~0)
689  {
690  ip4_address_t * first_int_addr;
691 
692  for (i = 0; i < vec_len (sm->to_resolve); i++)
693  {
694  rp = sm->to_resolve + i;
695  if (rp->sw_if_index != sw_if_index &&
696  rp->l_addr.as_u32 != l_addr.as_u32 &&
697  rp->vrf_id != vrf_id && rp->addr_only != addr_only)
698  continue;
699 
700  if (!addr_only)
701  {
702  if (rp->l_port != l_port && rp->e_port != e_port && rp->proto != proto)
703  continue;
704  }
705 
706  rp_match = rp;
707  break;
708  }
709 
710  /* Might be already set... */
711  first_int_addr = ip4_interface_first_address
712  (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
713 
714  if (is_add)
715  {
716  if (rp_match)
717  return VNET_API_ERROR_VALUE_EXIST;
718 
720  (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
721  addr_only, is_add, tag);
722 
723  /* DHCP resolution required? */
724  if (first_int_addr == 0)
725  {
726  return 0;
727  }
728  else
729  {
730  e_addr.as_u32 = first_int_addr->as_u32;
731  /* Identity mapping? */
732  if (l_addr.as_u32 == 0)
733  l_addr.as_u32 = e_addr.as_u32;
734  }
735  }
736  else
737  {
738  if (!rp_match)
739  return VNET_API_ERROR_NO_SUCH_ENTRY;
740 
741  vec_del1 (sm->to_resolve, i);
742 
743  if (first_int_addr)
744  {
745  e_addr.as_u32 = first_int_addr->as_u32;
746  /* Identity mapping? */
747  if (l_addr.as_u32 == 0)
748  l_addr.as_u32 = e_addr.as_u32;
749  }
750  else
751  return 0;
752  }
753  }
754 
755  m_key.addr = e_addr;
756  m_key.port = addr_only ? 0 : e_port;
757  m_key.protocol = addr_only ? 0 : proto;
758  m_key.fib_index = sm->outside_fib_index;
759  kv.key = m_key.as_u64;
760  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
761  m = 0;
762  else
763  m = pool_elt_at_index (sm->static_mappings, value.value);
764 
765  if (is_add)
766  {
767  if (m)
768  return VNET_API_ERROR_VALUE_EXIST;
769 
770  if (twice_nat && addr_only)
771  return VNET_API_ERROR_UNSUPPORTED;
772 
773  /* Convert VRF id to FIB index */
774  if (vrf_id != ~0)
775  {
776  p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
777  if (!p)
778  return VNET_API_ERROR_NO_SUCH_FIB;
779  fib_index = p[0];
780  }
781  /* If not specified use inside VRF id from SNAT plugin startup config */
782  else
783  {
784  fib_index = sm->inside_fib_index;
785  vrf_id = sm->inside_vrf_id;
786  }
787 
788  if (!out2in_only)
789  {
790  m_key.addr = l_addr;
791  m_key.port = addr_only ? 0 : l_port;
792  m_key.protocol = addr_only ? 0 : proto;
793  m_key.fib_index = fib_index;
794  kv.key = m_key.as_u64;
795  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
796  return VNET_API_ERROR_VALUE_EXIST;
797  }
798 
799  /* Find external address in allocated addresses and reserve port for
800  address and port pair mapping when dynamic translations enabled */
801  if (!(addr_only || sm->static_mapping_only || out2in_only))
802  {
803  for (i = 0; i < vec_len (sm->addresses); i++)
804  {
805  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
806  {
807  a = sm->addresses + i;
808  /* External port must be unused */
809  switch (proto)
810  {
811 #define _(N, j, n, s) \
812  case SNAT_PROTOCOL_##N: \
813  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
814  return VNET_API_ERROR_INVALID_VALUE; \
815  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
816  if (e_port > 1024) \
817  { \
818  a->busy_##n##_ports++; \
819  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
820  } \
821  break;
823 #undef _
824  default:
825  clib_warning("unknown_protocol");
826  return VNET_API_ERROR_INVALID_VALUE_2;
827  }
828  break;
829  }
830  }
831  /* External address must be allocated */
832  if (!a && (l_addr.as_u32 != e_addr.as_u32))
833  {
834  if (sw_if_index != ~0)
835  {
836  for (i = 0; i < vec_len (sm->to_resolve); i++)
837  {
838  rp = sm->to_resolve + i;
839  if (rp->addr_only)
840  continue;
841  if (rp->sw_if_index != sw_if_index &&
842  rp->l_addr.as_u32 != l_addr.as_u32 &&
843  rp->vrf_id != vrf_id && rp->l_port != l_port &&
844  rp->e_port != e_port && rp->proto != proto)
845  continue;
846 
847  vec_del1 (sm->to_resolve, i);
848  break;
849  }
850  }
851  return VNET_API_ERROR_NO_SUCH_ENTRY;
852  }
853  }
854 
855  pool_get (sm->static_mappings, m);
856  memset (m, 0, sizeof (*m));
857  m->tag = vec_dup (tag);
858  m->local_addr = l_addr;
859  m->external_addr = e_addr;
860  m->addr_only = addr_only;
861  m->vrf_id = vrf_id;
862  m->fib_index = fib_index;
863  m->twice_nat = twice_nat;
864  m->out2in_only = out2in_only;
865  if (!addr_only)
866  {
867  m->local_port = l_port;
868  m->external_port = e_port;
869  m->proto = proto;
870  }
871 
872  if (sm->workers)
873  {
874  ip4_header_t ip = {
875  .src_address = m->local_addr,
876  };
877  m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index);
879  }
880  else
882 
883  m_key.addr = m->local_addr;
884  m_key.port = m->local_port;
885  m_key.protocol = m->proto;
886  m_key.fib_index = m->fib_index;
887  kv.key = m_key.as_u64;
888  kv.value = m - sm->static_mappings;
889  if (!out2in_only)
890  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
891  if (twice_nat || out2in_only)
892  {
893  m_key.port = clib_host_to_net_u16 (l_port);
894  kv.key = m_key.as_u64;
895  kv.value = ~0ULL;
896  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
897  clib_warning ("in2out key add failed");
898  }
899 
900  m_key.addr = m->external_addr;
901  m_key.port = m->external_port;
902  m_key.fib_index = sm->outside_fib_index;
903  kv.key = m_key.as_u64;
904  kv.value = m - sm->static_mappings;
905  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
906  if (twice_nat || out2in_only)
907  {
908  m_key.port = clib_host_to_net_u16 (e_port);
909  kv.key = m_key.as_u64;
910  kv.value = ~0ULL;
911  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
912  clib_warning ("out2in key add failed");
913  }
914 
915  /* Delete dynamic sessions matching local address (+ local port) */
916  if (!(sm->static_mapping_only))
917  {
918  u_key.addr = m->local_addr;
919  u_key.fib_index = m->fib_index;
920  kv.key = u_key.as_u64;
921  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
922  {
923  user_index = value.value;
924  u = pool_elt_at_index (tsm->users, user_index);
925  if (u->nsessions)
926  {
927  head_index = u->sessions_per_user_list_head_index;
928  head = pool_elt_at_index (tsm->list_pool, head_index);
929  elt_index = head->next;
930  elt = pool_elt_at_index (tsm->list_pool, elt_index);
931  ses_index = elt->value;
932  while (ses_index != ~0)
933  {
934  s = pool_elt_at_index (tsm->sessions, ses_index);
935  elt = pool_elt_at_index (tsm->list_pool, elt->next);
936  ses_index = elt->value;
937 
938  if (snat_is_session_static (s))
939  continue;
940 
941  if (!addr_only)
942  {
943  if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
944  (clib_net_to_host_u16 (s->out2in.port) != e_port))
945  continue;
946  }
947 
948  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
949  clib_dlist_remove (tsm->list_pool, s->per_user_index);
950  pool_put_index (tsm->list_pool, s->per_user_index);
951  pool_put (tsm->sessions, s);
952  u->nsessions--;
953 
954  if (!addr_only)
955  break;
956  }
957  }
958  }
959  }
960  }
961  else
962  {
963  if (!m)
964  {
965  if (sw_if_index != ~0)
966  return 0;
967  else
968  return VNET_API_ERROR_NO_SUCH_ENTRY;
969  }
970 
971  /* Free external address port */
972  if (!(addr_only || sm->static_mapping_only || out2in_only))
973  {
974  for (i = 0; i < vec_len (sm->addresses); i++)
975  {
976  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
977  {
978  a = sm->addresses + i;
979  switch (proto)
980  {
981 #define _(N, j, n, s) \
982  case SNAT_PROTOCOL_##N: \
983  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
984  if (e_port > 1024) \
985  { \
986  a->busy_##n##_ports--; \
987  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
988  } \
989  break;
991 #undef _
992  default:
993  clib_warning("unknown_protocol");
994  return VNET_API_ERROR_INVALID_VALUE_2;
995  }
996  break;
997  }
998  }
999  }
1000 
1001  if (sm->num_workers > 1)
1003  else
1004  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1005 
1006  m_key.addr = m->local_addr;
1007  m_key.port = m->local_port;
1008  m_key.protocol = m->proto;
1009  m_key.fib_index = m->fib_index;
1010  kv.key = m_key.as_u64;
1011  if (!out2in_only)
1012  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
1013  if (twice_nat || out2in_only)
1014  {
1015  m_key.port = clib_host_to_net_u16 (m->local_port);
1016  kv.key = m_key.as_u64;
1017  kv.value = ~0ULL;
1018  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1019  clib_warning ("in2out key del failed");
1020  }
1021 
1022  m_key.addr = m->external_addr;
1023  m_key.port = m->external_port;
1024  m_key.fib_index = sm->outside_fib_index;
1025  kv.key = m_key.as_u64;
1026  clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
1027  if (twice_nat || out2in_only)
1028  {
1029  m_key.port = clib_host_to_net_u16 (m->external_port);
1030  kv.key = m_key.as_u64;
1031  kv.value = ~0ULL;
1032  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1033  clib_warning ("in2out key del failed");
1034  }
1035 
1036  /* Delete session(s) for static mapping if exist */
1037  if (!(sm->static_mapping_only) ||
1039  {
1040  u_key.addr = m->local_addr;
1041  u_key.fib_index = m->fib_index;
1042  kv.key = u_key.as_u64;
1043  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1044  {
1045  user_index = value.value;
1046  u = pool_elt_at_index (tsm->users, user_index);
1047  if (u->nstaticsessions)
1048  {
1049  head_index = u->sessions_per_user_list_head_index;
1050  head = pool_elt_at_index (tsm->list_pool, head_index);
1051  elt_index = head->next;
1052  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1053  ses_index = elt->value;
1054  while (ses_index != ~0)
1055  {
1056  s = pool_elt_at_index (tsm->sessions, ses_index);
1057  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1058  ses_index = elt->value;
1059 
1060  if (!addr_only)
1061  {
1062  if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
1063  (clib_net_to_host_u16 (s->out2in.port) != e_port))
1064  continue;
1065  }
1066 
1067  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1068  clib_dlist_remove (tsm->list_pool, s->per_user_index);
1069  pool_put_index (tsm->list_pool, s->per_user_index);
1070  pool_put (tsm->sessions, s);
1071  u->nstaticsessions--;
1072 
1073  if (!addr_only)
1074  break;
1075  }
1076  if (addr_only)
1077  {
1078  pool_put (tsm->users, u);
1079  clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
1080  }
1081  }
1082  }
1083  }
1084 
1085  vec_free (m->tag);
1086  /* Delete static mapping from pool */
1087  pool_put (sm->static_mappings, m);
1088  }
1089 
1090  if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1091  return 0;
1092 
1093  /* Add/delete external address to FIB */
1094  pool_foreach (interface, sm->interfaces,
1095  ({
1096  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1097  continue;
1098 
1099  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1100  break;
1101  }));
1102  pool_foreach (interface, sm->output_feature_interfaces,
1103  ({
1104  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1105  continue;
1106 
1107  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1108  break;
1109  }));
1110 
1111  return 0;
1112 }
1113 
1115  ip4_address_t * e_addr, u16 e_port)
1116 {
1117  snat_main_t *sm = &snat_main;
1120 
1121  /* *INDENT-OFF* */
1122  pool_foreach (m, sm->static_mappings,
1123  ({
1124  if (vec_len(m->locals))
1125  {
1126  if (m->external_port == e_port && m->external_addr.as_u32 == e_addr->as_u32)
1127  continue;
1128 
1129  vec_foreach (ap, m->locals)
1130  {
1131  if (ap->port == local->port && ap->addr.as_u32 == local->addr.as_u32)
1132  return 1;
1133  }
1134  }
1135  }));
1136  /* *INDENT-ON* */
1137 
1138  return 0;
1139 }
1140 
1142  snat_protocol_t proto, u32 vrf_id,
1143  nat44_lb_addr_port_t *locals, u8 is_add,
1144  u8 twice_nat, u8 out2in_only, u8 *tag)
1145 {
1146  snat_main_t * sm = &snat_main;
1148  snat_session_key_t m_key;
1149  clib_bihash_kv_8_8_t kv, value;
1150  u32 fib_index;
1151  snat_address_t *a = 0;
1152  int i;
1153  nat44_lb_addr_port_t *local;
1154  u32 worker_index = 0, elt_index, head_index, ses_index;
1156  snat_user_key_t u_key;
1157  snat_user_t *u;
1158  snat_session_t * s;
1159  dlist_elt_t * head, * elt;
1160 
1161  m_key.addr = e_addr;
1162  m_key.port = e_port;
1163  m_key.protocol = proto;
1164  m_key.fib_index = sm->outside_fib_index;
1165  kv.key = m_key.as_u64;
1166  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1167  m = 0;
1168  else
1169  m = pool_elt_at_index (sm->static_mappings, value.value);
1170 
1171  if (is_add)
1172  {
1173  if (m)
1174  return VNET_API_ERROR_VALUE_EXIST;
1175 
1176  if (vec_len (locals) < 2)
1177  return VNET_API_ERROR_INVALID_VALUE;
1178 
1180  vrf_id,
1182 
1183  /* Find external address in allocated addresses and reserve port for
1184  address and port pair mapping when dynamic translations enabled */
1185  if (!(sm->static_mapping_only || out2in_only))
1186  {
1187  for (i = 0; i < vec_len (sm->addresses); i++)
1188  {
1189  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1190  {
1191  a = sm->addresses + i;
1192  /* External port must be unused */
1193  switch (proto)
1194  {
1195 #define _(N, j, n, s) \
1196  case SNAT_PROTOCOL_##N: \
1197  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1198  return VNET_API_ERROR_INVALID_VALUE; \
1199  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1200  if (e_port > 1024) \
1201  { \
1202  a->busy_##n##_ports++; \
1203  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1204  } \
1205  break;
1207 #undef _
1208  default:
1209  clib_warning("unknown_protocol");
1210  return VNET_API_ERROR_INVALID_VALUE_2;
1211  }
1212  break;
1213  }
1214  }
1215  /* External address must be allocated */
1216  if (!a)
1217  return VNET_API_ERROR_NO_SUCH_ENTRY;
1218  }
1219 
1220  pool_get (sm->static_mappings, m);
1221  memset (m, 0, sizeof (*m));
1222  m->tag = vec_dup (tag);
1223  m->external_addr = e_addr;
1224  m->addr_only = 0;
1225  m->vrf_id = vrf_id;
1226  m->fib_index = fib_index;
1227  m->external_port = e_port;
1228  m->proto = proto;
1229  m->twice_nat = twice_nat;
1230  m->out2in_only = out2in_only;
1231 
1232  m_key.addr = m->external_addr;
1233  m_key.port = m->external_port;
1234  m_key.protocol = m->proto;
1235  m_key.fib_index = sm->outside_fib_index;
1236  kv.key = m_key.as_u64;
1237  kv.value = m - sm->static_mappings;
1238  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1239  {
1240  clib_warning ("static_mapping_by_external key add failed");
1241  return VNET_API_ERROR_UNSPECIFIED;
1242  }
1243 
1244  /* Assign worker */
1245  if (sm->workers)
1246  {
1247  worker_index = sm->first_worker_index +
1248  sm->workers[sm->next_worker++ % vec_len (sm->workers)];
1249  tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
1250  m->worker_index = worker_index;
1251  }
1252  else
1253  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1254 
1255  m_key.port = clib_host_to_net_u16 (m->external_port);
1256  kv.key = m_key.as_u64;
1257  kv.value = ~0ULL;
1258  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
1259  {
1260  clib_warning ("out2in key add failed");
1261  return VNET_API_ERROR_UNSPECIFIED;
1262  }
1263 
1264  m_key.fib_index = m->fib_index;
1265  for (i = 0; i < vec_len (locals); i++)
1266  {
1267  m_key.addr = locals[i].addr;
1268  if (!out2in_only)
1269  {
1270  m_key.port = locals[i].port;
1271  kv.key = m_key.as_u64;
1272  kv.value = m - sm->static_mappings;
1273  clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1274  }
1275  locals[i].prefix = (i == 0) ? locals[i].probability :\
1276  (locals[i - 1].prefix + locals[i].probability);
1277  vec_add1 (m->locals, locals[i]);
1278 
1279  m_key.port = clib_host_to_net_u16 (locals[i].port);
1280  kv.key = m_key.as_u64;
1281  kv.value = ~0ULL;
1282  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
1283  {
1284  clib_warning ("in2out key add failed");
1285  return VNET_API_ERROR_UNSPECIFIED;
1286  }
1287  }
1288  }
1289  else
1290  {
1291  if (!m)
1292  return VNET_API_ERROR_NO_SUCH_ENTRY;
1293 
1295 
1296  /* Free external address port */
1297  if (!(sm->static_mapping_only || out2in_only))
1298  {
1299  for (i = 0; i < vec_len (sm->addresses); i++)
1300  {
1301  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1302  {
1303  a = sm->addresses + i;
1304  switch (proto)
1305  {
1306 #define _(N, j, n, s) \
1307  case SNAT_PROTOCOL_##N: \
1308  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1309  if (e_port > 1024) \
1310  { \
1311  a->busy_##n##_ports--; \
1312  a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1313  } \
1314  break;
1316 #undef _
1317  default:
1318  clib_warning("unknown_protocol");
1319  return VNET_API_ERROR_INVALID_VALUE_2;
1320  }
1321  break;
1322  }
1323  }
1324  }
1325 
1327  m_key.addr = m->external_addr;
1328  m_key.port = m->external_port;
1329  m_key.protocol = m->proto;
1330  m_key.fib_index = sm->outside_fib_index;
1331  kv.key = m_key.as_u64;
1332  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1333  {
1334  clib_warning ("static_mapping_by_external key del failed");
1335  return VNET_API_ERROR_UNSPECIFIED;
1336  }
1337 
1338  m_key.port = clib_host_to_net_u16 (m->external_port);
1339  kv.key = m_key.as_u64;
1340  if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1341  {
1342  clib_warning ("outi2in key del failed");
1343  return VNET_API_ERROR_UNSPECIFIED;
1344  }
1345 
1346  vec_foreach (local, m->locals)
1347  {
1348  m_key.addr = local->addr;
1349  if (!out2in_only)
1350  {
1351  m_key.port = local->port;
1352  m_key.fib_index = m->fib_index;
1353  kv.key = m_key.as_u64;
1354  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1355  {
1356  clib_warning ("static_mapping_by_local key del failed");
1357  return VNET_API_ERROR_UNSPECIFIED;
1358  }
1359  }
1360 
1361  if (!lb_local_exists(local, &e_addr, e_port))
1362  {
1363  m_key.port = clib_host_to_net_u16 (local->port);
1364  kv.key = m_key.as_u64;
1365  if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1366  {
1367  clib_warning ("in2out key del failed");
1368  return VNET_API_ERROR_UNSPECIFIED;
1369  }
1370  }
1371  /* Delete sessions */
1372  u_key.addr = local->addr;
1373  u_key.fib_index = m->fib_index;
1374  kv.key = u_key.as_u64;
1375  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1376  {
1377  u = pool_elt_at_index (tsm->users, value.value);
1378  if (u->nstaticsessions)
1379  {
1380  head_index = u->sessions_per_user_list_head_index;
1381  head = pool_elt_at_index (tsm->list_pool, head_index);
1382  elt_index = head->next;
1383  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1384  ses_index = elt->value;
1385  while (ses_index != ~0)
1386  {
1387  s = pool_elt_at_index (tsm->sessions, ses_index);
1388  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1389  ses_index = elt->value;
1390 
1391  if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
1392  (clib_net_to_host_u16 (s->in2out.port) != local->port))
1393  continue;
1394 
1395  nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1396  clib_dlist_remove (tsm->list_pool, s->per_user_index);
1397  pool_put_index (tsm->list_pool, s->per_user_index);
1398  pool_put (tsm->sessions, s);
1399  u->nstaticsessions--;
1400  }
1401  }
1402  }
1403  }
1404  vec_free(m->locals);
1405  vec_free(m->tag);
1406 
1407  pool_put (sm->static_mappings, m);
1408  }
1409 
1410  return 0;
1411 }
1412 
1413 int
1415  u8 twice_nat)
1416 {
1417  snat_address_t *a = 0;
1418  snat_session_t *ses;
1419  u32 *ses_to_be_removed = 0, *ses_index;
1420  clib_bihash_kv_8_8_t kv, value;
1421  snat_user_key_t user_key;
1422  snat_user_t *u;
1425  snat_interface_t *interface;
1426  int i;
1427  snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1428 
1429  /* Find SNAT address */
1430  for (i=0; i < vec_len (addresses); i++)
1431  {
1432  if (addresses[i].addr.as_u32 == addr.as_u32)
1433  {
1434  a = addresses + i;
1435  break;
1436  }
1437  }
1438  if (!a)
1439  return VNET_API_ERROR_NO_SUCH_ENTRY;
1440 
1441  if (delete_sm)
1442  {
1443  pool_foreach (m, sm->static_mappings,
1444  ({
1445  if (m->external_addr.as_u32 == addr.as_u32)
1446  (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1447  m->local_port, m->external_port,
1448  m->vrf_id, m->addr_only, ~0,
1449  m->proto, 0, m->twice_nat,
1450  m->out2in_only, m->tag);
1451  }));
1452  }
1453  else
1454  {
1455  /* Check if address is used in some static mapping */
1457  {
1458  clib_warning ("address used in static mapping");
1459  return VNET_API_ERROR_UNSPECIFIED;
1460  }
1461  }
1462 
1463  if (a->fib_index != ~0)
1466 
1467  /* Delete sessions using address */
1468  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1469  {
1470  vec_foreach (tsm, sm->per_thread_data)
1471  {
1472  pool_foreach (ses, tsm->sessions, ({
1473  if (ses->out2in.addr.as_u32 == addr.as_u32)
1474  {
1475  ses->outside_address_index = ~0;
1476  nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1477  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1478  pool_put_index (tsm->list_pool, ses->per_user_index);
1479  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1480  user_key.addr = ses->in2out.addr;
1481  user_key.fib_index = ses->in2out.fib_index;
1482  kv.key = user_key.as_u64;
1483  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1484  {
1485  u = pool_elt_at_index (tsm->users, value.value);
1486  u->nsessions--;
1487  }
1488  }
1489  }));
1490 
1491  vec_foreach (ses_index, ses_to_be_removed)
1492  pool_put_index (tsm->sessions, ses_index[0]);
1493 
1494  vec_free (ses_to_be_removed);
1495  }
1496  }
1497 
1498  if (twice_nat)
1499  {
1500  vec_del1 (sm->twice_nat_addresses, i);
1501  return 0;
1502  }
1503  else
1504  vec_del1 (sm->addresses, i);
1505 
1506  /* Delete external address from FIB */
1507  pool_foreach (interface, sm->interfaces,
1508  ({
1509  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1510  continue;
1511 
1512  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1513  break;
1514  }));
1515  pool_foreach (interface, sm->output_feature_interfaces,
1516  ({
1517  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1518  continue;
1519 
1520  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1521  break;
1522  }));
1523 
1524  return 0;
1525 }
1526 
1527 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1528 {
1529  snat_main_t *sm = &snat_main;
1531  const char * feature_name, *del_feature_name;
1532  snat_address_t * ap;
1534  snat_det_map_t * dm;
1535 
1536  if (sm->out2in_dpo && !is_inside)
1537  return VNET_API_ERROR_UNSUPPORTED;
1538 
1540  ({
1541  if (i->sw_if_index == sw_if_index)
1542  return VNET_API_ERROR_VALUE_EXIST;
1543  }));
1544 
1546  feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1547  else
1548  {
1549  if (sm->num_workers > 1 && !sm->deterministic)
1550  feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1551  else if (sm->deterministic)
1552  feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1553  else
1554  feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1555  }
1556 
1557  if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1559 
1560  if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1562 
1563  pool_foreach (i, sm->interfaces,
1564  ({
1565  if (i->sw_if_index == sw_if_index)
1566  {
1567  if (is_del)
1568  {
1569  if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1570  {
1571  if (is_inside)
1572  i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1573  else
1574  i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1575 
1576  if (sm->num_workers > 1 && !sm->deterministic)
1577  {
1578  del_feature_name = "nat44-handoff-classify";
1579  feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1580  "nat44-out2in-worker-handoff";
1581  }
1582  else if (sm->deterministic)
1583  {
1584  del_feature_name = "nat44-det-classify";
1585  feature_name = !is_inside ? "nat44-det-in2out" :
1586  "nat44-det-out2in";
1587  }
1588  else
1589  {
1590  del_feature_name = "nat44-classify";
1591  feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1592  }
1593 
1594  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1595  sw_if_index, 0, 0, 0);
1596  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1597  sw_if_index, 1, 0, 0);
1598  }
1599  else
1600  {
1601  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1602  sw_if_index, 0, 0, 0);
1603  pool_put (sm->interfaces, i);
1604  }
1605  }
1606  else
1607  {
1608  if ((nat_interface_is_inside(i) && is_inside) ||
1609  (nat_interface_is_outside(i) && !is_inside))
1610  return 0;
1611 
1612  if (sm->num_workers > 1 && !sm->deterministic)
1613  {
1614  del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1615  "nat44-out2in-worker-handoff";
1616  feature_name = "nat44-handoff-classify";
1617  }
1618  else if (sm->deterministic)
1619  {
1620  del_feature_name = !is_inside ? "nat44-det-in2out" :
1621  "nat44-det-out2in";
1622  feature_name = "nat44-det-classify";
1623  }
1624  else
1625  {
1626  del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1627  feature_name = "nat44-classify";
1628  }
1629 
1630  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1631  sw_if_index, 0, 0, 0);
1632  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1633  sw_if_index, 1, 0, 0);
1634  goto set_flags;
1635  }
1636 
1637  goto fib;
1638  }
1639  }));
1640 
1641  if (is_del)
1642  return VNET_API_ERROR_NO_SUCH_ENTRY;
1643 
1644  pool_get (sm->interfaces, i);
1645  i->sw_if_index = sw_if_index;
1646  i->flags = 0;
1647  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1648 
1649 set_flags:
1650  if (is_inside)
1651  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1652  else
1653  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1654 
1655  /* Add/delete external addresses to FIB */
1656 fib:
1657  if (is_inside && !sm->out2in_dpo)
1658  {
1659  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1660  sw_if_index, !is_del, 0, 0);
1661  return 0;
1662  }
1663 
1664  vec_foreach (ap, sm->addresses)
1665  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1666 
1667  pool_foreach (m, sm->static_mappings,
1668  ({
1669  if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1670  continue;
1671 
1672  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1673  }));
1674 
1675  pool_foreach (dm, sm->det_maps,
1676  ({
1677  snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1678  }));
1679 
1680  return 0;
1681 }
1682 
1684  u8 is_inside,
1685  int is_del)
1686 {
1687  snat_main_t *sm = &snat_main;
1689  snat_address_t * ap;
1691 
1692  if (sm->deterministic ||
1694  return VNET_API_ERROR_UNSUPPORTED;
1695 
1696  pool_foreach (i, sm->interfaces,
1697  ({
1698  if (i->sw_if_index == sw_if_index)
1699  return VNET_API_ERROR_VALUE_EXIST;
1700  }));
1701 
1702  if (is_inside)
1703  {
1704  vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1705  sw_if_index, !is_del, 0, 0);
1706  vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1707  sw_if_index, !is_del, 0, 0);
1708  goto fq;
1709  }
1710 
1711  if (sm->num_workers > 1)
1712  {
1713  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1714  sw_if_index, !is_del, 0, 0);
1715  vnet_feature_enable_disable ("ip4-output",
1716  "nat44-in2out-output-worker-handoff",
1717  sw_if_index, !is_del, 0, 0);
1718  }
1719  else
1720  {
1721  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1722  !is_del, 0, 0);
1723  vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1724  sw_if_index, !is_del, 0, 0);
1725  }
1726 
1727 fq:
1728  if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1731 
1732  if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1734 
1736  ({
1737  if (i->sw_if_index == sw_if_index)
1738  {
1739  if (is_del)
1740  pool_put (sm->output_feature_interfaces, i);
1741  else
1742  return VNET_API_ERROR_VALUE_EXIST;
1743 
1744  goto fib;
1745  }
1746  }));
1747 
1748  if (is_del)
1749  return VNET_API_ERROR_NO_SUCH_ENTRY;
1750 
1751  pool_get (sm->output_feature_interfaces, i);
1752  i->sw_if_index = sw_if_index;
1753  i->flags = 0;
1754  if (is_inside)
1755  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1756  else
1757  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1758 
1759  /* Add/delete external addresses to FIB */
1760 fib:
1761  if (is_inside)
1762  return 0;
1763 
1764  vec_foreach (ap, sm->addresses)
1765  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1766 
1767  pool_foreach (m, sm->static_mappings,
1768  ({
1769  if (!(m->addr_only))
1770  continue;
1771 
1772  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1773  }));
1774 
1775  return 0;
1776 }
1777 
1778 int snat_set_workers (uword * bitmap)
1779 {
1780  snat_main_t *sm = &snat_main;
1781  int i, j = 0;
1782 
1783  if (sm->num_workers < 2)
1784  return VNET_API_ERROR_FEATURE_DISABLED;
1785 
1786  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1787  return VNET_API_ERROR_INVALID_WORKER;
1788 
1789  vec_free (sm->workers);
1790  clib_bitmap_foreach (i, bitmap,
1791  ({
1792  vec_add1(sm->workers, i);
1794  j++;
1795  }));
1796 
1797  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1798  sm->num_snat_thread = _vec_len (sm->workers);
1799 
1800  return 0;
1801 }
1802 
1803 
1804 static void
1806  uword opaque,
1807  u32 sw_if_index,
1808  ip4_address_t * address,
1809  u32 address_length,
1810  u32 if_address_index,
1811  u32 is_delete);
1812 
1813 static void
1815  uword opaque,
1816  u32 sw_if_index,
1817  ip4_address_t * address,
1818  u32 address_length,
1819  u32 if_address_index,
1820  u32 is_delete);
1821 
1822 static int
1824  u32 fib_index,
1825  u32 thread_index,
1826  snat_session_key_t * k,
1827  u32 * address_indexp,
1828  u16 port_per_thread,
1829  u32 snat_thread_index);
1830 
1832 {
1833  snat_main_t * sm = &snat_main;
1834  clib_error_t * error = 0;
1835  ip4_main_t * im = &ip4_main;
1836  ip_lookup_main_t * lm = &im->lookup_main;
1837  uword *p;
1840  uword *bitmap = 0;
1841  u32 i;
1843 
1844  sm->vlib_main = vm;
1845  sm->vnet_main = vnet_get_main();
1846  sm->ip4_main = im;
1847  sm->ip4_lookup_main = lm;
1848  sm->api_main = &api_main;
1849  sm->first_worker_index = 0;
1850  sm->next_worker = 0;
1851  sm->num_workers = 0;
1852  sm->num_snat_thread = 1;
1853  sm->workers = 0;
1854  sm->port_per_thread = 0xffff - 1024;
1855  sm->fq_in2out_index = ~0;
1856  sm->fq_out2in_index = ~0;
1862  sm->forwarding_enabled = 0;
1863 
1864  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1865  if (p)
1866  {
1867  tr = (vlib_thread_registration_t *) p[0];
1868  if (tr)
1869  {
1870  sm->num_workers = tr->count;
1871  sm->first_worker_index = tr->first_index;
1872  }
1873  }
1874 
1875  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1876 
1877  /* Use all available workers by default */
1878  if (sm->num_workers > 1)
1879  {
1880  for (i=0; i < sm->num_workers; i++)
1881  bitmap = clib_bitmap_set (bitmap, i, 1);
1882  snat_set_workers(bitmap);
1883  clib_bitmap_free (bitmap);
1884  }
1885  else
1886  {
1888  }
1889 
1890  error = snat_api_init(vm, sm);
1891  if (error)
1892  return error;
1893 
1894  /* Set up the interface address add/del callback */
1896  cb4.function_opaque = 0;
1897 
1899 
1901  cb4.function_opaque = 0;
1902 
1904 
1906 
1907  /* Init IPFIX logging */
1909 
1910  /* Init NAT64 */
1911  error = nat64_init(vm);
1912  if (error)
1913  return error;
1914 
1915  dslite_init(vm);
1916 
1917  nat66_init();
1918 
1919  /* Init virtual fragmenentation reassembly */
1920  return nat_reass_init(vm);
1921 }
1922 
1924 
1926  u32 thread_index,
1927  snat_session_key_t * k,
1928  u32 address_index)
1929 {
1930  snat_address_t *a;
1931  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1932 
1933  ASSERT (address_index < vec_len (addresses));
1934 
1935  a = addresses + address_index;
1936 
1937  switch (k->protocol)
1938  {
1939 #define _(N, i, n, s) \
1940  case SNAT_PROTOCOL_##N: \
1941  ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1942  port_host_byte_order) == 1); \
1943  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1944  port_host_byte_order, 0); \
1945  a->busy_##n##_ports--; \
1946  a->busy_##n##_ports_per_thread[thread_index]--; \
1947  break;
1949 #undef _
1950  default:
1951  clib_warning("unknown_protocol");
1952  return;
1953  }
1954 }
1955 
1956 /**
1957  * @brief Match NAT44 static mapping.
1958  *
1959  * @param sm NAT main.
1960  * @param match Address and port to match.
1961  * @param mapping External or local address and port of the matched mapping.
1962  * @param by_external If 0 match by local address otherwise match by external
1963  * address.
1964  * @param is_addr_only If matched mapping is address only
1965  * @param twice_nat If matched mapping is twice NAT.
1966  *
1967  * @returns 0 if match found otherwise 1.
1968  */
1970  snat_session_key_t match,
1971  snat_session_key_t * mapping,
1972  u8 by_external,
1973  u8 *is_addr_only,
1974  u8 *twice_nat)
1975 {
1976  clib_bihash_kv_8_8_t kv, value;
1978  snat_session_key_t m_key;
1979  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1980  u32 rand, lo = 0, hi, mid;
1981 
1982  if (by_external)
1983  mapping_hash = &sm->static_mapping_by_external;
1984 
1985  m_key.addr = match.addr;
1986  m_key.port = clib_net_to_host_u16 (match.port);
1987  m_key.protocol = match.protocol;
1988  m_key.fib_index = match.fib_index;
1989 
1990  kv.key = m_key.as_u64;
1991 
1992  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1993  {
1994  /* Try address only mapping */
1995  m_key.port = 0;
1996  m_key.protocol = 0;
1997  kv.key = m_key.as_u64;
1998  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1999  return 1;
2000  }
2001 
2002  m = pool_elt_at_index (sm->static_mappings, value.value);
2003 
2004  if (by_external)
2005  {
2006  if (vec_len (m->locals))
2007  {
2008  hi = vec_len (m->locals) - 1;
2009  rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2010  while (lo < hi)
2011  {
2012  mid = ((hi - lo) >> 1) + lo;
2013  (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2014  }
2015  if (!(m->locals[lo].prefix >= rand))
2016  return 1;
2017  mapping->addr = m->locals[lo].addr;
2018  mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2019  }
2020  else
2021  {
2022  mapping->addr = m->local_addr;
2023  /* Address only mapping doesn't change port */
2024  mapping->port = m->addr_only ? match.port
2025  : clib_host_to_net_u16 (m->local_port);
2026  }
2027  mapping->fib_index = m->fib_index;
2028  mapping->protocol = m->proto;
2029  }
2030  else
2031  {
2032  mapping->addr = m->external_addr;
2033  /* Address only mapping doesn't change port */
2034  mapping->port = m->addr_only ? match.port
2035  : clib_host_to_net_u16 (m->external_port);
2036  mapping->fib_index = sm->outside_fib_index;
2037  }
2038 
2039  if (PREDICT_FALSE(is_addr_only != 0))
2040  *is_addr_only = m->addr_only;
2041 
2042  if (PREDICT_FALSE(twice_nat != 0))
2043  *twice_nat = m->twice_nat;
2044 
2045  return 0;
2046 }
2047 
2050 {
2051  snat_main_t *sm = &snat_main;
2052  return min + random_u32 (&sm->random_seed) /
2053  (random_u32_max() / (max - min + 1) + 1);
2054 }
2055 
2056 int
2058  u32 fib_index,
2059  u32 thread_index,
2060  snat_session_key_t * k,
2061  u32 * address_indexp,
2062  u16 port_per_thread,
2063  u32 snat_thread_index)
2064 {
2065  snat_main_t *sm = &snat_main;
2066 
2067  return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
2068  address_indexp, port_per_thread,
2069  snat_thread_index);
2070 }
2071 
2072 static int
2074  u32 fib_index,
2075  u32 thread_index,
2076  snat_session_key_t * k,
2077  u32 * address_indexp,
2078  u16 port_per_thread,
2079  u32 snat_thread_index)
2080 {
2081  int i, gi = 0;
2082  snat_address_t *a, *ga = 0;
2083  u32 portnum;
2084 
2085  for (i = 0; i < vec_len (addresses); i++)
2086  {
2087  a = addresses + i;
2088  switch (k->protocol)
2089  {
2090 #define _(N, j, n, s) \
2091  case SNAT_PROTOCOL_##N: \
2092  if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2093  { \
2094  if (a->fib_index == fib_index) \
2095  { \
2096  while (1) \
2097  { \
2098  portnum = (port_per_thread * \
2099  snat_thread_index) + \
2100  snat_random_port(1, port_per_thread) + 1024; \
2101  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2102  continue; \
2103  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2104  a->busy_##n##_ports_per_thread[thread_index]++; \
2105  a->busy_##n##_ports++; \
2106  k->addr = a->addr; \
2107  k->port = clib_host_to_net_u16(portnum); \
2108  *address_indexp = i; \
2109  return 0; \
2110  } \
2111  } \
2112  else if (a->fib_index == ~0) \
2113  { \
2114  ga = a; \
2115  gi = i; \
2116  } \
2117  } \
2118  break;
2120 #undef _
2121  default:
2122  clib_warning("unknown protocol");
2123  return 1;
2124  }
2125 
2126  }
2127 
2128  if (ga)
2129  {
2130  a = ga;
2131  switch (k->protocol)
2132  {
2133 #define _(N, j, n, s) \
2134  case SNAT_PROTOCOL_##N: \
2135  while (1) \
2136  { \
2137  portnum = (port_per_thread * \
2138  snat_thread_index) + \
2139  snat_random_port(1, port_per_thread) + 1024; \
2140  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2141  continue; \
2142  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2143  a->busy_##n##_ports_per_thread[thread_index]++; \
2144  a->busy_##n##_ports++; \
2145  k->addr = a->addr; \
2146  k->port = clib_host_to_net_u16(portnum); \
2147  *address_indexp = gi; \
2148  return 0; \
2149  }
2150  break;
2152 #undef _
2153  default:
2154  clib_warning ("unknown protocol");
2155  return 1;
2156  }
2157  }
2158 
2159  /* Totally out of translations to use... */
2161  return 1;
2162 }
2163 
2164 static int
2166  u32 fib_index,
2167  u32 thread_index,
2168  snat_session_key_t * k,
2169  u32 * address_indexp,
2170  u16 port_per_thread,
2171  u32 snat_thread_index)
2172 {
2173  snat_main_t *sm = &snat_main;
2174  snat_address_t *a = addresses;
2175  u16 m, ports, portnum, A, j;
2176  m = 16 - (sm->psid_offset + sm->psid_length);
2177  ports = (1 << (16 - sm->psid_length)) - (1 << m);
2178 
2179  if (!vec_len (addresses))
2180  goto exhausted;
2181 
2182  switch (k->protocol)
2183  {
2184 #define _(N, i, n, s) \
2185  case SNAT_PROTOCOL_##N: \
2186  if (a->busy_##n##_ports < ports) \
2187  { \
2188  while (1) \
2189  { \
2190  A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2191  j = snat_random_port(0, pow2_mask(m)); \
2192  portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2193  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2194  continue; \
2195  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2196  a->busy_##n##_ports++; \
2197  k->addr = a->addr; \
2198  k->port = clib_host_to_net_u16 (portnum); \
2199  *address_indexp = i; \
2200  return 0; \
2201  } \
2202  } \
2203  break;
2205 #undef _
2206  default:
2207  clib_warning("unknown protocol");
2208  return 1;
2209  }
2210 
2211 exhausted:
2212  /* Totally out of translations to use... */
2214  return 1;
2215 }
2216 
2217 void
2219 {
2220  dpo_id_t dpo_v4 = DPO_INVALID;
2221  fib_prefix_t pfx = {
2223  .fp_len = 32,
2224  .fp_addr.ip4.as_u32 = addr.as_u32,
2225  };
2226 
2227  if (is_add)
2228  {
2229  nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2231  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2232  dpo_reset (&dpo_v4);
2233  }
2234  else
2235  {
2237  }
2238 }
2239 
2240 uword
2241 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2242 {
2243  u32 *r = va_arg (*args, u32 *);
2244 
2245  if (0);
2246 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2248 #undef _
2249  else
2250  return 0;
2251  return 1;
2252 }
2253 
2254 u8 *
2255 format_snat_protocol (u8 * s, va_list * args)
2256 {
2257  u32 i = va_arg (*args, u32);
2258  u8 *t = 0;
2259 
2260  switch (i)
2261  {
2262 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2264 #undef _
2265  default:
2266  s = format (s, "unknown");
2267  return s;
2268  }
2269  s = format (s, "%s", t);
2270  return s;
2271 }
2272 
2273 static u32
2275 {
2276  snat_main_t *sm = &snat_main;
2277  u32 next_worker_index = 0;
2278  u32 hash;
2279 
2280  next_worker_index = sm->first_worker_index;
2281  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2282  (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2283 
2284  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2285  next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2286  else
2287  next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2288 
2289  return next_worker_index;
2290 }
2291 
2292 static u32
2294 {
2295  snat_main_t *sm = &snat_main;
2296  udp_header_t *udp;
2297  u16 port;
2298  snat_session_key_t m_key;
2299  clib_bihash_kv_8_8_t kv, value;
2301  nat_ed_ses_key_t key;
2302  clib_bihash_kv_16_8_t s_kv, s_value;
2304  snat_session_t *s;
2305  int i;
2306  u32 proto;
2307  u32 next_worker_index = 0;
2308 
2309  /* first try static mappings without port */
2311  {
2312  m_key.addr = ip0->dst_address;
2313  m_key.port = 0;
2314  m_key.protocol = 0;
2315  m_key.fib_index = rx_fib_index0;
2316  kv.key = m_key.as_u64;
2317  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2318  {
2319  m = pool_elt_at_index (sm->static_mappings, value.value);
2320  return m->worker_index;
2321  }
2322  }
2323 
2324  proto = ip_proto_to_snat_proto (ip0->protocol);
2325  udp = ip4_next_header (ip0);
2326  port = udp->dst_port;
2327 
2328  if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2329  {
2331  return vlib_get_thread_index ();
2332 
2333  if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2334  {
2335  nat_reass_ip4_t *reass;
2336 
2337  reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2338  ip0->fragment_id, ip0->protocol);
2339 
2340  if (reass && (reass->thread_index != (u32) ~ 0))
2341  return reass->thread_index;
2342  else
2343  return vlib_get_thread_index ();
2344  }
2345  }
2346 
2347  /* unknown protocol */
2348  if (PREDICT_FALSE (proto == ~0))
2349  {
2350  key.l_addr = ip0->dst_address;
2351  key.r_addr = ip0->src_address;
2352  key.fib_index = rx_fib_index0;
2353  key.proto = ip0->protocol;
2354  key.r_port = 0;
2355  key.l_port = 0;
2356  s_kv.key[0] = key.as_u64[0];
2357  s_kv.key[1] = key.as_u64[1];
2358 
2359  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2360  {
2361  for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2362  {
2363  tsm = vec_elt_at_index (sm->per_thread_data, i);
2364  if (!pool_is_free_index(tsm->sessions, s_value.value))
2365  {
2366  s = pool_elt_at_index (tsm->sessions, s_value.value);
2367  if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2368  s->out2in.port == ip0->protocol &&
2370  return i;
2371  }
2372  }
2373  }
2374 
2375  /* if no session use current thread */
2376  return vlib_get_thread_index ();
2377  }
2378 
2379  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2380  {
2381  icmp46_header_t * icmp = (icmp46_header_t *) udp;
2382  icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2383  if (!icmp_is_error_message (icmp))
2384  port = echo->identifier;
2385  else
2386  {
2387  ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2388  proto = ip_proto_to_snat_proto (inner_ip->protocol);
2389  void *l4_header = ip4_next_header (inner_ip);
2390  switch (proto)
2391  {
2392  case SNAT_PROTOCOL_ICMP:
2393  icmp = (icmp46_header_t*)l4_header;
2394  echo = (icmp_echo_header_t *)(icmp + 1);
2395  port = echo->identifier;
2396  break;
2397  case SNAT_PROTOCOL_UDP:
2398  case SNAT_PROTOCOL_TCP:
2399  port = ((tcp_udp_header_t*)l4_header)->src_port;
2400  break;
2401  default:
2402  return vlib_get_thread_index ();
2403  }
2404  }
2405  }
2406 
2407  /* try static mappings with port */
2408  if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2409  {
2410  m_key.addr = ip0->dst_address;
2411  m_key.port = clib_net_to_host_u16 (port);
2412  m_key.protocol = proto;
2413  m_key.fib_index = rx_fib_index0;
2414  kv.key = m_key.as_u64;
2415  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2416  {
2417  m = pool_elt_at_index (sm->static_mappings, value.value);
2418  return m->worker_index;
2419  }
2420  }
2421 
2422  /* worker by outside port */
2423  next_worker_index = sm->first_worker_index;
2424  next_worker_index +=
2425  sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2426  return next_worker_index;
2427 }
2428 
2429 static clib_error_t *
2431 {
2432  snat_main_t * sm = &snat_main;
2433  nat66_main_t * nm = &nat66_main;
2434  u32 translation_buckets = 1024;
2435  u32 translation_memory_size = 128<<20;
2436  u32 user_buckets = 128;
2437  u32 user_memory_size = 64<<20;
2438  u32 max_translations_per_user = 100;
2439  u32 outside_vrf_id = 0;
2440  u32 outside_ip6_vrf_id = 0;
2441  u32 inside_vrf_id = 0;
2442  u32 static_mapping_buckets = 1024;
2443  u32 static_mapping_memory_size = 64<<20;
2444  u32 nat64_bib_buckets = 1024;
2445  u32 nat64_bib_memory_size = 128 << 20;
2446  u32 nat64_st_buckets = 2048;
2447  u32 nat64_st_memory_size = 256 << 20;
2448  u8 static_mapping_only = 0;
2449  u8 static_mapping_connection_tracking = 0;
2451  dslite_main_t * dm = &dslite_main;
2452 
2453  sm->deterministic = 0;
2454  sm->out2in_dpo = 0;
2455 
2456  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2457  {
2458  if (unformat (input, "translation hash buckets %d", &translation_buckets))
2459  ;
2460  else if (unformat (input, "translation hash memory %d",
2461  &translation_memory_size));
2462  else if (unformat (input, "user hash buckets %d", &user_buckets))
2463  ;
2464  else if (unformat (input, "user hash memory %d",
2465  &user_memory_size))
2466  ;
2467  else if (unformat (input, "max translations per user %d",
2468  &max_translations_per_user))
2469  ;
2470  else if (unformat (input, "outside VRF id %d",
2471  &outside_vrf_id))
2472  ;
2473  else if (unformat (input, "outside ip6 VRF id %d",
2474  &outside_ip6_vrf_id))
2475  ;
2476  else if (unformat (input, "inside VRF id %d",
2477  &inside_vrf_id))
2478  ;
2479  else if (unformat (input, "static mapping only"))
2480  {
2481  static_mapping_only = 1;
2482  if (unformat (input, "connection tracking"))
2483  static_mapping_connection_tracking = 1;
2484  }
2485  else if (unformat (input, "deterministic"))
2486  sm->deterministic = 1;
2487  else if (unformat (input, "nat64 bib hash buckets %d",
2488  &nat64_bib_buckets))
2489  ;
2490  else if (unformat (input, "nat64 bib hash memory %d",
2491  &nat64_bib_memory_size))
2492  ;
2493  else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2494  ;
2495  else if (unformat (input, "nat64 st hash memory %d",
2496  &nat64_st_memory_size))
2497  ;
2498  else if (unformat (input, "out2in dpo"))
2499  sm->out2in_dpo = 1;
2500  else if (unformat (input, "dslite ce"))
2501  dslite_set_ce(dm, 1);
2502  else
2503  return clib_error_return (0, "unknown input '%U'",
2504  format_unformat_error, input);
2505  }
2506 
2507  /* for show commands, etc. */
2508  sm->translation_buckets = translation_buckets;
2509  sm->translation_memory_size = translation_memory_size;
2510  /* do not exceed load factor 10 */
2511  sm->max_translations = 10 * translation_buckets;
2512  sm->user_buckets = user_buckets;
2513  sm->user_memory_size = user_memory_size;
2514  sm->max_translations_per_user = max_translations_per_user;
2515  sm->outside_vrf_id = outside_vrf_id;
2517  outside_vrf_id,
2519  nm->outside_vrf_id = outside_ip6_vrf_id;
2521  outside_ip6_vrf_id,
2523  sm->inside_vrf_id = inside_vrf_id;
2525  inside_vrf_id,
2527  sm->static_mapping_only = static_mapping_only;
2528  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2529 
2530  nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2531  nat64_st_memory_size);
2532 
2533  if (sm->deterministic)
2534  {
2536  sm->in2out_output_node_index = ~0;
2540  }
2541  else
2542  {
2545  sm->in2out_node_index = snat_in2out_node.index;
2547  sm->out2in_node_index = snat_out2in_node.index;
2548  if (!static_mapping_only ||
2549  (static_mapping_only && static_mapping_connection_tracking))
2550  {
2553 
2554  vec_foreach (tsm, sm->per_thread_data)
2555  {
2556  clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2557  translation_memory_size);
2558 
2559  clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2560  translation_memory_size);
2561 
2562  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2563  user_memory_size);
2564  }
2565 
2566  clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2567  translation_buckets, translation_memory_size);
2568 
2569  clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2570  translation_buckets, translation_memory_size);
2571  }
2572  else
2573  {
2576  }
2577  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2578  "static_mapping_by_local", static_mapping_buckets,
2579  static_mapping_memory_size);
2580 
2581  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2582  "static_mapping_by_external", static_mapping_buckets,
2583  static_mapping_memory_size);
2584  }
2585 
2586  return 0;
2587 }
2588 
2590 
2591 u8 * format_snat_session_state (u8 * s, va_list * args)
2592 {
2593  u32 i = va_arg (*args, u32);
2594  u8 *t = 0;
2595 
2596  switch (i)
2597  {
2598 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2600 #undef _
2601  default:
2602  t = format (t, "unknown");
2603  }
2604  s = format (s, "%s", t);
2605  return s;
2606 }
2607 
2608 u8 * format_snat_key (u8 * s, va_list * args)
2609 {
2610  snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2611 
2612  s = format (s, "%U proto %U port %d fib %d",
2613  format_ip4_address, &key->addr,
2615  clib_net_to_host_u16 (key->port), key->fib_index);
2616  return s;
2617 }
2618 
2619 u8 * format_snat_session (u8 * s, va_list * args)
2620 {
2621  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2622  snat_session_t * sess = va_arg (*args, snat_session_t *);
2623 
2624  if (snat_is_unk_proto_session (sess))
2625  {
2626  s = format (s, " i2o %U proto %u fib %u\n",
2627  format_ip4_address, &sess->in2out.addr,
2628  clib_net_to_host_u16 (sess->in2out.port),
2629  sess->in2out.fib_index);
2630  s = format (s, " o2i %U proto %u fib %u\n",
2631  format_ip4_address, &sess->out2in.addr,
2632  clib_net_to_host_u16 (sess->out2in.port),
2633  sess->out2in.fib_index);
2634  }
2635  else
2636  {
2637  s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2638  s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2639  }
2640  if (is_twice_nat_session (sess))
2641  {
2642  s = format (s, " external host o2i %U:%d i2o %U:%d\n",
2643  format_ip4_address, &sess->ext_host_addr,
2644  clib_net_to_host_u16 (sess->ext_host_port),
2645  format_ip4_address, &sess->ext_host_nat_addr,
2646  clib_net_to_host_u16 (sess->ext_host_nat_port));
2647  }
2648  else
2649  {
2650  if (sess->ext_host_addr.as_u32)
2651  s = format (s, " external host %U\n",
2652  format_ip4_address, &sess->ext_host_addr);
2653  }
2654  s = format (s, " last heard %.2f\n", sess->last_heard);
2655  s = format (s, " total pkts %d, total bytes %lld\n",
2656  sess->total_pkts, sess->total_bytes);
2657  if (snat_is_session_static (sess))
2658  s = format (s, " static translation\n");
2659  else
2660  s = format (s, " dynamic translation\n");
2661  if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2662  s = format (s, " load-balancing\n");
2663  if (is_twice_nat_session (sess))
2664  s = format (s, " twice-nat\n");
2665 
2666  return s;
2667 }
2668 
2669 u8 * format_snat_user (u8 * s, va_list * args)
2670 {
2672  snat_user_t * u = va_arg (*args, snat_user_t *);
2673  int verbose = va_arg (*args, int);
2674  dlist_elt_t * head, * elt;
2675  u32 elt_index, head_index;
2676  u32 session_index;
2677  snat_session_t * sess;
2678 
2679  s = format (s, "%U: %d dynamic translations, %d static translations\n",
2681 
2682  if (verbose == 0)
2683  return s;
2684 
2685  if (u->nsessions || u->nstaticsessions)
2686  {
2687  head_index = u->sessions_per_user_list_head_index;
2688  head = pool_elt_at_index (sm->list_pool, head_index);
2689 
2690  elt_index = head->next;
2691  elt = pool_elt_at_index (sm->list_pool, elt_index);
2692  session_index = elt->value;
2693 
2694  while (session_index != ~0)
2695  {
2696  sess = pool_elt_at_index (sm->sessions, session_index);
2697 
2698  s = format (s, " %U\n", format_snat_session, sm, sess);
2699 
2700  elt_index = elt->next;
2701  elt = pool_elt_at_index (sm->list_pool, elt_index);
2702  session_index = elt->value;
2703  }
2704  }
2705 
2706  return s;
2707 }
2708 
2709 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2710 {
2711  snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2712  nat44_lb_addr_port_t *local;
2713 
2714  if (m->addr_only)
2715  s = format (s, "local %U external %U vrf %d %s",
2718  m->vrf_id, m->twice_nat ? "twice-nat" : "");
2719  else
2720  {
2721  if (vec_len (m->locals))
2722  {
2723  s = format (s, "%U vrf %d external %U:%d %s %s",
2725  m->vrf_id,
2727  m->twice_nat ? "twice-nat" : "",
2728  m->out2in_only ? "out2in-only" : "");
2729  vec_foreach (local, m->locals)
2730  s = format (s, "\n local %U:%d probability %d\%",
2731  format_ip4_address, &local->addr, local->port,
2732  local->probability);
2733  }
2734  else
2735  s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
2739  m->vrf_id, m->twice_nat ? "twice-nat" : "",
2740  m->out2in_only ? "out2in-only" : "");
2741  }
2742  return s;
2743 }
2744 
2745 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2746 {
2748  vnet_main_t *vnm = vnet_get_main();
2749 
2750  if (m->addr_only)
2751  s = format (s, "local %U external %U vrf %d",
2754  m->vrf_id);
2755  else
2756  s = format (s, "%U local %U:%d external %U:%d vrf %d",
2758  format_ip4_address, &m->l_addr, m->l_port,
2760  m->e_port, m->vrf_id);
2761 
2762  return s;
2763 }
2764 
2765 u8 * format_det_map_ses (u8 * s, va_list * args)
2766 {
2767  snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2768  ip4_address_t in_addr, out_addr;
2769  u32 in_offset, out_offset;
2770  snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2771  u32 * i = va_arg (*args, u32 *);
2772 
2773  u32 user_index = *i / SNAT_DET_SES_PER_USER;
2774  in_addr.as_u32 = clib_host_to_net_u32 (
2775  clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2776  in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2777  clib_net_to_host_u32(det_map->in_addr.as_u32);
2778  out_offset = in_offset / det_map->sharing_ratio;
2779  out_addr.as_u32 = clib_host_to_net_u32(
2780  clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2781  s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2782  format_ip4_address, &in_addr,
2783  clib_net_to_host_u16 (ses->in_port),
2784  format_ip4_address, &out_addr,
2785  clib_net_to_host_u16 (ses->out.out_port),
2787  clib_net_to_host_u16 (ses->out.ext_host_port),
2789  ses->expire);
2790 
2791  return s;
2792 }
2793 
2794 static void
2796  uword opaque,
2797  u32 sw_if_index,
2798  ip4_address_t * address,
2799  u32 address_length,
2800  u32 if_address_index,
2801  u32 is_delete)
2802 {
2803  snat_main_t *sm = &snat_main;
2806  snat_session_key_t m_key;
2807  clib_bihash_kv_8_8_t kv, value;
2808  int i, rv;
2809  ip4_address_t l_addr;
2810 
2811  for (i = 0; i < vec_len (sm->to_resolve); i++)
2812  {
2813  rp = sm->to_resolve + i;
2814  if (rp->addr_only == 0)
2815  continue;
2816  if (rp->sw_if_index == sw_if_index)
2817  goto match;
2818  }
2819 
2820  return;
2821 
2822 match:
2823  m_key.addr.as_u32 = address->as_u32;
2824  m_key.port = rp->addr_only ? 0 : rp->e_port;
2825  m_key.protocol = rp->addr_only ? 0 : rp->proto;
2826  m_key.fib_index = sm->outside_fib_index;
2827  kv.key = m_key.as_u64;
2828  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2829  m = 0;
2830  else
2831  m = pool_elt_at_index (sm->static_mappings, value.value);
2832 
2833  if (!is_delete)
2834  {
2835  /* Don't trip over lease renewal, static config */
2836  if (m)
2837  return;
2838  }
2839  else
2840  {
2841  if (!m)
2842  return;
2843  }
2844 
2845  /* Indetity mapping? */
2846  if (rp->l_addr.as_u32 == 0)
2847  l_addr.as_u32 = address[0].as_u32;
2848  else
2849  l_addr.as_u32 = rp->l_addr.as_u32;
2850  /* Add the static mapping */
2851  rv = snat_add_static_mapping (l_addr,
2852  address[0],
2853  rp->l_port,
2854  rp->e_port,
2855  rp->vrf_id,
2856  rp->addr_only,
2857  ~0 /* sw_if_index */,
2858  rp->proto,
2859  !is_delete,
2860  0, 0, rp->tag);
2861  if (rv)
2862  clib_warning ("snat_add_static_mapping returned %d", rv);
2863 }
2864 
2865 static void
2867  uword opaque,
2868  u32 sw_if_index,
2869  ip4_address_t * address,
2870  u32 address_length,
2871  u32 if_address_index,
2872  u32 is_delete)
2873 {
2874  snat_main_t *sm = &snat_main;
2876  ip4_address_t l_addr;
2877  int i, j;
2878  int rv;
2879  u8 twice_nat = 0;
2880  snat_address_t *addresses = sm->addresses;
2881 
2882  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2883  {
2884  if (sw_if_index == sm->auto_add_sw_if_indices[i])
2885  goto match;
2886  }
2887 
2888  for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
2889  {
2890  twice_nat = 1;
2891  addresses = sm->twice_nat_addresses;
2892  if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
2893  goto match;
2894  }
2895 
2896  return;
2897 
2898 match:
2899  if (!is_delete)
2900  {
2901  /* Don't trip over lease renewal, static config */
2902  for (j = 0; j < vec_len(addresses); j++)
2903  if (addresses[j].addr.as_u32 == address->as_u32)
2904  return;
2905 
2906  snat_add_address (sm, address, ~0, twice_nat);
2907  /* Scan static map resolution vector */
2908  for (j = 0; j < vec_len (sm->to_resolve); j++)
2909  {
2910  rp = sm->to_resolve + j;
2911  if (rp->addr_only)
2912  continue;
2913  /* On this interface? */
2914  if (rp->sw_if_index == sw_if_index)
2915  {
2916  /* Indetity mapping? */
2917  if (rp->l_addr.as_u32 == 0)
2918  l_addr.as_u32 = address[0].as_u32;
2919  else
2920  l_addr.as_u32 = rp->l_addr.as_u32;
2921  /* Add the static mapping */
2922  rv = snat_add_static_mapping (l_addr,
2923  address[0],
2924  rp->l_port,
2925  rp->e_port,
2926  rp->vrf_id,
2927  rp->addr_only,
2928  ~0 /* sw_if_index */,
2929  rp->proto,
2930  rp->is_add,
2931  0, 0, rp->tag);
2932  if (rv)
2933  clib_warning ("snat_add_static_mapping returned %d",
2934  rv);
2935  }
2936  }
2937  return;
2938  }
2939  else
2940  {
2941  (void) snat_del_address(sm, address[0], 1, twice_nat);
2942  return;
2943  }
2944 }
2945 
2946 
2947 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
2948  u8 twice_nat)
2949 {
2950  ip4_main_t * ip4_main = sm->ip4_main;
2951  ip4_address_t * first_int_addr;
2953  u32 *indices_to_delete = 0;
2954  int i, j;
2955  u32 *auto_add_sw_if_indices =
2957 
2958  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2959  0 /* just want the address*/);
2960 
2961  for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
2962  {
2963  if (auto_add_sw_if_indices[i] == sw_if_index)
2964  {
2965  if (is_del)
2966  {
2967  /* if have address remove it */
2968  if (first_int_addr)
2969  (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
2970  else
2971  {
2972  for (j = 0; j < vec_len (sm->to_resolve); j++)
2973  {
2974  rp = sm->to_resolve + j;
2975  if (rp->sw_if_index == sw_if_index)
2976  vec_add1 (indices_to_delete, j);
2977  }
2978  if (vec_len(indices_to_delete))
2979  {
2980  for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2981  vec_del1(sm->to_resolve, j);
2982  vec_free(indices_to_delete);
2983  }
2984  }
2985  if (twice_nat)
2987  else
2989  }
2990  else
2991  return VNET_API_ERROR_VALUE_EXIST;
2992 
2993  return 0;
2994  }
2995  }
2996 
2997  if (is_del)
2998  return VNET_API_ERROR_NO_SUCH_ENTRY;
2999 
3000  /* add to the auto-address list */
3001  if (twice_nat)
3002  vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3003  else
3004  vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3005 
3006  /* If the address is already bound - or static - add it now */
3007  if (first_int_addr)
3008  snat_add_address (sm, first_int_addr, ~0, twice_nat);
3009 
3010  return 0;
3011 }
3012 
3013 int
3015  snat_protocol_t proto, u32 vrf_id, int is_in)
3016 {
3018  clib_bihash_kv_8_8_t kv, value;
3019  ip4_header_t ip;
3020  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3021  snat_session_key_t key;
3022  snat_session_t *s;
3023  clib_bihash_8_8_t *t;
3024  snat_user_key_t u_key;
3025  snat_user_t *u;
3026 
3027  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3028  if (sm->num_workers > 1)
3029  tsm =
3031  sm->worker_in2out_cb (&ip, fib_index));
3032  else
3033  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3034 
3035  key.addr.as_u32 = addr->as_u32;
3036  key.port = clib_host_to_net_u16 (port);
3037  key.protocol = proto;
3038  key.fib_index = fib_index;
3039  kv.key = key.as_u64;
3040  t = is_in ? &tsm->in2out : &tsm->out2in;
3041  if (!clib_bihash_search_8_8 (t, &kv, &value))
3042  {
3043  s = pool_elt_at_index (tsm->sessions, value.value);
3044  kv.key = s->in2out.as_u64;
3045  clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3046  kv.key = s->out2in.as_u64;
3047  clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3048  u_key.addr = s->in2out.addr;
3049  u_key.fib_index = s->in2out.fib_index;
3050  kv.key = u_key.as_u64;
3051  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3052  {
3053  u = pool_elt_at_index (tsm->users, value.value);
3054  u->nsessions--;
3055  }
3056  clib_dlist_remove (tsm->list_pool, s->per_user_index);
3057  pool_put (tsm->sessions, s);
3058  return 0;
3059  }
3060 
3061  return VNET_API_ERROR_NO_SUCH_ENTRY;
3062 }
3063 
3064 void
3065 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3066 {
3067  snat_main_t *sm = &snat_main;
3068 
3070  sm->psid = psid;
3071  sm->psid_offset = psid_offset;
3072  sm->psid_length = psid_length;
3073 }
3074 
3075 void
3077 {
3078  snat_main_t *sm = &snat_main;
3079 
3081 }
3082 
ip4_address_t external_addr
Definition: nat.h:215
u32 user_memory_size
Definition: nat.h:368
u8 * format_snat_user(u8 *s, va_list *args)
Definition: nat.c:2669
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:434
clib_error_t * snat_api_init(vlib_main_t *vm, snat_main_t *sm)
Definition: nat_api.c:2889
void dslite_set_ce(dslite_main_t *dm, u8 set)
Definition: dslite.c:74
u32 next
Definition: dlist.h:30
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:197
vmrglw vmrglh hi
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:445
u32 sessions_per_user_list_head_index
Definition: nat.h:171
clib_bihash_16_8_t out2in_ed
Definition: nat.h:292
int snat_del_address(snat_main_t *sm, ip4_address_t addr, u8 delete_sm, u8 twice_nat)
Definition: nat.c:1414
vlib_node_registration_t nat44_handoff_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_handoff_classify_node)
Definition: nat.c:135
u16 ext_host_port
Definition: nat.h:79
void dslite_init(vlib_main_t *vm)
Definition: dslite.c:22
u16 out_port
Definition: nat.h:80
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:129
VLIB_NODE_FUNCTION_MULTIARCH(nat44_classify_node, nat44_classify_node_fn)
a
Definition: bitmap.h:516
u8 * format_snat_protocol(u8 *s, va_list *args)
Definition: nat.c:2255
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u32 icmp_timeout
Definition: nat.h:379
ip4_address_t src_address
Definition: ip4_packet.h:164
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static int nat_alloc_addr_and_port_mape(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2165
u32 fq_in2out_output_index
Definition: nat.h:345
clib_error_t * nat_reass_init(vlib_main_t *vm)
Initialize NAT virtual fragmentation reassembly.
Definition: nat_reass.c:585
#define SNAT_TCP_ESTABLISHED_TIMEOUT
Definition: nat.h:36
#define PREDICT_TRUE(x)
Definition: clib.h:106
u32 nsessions
Definition: nat.h:172
#define is_ed_session(s)
Check if NAT session is endpoint dependent.
Definition: nat.h:469
ip4_address_t addr
Definition: nat.h:207
#define NULL
Definition: clib.h:55
snat_protocol_t proto
Definition: nat.h:223
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:319
u16 port_per_thread
Definition: nat.h:304
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1754
nat_reass_ip4_t * nat_ip4_reass_find(ip4_address_t src, ip4_address_t dst, u16 frag_id, u8 proto)
Find reassembly.
Definition: nat_reass.c:199
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:520
u32 nstaticsessions
Definition: nat.h:173
u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:386
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:559
#define NAT_INTERFACE_FLAG_IS_OUTSIDE
Definition: nat.h:134
int i
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
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
Definition: out2in.c:2475
void nat64_set_hash(u32 bib_buckets, u32 bib_memory_size, u32 st_buckets, u32 st_memory_size)
Set NAT64 hash tables configuration.
Definition: nat64.c:251
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 fib_index
Definition: nat.h:170
clib_bihash_16_8_t in2out_ed
Definition: nat.h:293
int snat_static_mapping_match(snat_main_t *sm, snat_session_key_t match, snat_session_key_t *mapping, u8 by_external, u8 *is_addr_only, u8 *twice_nat)
Match NAT44 static mapping.
Definition: nat.c:1969
void snat_add_del_addr_to_fib(ip4_address_t *addr, u8 p_len, u32 sw_if_index, int is_add)
Add/del NAT address to FIB.
Definition: nat.c:510
nat_alloc_out_addr_and_port_function_t * alloc_addr_and_port
Definition: nat.h:325
static void snat_ip4_add_del_interface_address_cb(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
Definition: nat.c:2866
u32 num_snat_thread
Definition: nat.h:305
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
dlist_elt_t * list_pool
Definition: nat.h:262
#define snat_is_unk_proto_session(s)
Check if SNAT session for unknown protocol.
Definition: nat.h:451
u8 * format_snat_static_mapping(u8 *s, va_list *args)
Definition: nat.c:2709
u32 proto
Definition: nat.h:64
u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: in2out.c:677
format_function_t format_vnet_sw_if_index_name
u8 deterministic
Definition: nat.h:362
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Definition: nat.c:1527
static uword nat44_classify_node_fn_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:346
u16 l_port
Definition: nat.h:66
nat44_lb_addr_port_t * locals
Definition: nat.h:226
void nat66_init(void)
Definition: nat66.c:43
u32 user_buckets
Definition: nat.h:367
clib_bihash_8_8_t user_hash
Definition: nat.h:253
u16 identifier
Definition: nat.h:481
fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_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:764
u32 max_translations_per_user
Definition: nat.h:369
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, u8 *tag)
Definition: nat.c:619
clib_bihash_8_8_t in2out
Definition: nat.h:250
nat66_main_t nat66_main
Definition: nat66.c:23
int nat44_add_del_lb_static_mapping(ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add, u8 twice_nat, u8 out2in_only, u8 *tag)
Definition: nat.c:1141
u32 in2out_output_node_index
Definition: nat.h:350
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:226
format_function_t format_ip4_address
Definition: format.h:79
#define static_always_inline
Definition: clib.h:93
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:440
u16 r_port
Definition: nat.h:67
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:1688
ip4_address_t ext_host_addr
Definition: nat.h:78
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:399
ip4_address_t dst_address
Definition: ip4_packet.h:164
static u32 snat_get_worker_in2out_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: nat.c:2274
u32 translation_buckets
Definition: nat.h:364
ip4_address_t addr
Definition: nat.h:169
#define SNAT_DET_SES_PER_USER
Definition: nat_det.h:30
A high priority source a plugin can use.
Definition: fib_entry.h:62
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregrate type for a prefix.
Definition: fib_types.h:188
#define clib_error_return(e, args...)
Definition: error.h:99
void snat_ipfix_logging_init(vlib_main_t *vm)
Initialize NAT plugin IPFIX logging.
u8 * format_snat_key(u8 *s, va_list *args)
Definition: nat.c:2608
ip4_main_t * ip4_main
Definition: nat.h:387
unsigned long u64
Definition: types.h:89
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
nat44_classify_next_t
Definition: nat.c:137
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1037
u16 fp_len
The mask length.
Definition: fib_types.h:192
ip4_address_t local_addr
Definition: nat.h:214
static void nat_ip4_add_del_addr_only_sm_cb(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
Definition: nat.c:2795
u64 as_u64[2]
Definition: nat.h:69
static uword nat44_det_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:452
snat_protocol_t proto
Definition: nat.h:240
u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: out2in.c:2514
static int ip4_is_fragment(ip4_header_t *i)
Definition: ip4_packet.h:205
VNET_FEATURE_INIT(ip4_snat_in2out, static)
u32 max_translations
Definition: nat.h:366
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:168
u32 * auto_add_sw_if_indices_twice_nat
Definition: nat.h:335
Definition: fib_entry.h:275
u32 fib_index
Definition: nat.h:64
#define hash_get(h, key)
Definition: hash.h:248
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Definition: nat.c:241
Definition: fib_entry.h:274
#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:461
void nat_free_session_data(snat_main_t *sm, snat_session_t *s, u32 thread_index)
Definition: nat.c:144
void nat_dpo_module_init(void)
Definition: nat_dpo.c:68
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:121
static uword clib_bitmap_last_set(uword *ai)
Return the higest numbered set bit in a bitmap.
Definition: bitmap.h:402
u64 key
the key
Definition: bihash_8_8.h:35
lo
vlib_main_t * vlib_main
Definition: nat.h:385
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
#define v
Definition: acl.c:495
struct _unformat_input_t unformat_input_t
u16 protocol
Definition: nat.h:50
u8 out2in_dpo
Definition: nat.h:363
#define SNAT_UDP_TIMEOUT
Definition: nat.h:33
snat_static_mapping_t * static_mappings
Definition: nat.h:317
u32 inside_fib_index
Definition: nat.h:373
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
void snat_ipfix_logging_nat44_ses_delete(u32 src_ip, u32 nat_src_ip, snat_protocol_t snat_proto, u16 src_port, u16 nat_src_port, u32 vrf_id)
Generate NAT44 session delete event.
vlib_node_registration_t nat44_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_classify_node)
Definition: nat.c:133
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:273
u32 udp_timeout
Definition: nat.h:376
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:370
u8 static_mapping_only
Definition: nat.h:360
#define PREDICT_FALSE(x)
Definition: clib.h:105
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:803
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:314
u8 psid_offset
Definition: nat.h:326
int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, u8 twice_nat, u8 out2in_only, u8 *tag)
Add static mapping.
Definition: nat.c:663
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
void nat_set_alloc_addr_and_port_default(void)
Definition: nat.c:3076
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
api_main_t * api_main
Definition: nat.h:389
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1209
u8 psid_length
Definition: nat.h:327
vnet_main_t * vnet_main
Definition: nat.h:386
u32 inside_vrf_id
Definition: nat.h:372
u32 fq_out2in_index
Definition: nat.h:346
snat_interface_t * output_feature_interfaces
Definition: nat.h:321
static uword nat44_handoff_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:475
snat_main_t snat_main
Definition: nat.c:35
u64 value
the value
Definition: bihash_8_8.h:36
snat_user_t * users
Definition: nat.h:256
u32 random_seed
Definition: nat.h:341
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:344
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k, u32 address_index)
Definition: nat.c:1925
clib_bihash_8_8_t out2in
Definition: nat.h:249
static u32 random_u32_max(void)
Maximum value returned by random_u32()
Definition: random.h:80
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
u8 nat_reass_is_drop_frag(u8 is_ip6)
Get status of virtual fragmentation reassembly.
Definition: nat_reass.c:168
vlib_main_t * vm
Definition: buffer.c:294
u32 outside_vrf_id
Definition: nat.h:370
void nat44_add_del_address_dpo(ip4_address_t addr, u8 is_add)
Definition: nat.c:2218
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:106
ip4_address_t l_addr
Definition: nat.h:62
u8 static_mapping_connection_tracking
Definition: nat.h:361
snat_get_worker_function_t * worker_in2out_cb
Definition: nat.h:302
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:845
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:72
deterministic NAT definitions
#define clib_warning(format, args...)
Definition: error.h:59
VLIB_PLUGIN_REGISTER()
int snat_interface_add_del_output_feature(u32 sw_if_index, u8 is_inside, int is_del)
Definition: nat.c:1683
static int ip4_is_first_fragment(ip4_header_t *i)
Definition: ip4_packet.h:212
u32 sharing_ratio
Definition: nat.h:199
ip4_address_t out_addr
Definition: nat.h:197
u16 psid
Definition: nat.h:328
static uword nat44_classify_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nat.c:429
dslite_main_t dslite_main
Definition: dslite.c:19
u32 outside_fib_index
Definition: nat.h:371
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:270
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
ip4_address_t addr
Definition: nat.h:48
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:454
u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:547
u32 tcp_transitory_timeout
Definition: nat.h:378
ip4_address_t r_addr
Definition: nat.h:63
u32 * auto_add_sw_if_indices
Definition: nat.h:334
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:299
static_always_inline u16 snat_random_port(u16 min, u16 max)
Definition: nat.c:2049
static int nat_alloc_addr_and_port_default(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2073
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:296
#define ASSERT(truth)
#define NAT_INTERFACE_FLAG_IS_INSIDE
Definition: nat.h:133
u8 * format_snat_static_map_to_resolve(u8 *s, va_list *args)
Definition: nat.c:2745
u32 num_workers
Definition: nat.h:298
unsigned int u32
Definition: types.h:88
u32 first_worker_index
Definition: nat.h:299
snat_get_worker_function_t * worker_out2in_cb
Definition: nat.h:303
ip4_address_t l_addr
Definition: nat.h:235
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat.h:486
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:296
IPv4 main type.
Definition: ip4.h:95
u64 as_u64
Definition: nat.h:94
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1096
ip4_address_t addr
Definition: nat.h:91
ip4_address_t in_addr
Definition: nat.h:195
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
u32 fq_in2out_index
Definition: nat.h:344
uword * thread_registrations_by_name
Definition: threads.h:297
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u32 out2in_node_index
Definition: nat.h:351
ip4_address_t addr
Definition: nat.h:177
int nat44_del_session(snat_main_t *sm, ip4_address_t *addr, u16 port, snat_protocol_t proto, u32 vrf_id, int is_in)
Definition: nat.c:3014
snat_address_t * twice_nat_addresses
Definition: nat.h:331
#define VNET_FEATURES(...)
Definition: feature.h:375
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: nat.c:1831
static uword is_pow2(uword x)
Definition: clib.h:280
u32 value
Definition: dlist.h:32
u64 uword
Definition: types.h:112
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index)
Definition: nat.c:285
vlib_node_registration_t snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
Definition: in2out.c:110
u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation.
Definition: out2in.c:536
clib_error_t * nat64_init(vlib_main_t *vm)
Initialize NAT64.
Definition: nat64.c:211
struct _vlib_node_registration vlib_node_registration_t
NAT64 global declarations.
void increment_v4_address(ip4_address_t *a)
Definition: nat.c:610
unsigned short u16
Definition: types.h:57
void snat_add_address(snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, u8 twice_nat)
Definition: nat.c:542
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u32 *address_indexp, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2057
static int lb_local_exists(nat44_lb_addr_port_t *local, ip4_address_t *e_addr, u16 e_port)
Definition: nat.c:1114
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u32 outside_fib_index
Definition: nat66.h:60
Definition: fib_entry.h:271
void snat_ipfix_logging_addresses_exhausted(u32 pool_id)
Generate NAT addresses exhausted event.
u32 * workers
Definition: nat.h:301
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:308
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
snat_protocol_t
Definition: nat.h:104
snat_det_out_key_t out
Definition: nat.h:189
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:195
u32 fib_index
Definition: nat.h:92
snat_address_t * addresses
Definition: nat.h:324
void nat_dpo_create(dpo_proto_t dproto, u32 aftr_index, dpo_id_t *dpo)
Definition: nat_dpo.c:22
int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del, u8 twice_nat)
Definition: nat.c:2947
u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Get address and port values to be used for ICMP packet translation and create session if needed...
Definition: in2out.c:3372
u8 * format_snat_session(u8 *s, va_list *args)
Definition: nat.c:2619
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * format_det_map_ses(u8 *s, va_list *args)
Definition: nat.c:2765
u32 in2out_node_index
Definition: nat.h:349
#define SNAT_ICMP_TIMEOUT
Definition: nat.h:38
uword unformat_snat_protocol(unformat_input_t *input, va_list *args)
Definition: nat.c:2241
snat_static_map_resolve_t * to_resolve
Definition: nat.h:338
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:818
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
u32 outside_vrf_id
Definition: nat66.h:59
u8 forwarding_enabled
Definition: nat.h:357
u32 translation_memory_size
Definition: nat.h:365
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:231
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t snat_in2out_output_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_output_node)
Definition: in2out.c:111
vlib_node_registration_t nat44_det_classify_node
(constructor) VLIB_REGISTER_NODE (nat44_det_classify_node)
Definition: nat.c:134
u32 next_worker
Definition: nat.h:300
int snat_set_workers(uword *bitmap)
Definition: nat.c:1778
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:457
vhost_vring_addr_t addr
Definition: vhost-user.h:83
static clib_error_t * snat_config(vlib_main_t *vm, unformat_input_t *input)
Definition: nat.c:2430
NAT plugin virtual fragmentation reassembly.
void nat_set_alloc_addr_and_port_mape(u16 psid, u16 psid_offset, u16 psid_length)
Definition: nat.c:3065
NAT66 global declarations.
#define SNAT_TCP_TRANSITORY_TIMEOUT
Definition: nat.h:35
ip_lookup_main_t * ip4_lookup_main
Definition: nat.h:388
api_main_t api_main
Definition: api_shared.c:35
static int is_snat_address_used_in_static_mapping(snat_main_t *sm, ip4_address_t addr)
Definition: nat.c:597
snat_session_t * sessions
Definition: nat.h:259
u8 * format_snat_session_state(u8 *s, va_list *args)
Definition: nat.c:2591
A low (below routing) priority source a plugin can use.
Definition: fib_entry.h:78
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
snat_icmp_match_function_t * icmp_match_in2out_cb
Definition: nat.h:295
#define SNAT_SESSION_FLAG_LOAD_BALANCING
Definition: nat.h:130
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:311
static u32 snat_get_worker_out2in_cb(ip4_header_t *ip0, u32 rx_fib_index0)
Definition: nat.c:2293
u32 fib_index
Definition: nat.h:178
snat_interface_t * interfaces
Definition: nat.h:320
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u16 fib_index
Definition: nat.h:50
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:233
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static_always_inline u8 icmp_is_error_message(icmp46_header_t *icmp)
Definition: nat.h:580
static u8 snat_proto_to_ip_proto(snat_protocol_t snat_proto)
Definition: nat.h:499
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117
u32 tcp_established_timeout
Definition: nat.h:377
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128