FD.io VPP  v20.01-48-g3e0dafb74
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_inlines.h>
30 #include <nat/nat_affinity.h>
31 #include <nat/nat_syslog.h>
32 #include <nat/nat_ha.h>
33 #include <vnet/fib/fib_table.h>
34 #include <vnet/fib/ip4_fib.h>
36 
37 #include <vpp/app/version.h>
38 
40 
43 
44 /* *INDENT-OFF* */
45 /* Hook up input features */
46 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
47  .arc_name = "ip4-unicast",
48  .node_name = "nat-pre-in2out",
49  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
50  "ip4-sv-reassembly-feature"),
51 };
52 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
53  .arc_name = "ip4-unicast",
54  .node_name = "nat-pre-out2in",
55  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
56  "ip4-dhcp-client-detect",
57  "ip4-sv-reassembly-feature"),
58 };
59 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
60  .arc_name = "ip4-unicast",
61  .node_name = "nat44-in2out-worker-handoff",
62  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
63 };
64 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
65  .arc_name = "ip4-unicast",
66  .node_name = "nat44-out2in-worker-handoff",
67  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
68  "ip4-dhcp-client-detect"),
69 };
70 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
71  .arc_name = "ip4-unicast",
72  .node_name = "nat44-in2out",
73  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
74 };
75 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
76  .arc_name = "ip4-unicast",
77  .node_name = "nat44-out2in",
78  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
79  "ip4-dhcp-client-detect"),
80 };
81 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
82  .arc_name = "ip4-unicast",
83  .node_name = "nat44-classify",
84  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
85 };
86 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
87  .arc_name = "ip4-unicast",
88  .node_name = "nat44-det-in2out",
89  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
90 };
91 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
92  .arc_name = "ip4-unicast",
93  .node_name = "nat44-det-out2in",
94  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
95  "ip4-dhcp-client-detect"),
96 };
97 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
98  .arc_name = "ip4-unicast",
99  .node_name = "nat44-det-classify",
100  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
101 };
102 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
103  .arc_name = "ip4-unicast",
104  .node_name = "nat44-ed-in2out",
105  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
106 };
107 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
108  .arc_name = "ip4-unicast",
109  .node_name = "nat44-ed-out2in",
110  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
111  "ip4-dhcp-client-detect"),
112 };
113 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
114  .arc_name = "ip4-unicast",
115  .node_name = "nat44-ed-classify",
116  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
117 };
118 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
119  .arc_name = "ip4-unicast",
120  .node_name = "nat44-handoff-classify",
121  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
122 };
123 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
124  .arc_name = "ip4-unicast",
125  .node_name = "nat44-in2out-fast",
126  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
127 };
128 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
129  .arc_name = "ip4-unicast",
130  .node_name = "nat44-out2in-fast",
131  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
132  "ip4-dhcp-client-detect"),
133 };
134 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
135  .arc_name = "ip4-unicast",
136  .node_name = "nat44-hairpin-dst",
137  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
138 };
139 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
140  .arc_name = "ip4-unicast",
141  .node_name = "nat44-ed-hairpin-dst",
142  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
143 };
144 
145 /* Hook up output features */
146 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
147  .arc_name = "ip4-output",
148  .node_name = "nat44-in2out-output",
149  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
150 };
151 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
152  .arc_name = "ip4-output",
153  .node_name = "nat44-in2out-output-worker-handoff",
154  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
155 };
156 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
157  .arc_name = "ip4-output",
158  .node_name = "nat44-hairpin-src",
159  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
160 };
161 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
162  .arc_name = "ip4-output",
163  .node_name = "nat44-ed-in2out-output",
164  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
165 };
166 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
167  .arc_name = "ip4-output",
168  .node_name = "nat44-ed-hairpin-src",
169  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
170 };
171 
172 /* Hook up ip4-local features */
173 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
174 {
175  .arc_name = "ip4-local",
176  .node_name = "nat44-hairpinning",
177  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
178 };
179 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
180 {
181  .arc_name = "ip4-local",
182  .node_name = "nat44-ed-hairpinning",
183  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
184 };
185 
186 
188  .version = VPP_BUILD_VER,
189  .description = "Network Address Translation (NAT)",
190 };
191 /* *INDENT-ON* */
192 
193 void
194 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
195  u8 is_ha)
196 {
199  nat_ed_ses_key_t ed_key;
200  clib_bihash_kv_16_8_t ed_kv;
202  vec_elt_at_index (sm->per_thread_data, thread_index);
203 
204  if (is_fwd_bypass_session (s))
205  {
207  {
208  ed_key.proto = s->in2out.port;
209  ed_key.r_port = 0;
210  ed_key.l_port = 0;
211  }
212  else
213  {
214  ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
215  ed_key.l_port = s->in2out.port;
216  ed_key.r_port = s->ext_host_port;
217  }
218  ed_key.l_addr = s->in2out.addr;
219  ed_key.r_addr = s->ext_host_addr;
220  ed_key.fib_index = 0;
221  ed_kv.key[0] = ed_key.as_u64[0];
222  ed_kv.key[1] = ed_key.as_u64[1];
223  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
224  nat_elog_warn ("in2out_ed key del failed");
225  return;
226  }
227 
228  /* session lookup tables */
229  if (is_ed_session (s))
230  {
231  if (is_affinity_sessions (s))
232  nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
233  s->in2out.protocol, s->out2in.port);
234  ed_key.l_addr = s->out2in.addr;
235  ed_key.r_addr = s->ext_host_addr;
236  ed_key.fib_index = s->out2in.fib_index;
238  {
239  ed_key.proto = s->in2out.port;
240  ed_key.r_port = 0;
241  ed_key.l_port = 0;
242  }
243  else
244  {
245  ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
246  ed_key.l_port = s->out2in.port;
247  ed_key.r_port = s->ext_host_port;
248  }
249  ed_kv.key[0] = ed_key.as_u64[0];
250  ed_kv.key[1] = ed_key.as_u64[1];
251  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
252  nat_elog_warn ("out2in_ed key del failed");
253  ed_key.l_addr = s->in2out.addr;
254  ed_key.fib_index = s->in2out.fib_index;
255  if (!snat_is_unk_proto_session (s))
256  ed_key.l_port = s->in2out.port;
257  if (is_twice_nat_session (s))
258  {
259  ed_key.r_addr = s->ext_host_nat_addr;
260  ed_key.r_port = s->ext_host_nat_port;
261  }
262  ed_kv.key[0] = ed_key.as_u64[0];
263  ed_kv.key[1] = ed_key.as_u64[1];
264  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
265  nat_elog_warn ("in2out_ed key del failed");
266 
267  if (!is_ha)
268  nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
269  &s->in2out.addr, s->in2out.port,
270  &s->ext_host_nat_addr, s->ext_host_nat_port,
271  &s->out2in.addr, s->out2in.port,
272  &s->ext_host_addr, s->ext_host_port,
273  s->in2out.protocol, is_twice_nat_session (s));
274  }
275  else
276  {
277  kv.key = s->in2out.as_u64;
278  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
279  nat_elog_warn ("in2out key del failed");
280  kv.key = s->out2in.as_u64;
281  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
282  nat_elog_warn ("out2in key del failed");
283 
284  if (!is_ha)
285  nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
286  &s->in2out.addr, s->in2out.port,
287  &s->out2in.addr, s->out2in.port,
288  s->in2out.protocol);
289  }
290 
292  return;
293 
294  if (!is_ha)
295  {
296  /* log NAT event */
298  s->in2out.addr.as_u32,
299  s->out2in.addr.as_u32,
300  s->in2out.protocol,
301  s->in2out.port,
302  s->out2in.port,
303  s->in2out.fib_index);
304 
305  nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
306  s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
307  thread_index);
308  }
309 
310  /* Twice NAT address and port for external host */
311  if (is_twice_nat_session (s))
312  {
313  key.protocol = s->in2out.protocol;
314  key.port = s->ext_host_nat_port;
315  key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
317  thread_index, &key);
318  }
319 
320  if (snat_is_session_static (s))
321  return;
322 
324  &s->out2in);
325 }
326 
327 snat_user_t *
329  u32 thread_index)
330 {
331  snat_user_t *u = 0;
332  snat_user_key_t user_key;
334  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
335  dlist_elt_t *per_user_list_head_elt;
336 
337  user_key.addr.as_u32 = addr->as_u32;
338  user_key.fib_index = fib_index;
339  kv.key = user_key.as_u64;
340 
341  /* Ever heard of the "user" = src ip4 address before? */
342  if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
343  {
344  /* no, make a new one */
345  pool_get (tsm->users, u);
346  clib_memset (u, 0, sizeof (*u));
347  u->addr.as_u32 = addr->as_u32;
348  u->fib_index = fib_index;
349 
350  pool_get (tsm->list_pool, per_user_list_head_elt);
351 
352  u->sessions_per_user_list_head_index = per_user_list_head_elt -
353  tsm->list_pool;
354 
356 
357  kv.value = u - tsm->users;
358 
359  /* add user */
360  if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
361  nat_elog_warn ("user_hash keay add failed");
362 
363  vlib_set_simple_counter (&sm->total_users, thread_index, 0,
364  pool_elts (tsm->users));
365  }
366  else
367  {
368  u = pool_elt_at_index (tsm->users, value.value);
369  }
370 
371  return u;
372 }
373 
374 snat_session_t *
376  u32 thread_index, f64 now)
377 {
378  snat_session_t *s;
379  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
380  u32 oldest_per_user_translation_list_index, session_index;
381  dlist_elt_t *oldest_per_user_translation_list_elt;
382  dlist_elt_t *per_user_translation_list_elt;
383 
384  /* Over quota? Recycle the least recently used translation */
386  {
387  oldest_per_user_translation_list_index =
390 
391  ASSERT (oldest_per_user_translation_list_index != ~0);
392 
393  /* Add it back to the end of the LRU list */
396  oldest_per_user_translation_list_index);
397  /* Get the list element */
398  oldest_per_user_translation_list_elt =
400  oldest_per_user_translation_list_index);
401 
402  /* Get the session index from the list element */
403  session_index = oldest_per_user_translation_list_elt->value;
404 
405  /* Get the session */
406  s = pool_elt_at_index (tsm->sessions, session_index);
407  nat_free_session_data (sm, s, thread_index, 0);
408  if (snat_is_session_static (s))
409  u->nstaticsessions--;
410  else
411  u->nsessions--;
412  s->flags = 0;
413  s->total_bytes = 0;
414  s->total_pkts = 0;
415  s->state = 0;
416  s->ext_host_addr.as_u32 = 0;
417  s->ext_host_port = 0;
418  s->ext_host_nat_addr.as_u32 = 0;
419  s->ext_host_nat_port = 0;
420  }
421  else
422  {
423  pool_get (tsm->sessions, s);
424  clib_memset (s, 0, sizeof (*s));
425 
426  /* Create list elts */
427  pool_get (tsm->list_pool, per_user_translation_list_elt);
429  per_user_translation_list_elt - tsm->list_pool);
430 
431  per_user_translation_list_elt->value = s - tsm->sessions;
432  s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
433  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
434 
436  s->per_user_list_head_index,
437  per_user_translation_list_elt - tsm->list_pool);
438 
439  s->user_index = u - tsm->users;
440  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
441  pool_elts (tsm->sessions));
442  }
443 
444  s->ha_last_refreshed = now;
445 
446  return s;
447 }
448 
449 snat_session_t *
451  f64 now)
452 {
453  snat_session_t *s;
454  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
455  dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
456  u32 oldest_index;
457  u64 sess_timeout_time;
458 
459  if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
460  goto alloc_new;
461 
462  oldest_index =
465  oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
466  s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
467 
468  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
469  if (now >= sess_timeout_time)
470  {
472  u->sessions_per_user_list_head_index, oldest_index);
473  nat_free_session_data (sm, s, thread_index, 0);
474  if (snat_is_session_static (s))
475  u->nstaticsessions--;
476  else
477  u->nsessions--;
478  s->flags = 0;
479  s->total_bytes = 0;
480  s->total_pkts = 0;
481  s->state = 0;
482  s->ext_host_addr.as_u32 = 0;
483  s->ext_host_port = 0;
484  s->ext_host_nat_addr.as_u32 = 0;
485  s->ext_host_nat_port = 0;
486  }
487  else
488  {
490  u->sessions_per_user_list_head_index, oldest_index);
491  if ((u->nsessions + u->nstaticsessions) >=
493  {
494  nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
495  clib_net_to_host_u32 (u->addr.as_u32));
497  (thread_index, sm->max_translations_per_user, u->addr.as_u32);
498  return 0;
499  }
500  else
501  {
502  alloc_new:
503  pool_get (tsm->sessions, s);
504  clib_memset (s, 0, sizeof (*s));
505 
506  /* Create list elts */
507  pool_get (tsm->list_pool, per_user_translation_list_elt);
509  per_user_translation_list_elt - tsm->list_pool);
510 
511  per_user_translation_list_elt->value = s - tsm->sessions;
512  s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
513  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
514 
516  s->per_user_list_head_index,
517  per_user_translation_list_elt - tsm->list_pool);
518  }
519 
520  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
521  pool_elts (tsm->sessions));
522  }
523 
524  s->ha_last_refreshed = now;
525 
526  return s;
527 }
528 
529 void
531  int is_add)
532 {
533  fib_prefix_t prefix = {
534  .fp_len = p_len,
535  .fp_proto = FIB_PROTOCOL_IP4,
536  .fp_addr = {
537  .ip4.as_u32 = addr->as_u32,
538  },
539  };
540  u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
541 
542  if (is_add)
544  &prefix,
545  nat_fib_src_low,
550  NULL,
551  sw_if_index,
553  else
554  fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
555 }
556 
557 int
559  u8 twice_nat)
560 {
561  snat_address_t *ap;
564 
565  if (twice_nat && !sm->endpoint_dependent)
566  return VNET_API_ERROR_FEATURE_DISABLED;
567 
568  /* Check if address already exists */
569  /* *INDENT-OFF* */
570  vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
571  {
572  if (ap->addr.as_u32 == addr->as_u32)
573  return VNET_API_ERROR_VALUE_EXIST;
574  }
575  /* *INDENT-ON* */
576 
577  if (twice_nat)
578  vec_add2 (sm->twice_nat_addresses, ap, 1);
579  else
580  vec_add2 (sm->addresses, ap, 1);
581 
582  ap->addr = *addr;
583  if (vrf_id != ~0)
584  ap->fib_index =
586  nat_fib_src_low);
587  else
588  ap->fib_index = ~0;
589 #define _(N, i, n, s) \
590  clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
591  ap->busy_##n##_ports = 0; \
592  ap->busy_##n##_ports_per_thread = 0;\
593  vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
595 #undef _
596  if (twice_nat)
597  return 0;
598 
599  /* Add external address to FIB */
600  /* *INDENT-OFF* */
601  pool_foreach (i, sm->interfaces,
602  ({
603  if (nat_interface_is_inside(i) || sm->out2in_dpo)
604  continue;
605 
606  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
607  break;
608  }));
610  ({
611  if (nat_interface_is_inside(i) || sm->out2in_dpo)
612  continue;
613 
614  snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
615  break;
616  }));
617  /* *INDENT-ON* */
618 
619  return 0;
620 }
621 
622 static int
624 {
626  /* *INDENT-OFF* */
628  ({
629  if (is_addr_only_static_mapping (m) ||
630  is_out2in_only_static_mapping (m) ||
631  is_identity_static_mapping (m))
632  continue;
633  if (m->external_addr.as_u32 == addr.as_u32)
634  return 1;
635  }));
636  /* *INDENT-ON* */
637 
638  return 0;
639 }
640 
641 void
643 {
644  u32 v;
645 
646  v = clib_net_to_host_u32 (a->as_u32) + 1;
647  a->as_u32 = clib_host_to_net_u32 (v);
648 }
649 
650 static void
652  ip4_address_t l_addr,
653  u16 l_port,
655  u16 e_port,
656  u32 vrf_id,
658  int addr_only, int is_add, u8 * tag,
659  int twice_nat, int out2in_only,
660  int identity_nat)
661 {
663 
664  vec_add2 (sm->to_resolve, rp, 1);
665  rp->l_addr.as_u32 = l_addr.as_u32;
666  rp->l_port = l_port;
667  rp->sw_if_index = sw_if_index;
668  rp->e_port = e_port;
669  rp->vrf_id = vrf_id;
670  rp->proto = proto;
671  rp->addr_only = addr_only;
672  rp->is_add = is_add;
673  rp->twice_nat = twice_nat;
674  rp->out2in_only = out2in_only;
675  rp->identity_nat = identity_nat;
676  rp->tag = vec_dup (tag);
677 }
678 
679 static u32
681 {
682  snat_main_t *sm = &snat_main;
683  u32 thread_idx = sm->num_workers;
684  if (sm->num_workers > 1)
685  {
686  thread_idx =
687  sm->first_worker_index +
688  sm->workers[(e_port - 1024) / sm->port_per_thread];
689  }
690  return thread_idx;
691 }
692 
693 int
695  u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
696  u32 sw_if_index, snat_protocol_t proto, int is_add,
697  twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
698  u8 identity_nat)
699 {
700  snat_main_t *sm = &snat_main;
702  snat_session_key_t m_key;
704  snat_address_t *a = 0;
705  u32 fib_index = ~0;
706  snat_interface_t *interface;
707  int i;
709  snat_user_key_t u_key;
710  snat_user_t *u;
711  dlist_elt_t *head, *elt;
712  u32 elt_index, head_index;
713  u32 ses_index;
714  u64 user_index;
715  snat_session_t *s;
716  snat_static_map_resolve_t *rp, *rp_match = 0;
717  nat44_lb_addr_port_t *local;
718  u32 find = ~0;
719 
720  if (!sm->endpoint_dependent)
721  {
722  if (twice_nat || out2in_only)
723  return VNET_API_ERROR_FEATURE_DISABLED;
724  }
725 
726  /* If the external address is a specific interface address */
727  if (sw_if_index != ~0)
728  {
729  ip4_address_t *first_int_addr;
730 
731  for (i = 0; i < vec_len (sm->to_resolve); i++)
732  {
733  rp = sm->to_resolve + i;
734  if (rp->sw_if_index != sw_if_index ||
735  rp->l_addr.as_u32 != l_addr.as_u32 ||
736  rp->vrf_id != vrf_id || rp->addr_only != addr_only)
737  continue;
738 
739  if (!addr_only)
740  {
741  if ((rp->l_port != l_port && rp->e_port != e_port)
742  || rp->proto != proto)
743  continue;
744  }
745 
746  rp_match = rp;
747  break;
748  }
749 
750  /* Might be already set... */
751  first_int_addr = ip4_interface_first_address
752  (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
753 
754  if (is_add)
755  {
756  if (rp_match)
757  return VNET_API_ERROR_VALUE_EXIST;
758 
760  (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
761  addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
762 
763  /* DHCP resolution required? */
764  if (first_int_addr == 0)
765  {
766  return 0;
767  }
768  else
769  {
770  e_addr.as_u32 = first_int_addr->as_u32;
771  /* Identity mapping? */
772  if (l_addr.as_u32 == 0)
773  l_addr.as_u32 = e_addr.as_u32;
774  }
775  }
776  else
777  {
778  if (!rp_match)
779  return VNET_API_ERROR_NO_SUCH_ENTRY;
780 
781  vec_del1 (sm->to_resolve, i);
782 
783  if (first_int_addr)
784  {
785  e_addr.as_u32 = first_int_addr->as_u32;
786  /* Identity mapping? */
787  if (l_addr.as_u32 == 0)
788  l_addr.as_u32 = e_addr.as_u32;
789  }
790  else
791  return 0;
792  }
793  }
794 
795  m_key.addr = e_addr;
796  m_key.port = addr_only ? 0 : e_port;
797  m_key.protocol = addr_only ? 0 : proto;
798  m_key.fib_index = 0;
799  kv.key = m_key.as_u64;
800  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
801  m = 0;
802  else
803  m = pool_elt_at_index (sm->static_mappings, value.value);
804 
805  if (is_add)
806  {
807  if (m)
808  {
810  {
811  /* *INDENT-OFF* */
812  pool_foreach (local, m->locals,
813  ({
814  if (local->vrf_id == vrf_id)
815  return VNET_API_ERROR_VALUE_EXIST;
816  }));
817  /* *INDENT-ON* */
818  pool_get (m->locals, local);
819  local->vrf_id = vrf_id;
820  local->fib_index =
822  nat_fib_src_low);
823  m_key.addr = m->local_addr;
824  m_key.port = m->local_port;
825  m_key.protocol = m->proto;
826  m_key.fib_index = local->fib_index;
827  kv.key = m_key.as_u64;
828  kv.value = m - sm->static_mappings;
829  clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
830  return 0;
831  }
832  else
833  return VNET_API_ERROR_VALUE_EXIST;
834  }
835 
836  if (twice_nat && addr_only)
837  return VNET_API_ERROR_UNSUPPORTED;
838 
839  /* Convert VRF id to FIB index */
840  if (vrf_id != ~0)
841  fib_index =
843  nat_fib_src_low);
844  /* If not specified use inside VRF id from SNAT plugin startup config */
845  else
846  {
847  fib_index = sm->inside_fib_index;
848  vrf_id = sm->inside_vrf_id;
849  fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
850  }
851 
852  if (!(out2in_only || identity_nat))
853  {
854  m_key.addr = l_addr;
855  m_key.port = addr_only ? 0 : l_port;
856  m_key.protocol = addr_only ? 0 : proto;
857  m_key.fib_index = fib_index;
858  kv.key = m_key.as_u64;
859  if (!clib_bihash_search_8_8
860  (&sm->static_mapping_by_local, &kv, &value))
861  return VNET_API_ERROR_VALUE_EXIST;
862  }
863 
864  /* Find external address in allocated addresses and reserve port for
865  address and port pair mapping when dynamic translations enabled */
866  if (!(addr_only || sm->static_mapping_only || out2in_only))
867  {
868  for (i = 0; i < vec_len (sm->addresses); i++)
869  {
870  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
871  {
872  a = sm->addresses + i;
873  /* External port must be unused */
874  switch (proto)
875  {
876 #define _(N, j, n, s) \
877  case SNAT_PROTOCOL_##N: \
878  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
879  return VNET_API_ERROR_INVALID_VALUE; \
880  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
881  if (e_port > 1024) \
882  { \
883  a->busy_##n##_ports++; \
884  a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
885  } \
886  break;
888 #undef _
889  default:
890  nat_elog_info ("unknown protocol");
891  return VNET_API_ERROR_INVALID_VALUE_2;
892  }
893  break;
894  }
895  }
896  /* External address must be allocated */
897  if (!a && (l_addr.as_u32 != e_addr.as_u32))
898  {
899  if (sw_if_index != ~0)
900  {
901  for (i = 0; i < vec_len (sm->to_resolve); i++)
902  {
903  rp = sm->to_resolve + i;
904  if (rp->addr_only)
905  continue;
906  if (rp->sw_if_index != sw_if_index &&
907  rp->l_addr.as_u32 != l_addr.as_u32 &&
908  rp->vrf_id != vrf_id && rp->l_port != l_port &&
909  rp->e_port != e_port && rp->proto != proto)
910  continue;
911 
912  vec_del1 (sm->to_resolve, i);
913  break;
914  }
915  }
916  return VNET_API_ERROR_NO_SUCH_ENTRY;
917  }
918  }
919 
920  pool_get (sm->static_mappings, m);
921  clib_memset (m, 0, sizeof (*m));
922  m->tag = vec_dup (tag);
923  m->local_addr = l_addr;
924  m->external_addr = e_addr;
925  m->twice_nat = twice_nat;
926  if (out2in_only)
928  if (addr_only)
930  if (identity_nat)
931  {
933  pool_get (m->locals, local);
934  local->vrf_id = vrf_id;
935  local->fib_index = fib_index;
936  }
937  else
938  {
939  m->vrf_id = vrf_id;
940  m->fib_index = fib_index;
941  }
942  if (!addr_only)
943  {
944  m->local_port = l_port;
945  m->external_port = e_port;
946  m->proto = proto;
947  }
948 
949  if (sm->num_workers > 1)
950  {
951  ip4_header_t ip = {
952  .src_address = m->local_addr,
953  };
954  vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
955  tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
956  }
957  else
959 
960  m_key.addr = m->local_addr;
961  m_key.port = m->local_port;
962  m_key.protocol = m->proto;
963  m_key.fib_index = fib_index;
964  kv.key = m_key.as_u64;
965  kv.value = m - sm->static_mappings;
966  if (!out2in_only)
967  clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
968 
969  m_key.addr = m->external_addr;
970  m_key.port = m->external_port;
971  m_key.fib_index = 0;
972  kv.key = m_key.as_u64;
973  kv.value = m - sm->static_mappings;
974  clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
975 
976  /* Delete dynamic sessions matching local address (+ local port) */
977  if (!(sm->static_mapping_only))
978  {
979  u_key.addr = m->local_addr;
980  u_key.fib_index = m->fib_index;
981  kv.key = u_key.as_u64;
982  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
983  {
984  user_index = value.value;
985  u = pool_elt_at_index (tsm->users, user_index);
986  if (u->nsessions)
987  {
988  head_index = u->sessions_per_user_list_head_index;
989  head = pool_elt_at_index (tsm->list_pool, head_index);
990  elt_index = head->next;
991  elt = pool_elt_at_index (tsm->list_pool, elt_index);
992  ses_index = elt->value;
993  while (ses_index != ~0)
994  {
995  s = pool_elt_at_index (tsm->sessions, ses_index);
996  elt = pool_elt_at_index (tsm->list_pool, elt->next);
997  ses_index = elt->value;
998 
999  if (snat_is_session_static (s))
1000  continue;
1001 
1002  if (!addr_only
1003  && (clib_net_to_host_u16 (s->in2out.port) !=
1004  m->local_port))
1005  continue;
1006 
1007  nat_free_session_data (sm, s,
1008  tsm - sm->per_thread_data, 0);
1009  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1010 
1011  if (!addr_only && !sm->endpoint_dependent)
1012  break;
1013  }
1014  }
1015  }
1016  }
1017  }
1018  else
1019  {
1020  if (!m)
1021  {
1022  if (sw_if_index != ~0)
1023  return 0;
1024  else
1025  return VNET_API_ERROR_NO_SUCH_ENTRY;
1026  }
1027 
1028  if (identity_nat)
1029  {
1030  if (vrf_id == ~0)
1031  vrf_id = sm->inside_vrf_id;
1032 
1033  /* *INDENT-OFF* */
1034  pool_foreach (local, m->locals,
1035  ({
1036  if (local->vrf_id == vrf_id)
1037  find = local - m->locals;
1038  }));
1039  /* *INDENT-ON* */
1040  if (find == ~0)
1041  return VNET_API_ERROR_NO_SUCH_ENTRY;
1042 
1043  local = pool_elt_at_index (m->locals, find);
1044  fib_index = local->fib_index;
1045  pool_put (m->locals, local);
1046  }
1047  else
1048  fib_index = m->fib_index;
1049 
1050  /* Free external address port */
1051  if (!(addr_only || sm->static_mapping_only || out2in_only))
1052  {
1053  for (i = 0; i < vec_len (sm->addresses); i++)
1054  {
1055  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1056  {
1057  a = sm->addresses + i;
1058  switch (proto)
1059  {
1060 #define _(N, j, n, s) \
1061  case SNAT_PROTOCOL_##N: \
1062  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1063  if (e_port > 1024) \
1064  { \
1065  a->busy_##n##_ports--; \
1066  a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1067  } \
1068  break;
1070 #undef _
1071  default:
1072  nat_elog_info ("unknown protocol");
1073  return VNET_API_ERROR_INVALID_VALUE_2;
1074  }
1075  break;
1076  }
1077  }
1078  }
1079 
1080  if (sm->num_workers > 1)
1081  tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1082  else
1083  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1084 
1085  m_key.addr = m->local_addr;
1086  m_key.port = m->local_port;
1087  m_key.protocol = m->proto;
1088  m_key.fib_index = fib_index;
1089  kv.key = m_key.as_u64;
1090  if (!out2in_only)
1091  clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1092 
1093  /* Delete session(s) for static mapping if exist */
1094  if (!(sm->static_mapping_only) ||
1096  {
1097  u_key.addr = m->local_addr;
1098  u_key.fib_index = fib_index;
1099  kv.key = u_key.as_u64;
1100  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1101  {
1102  user_index = value.value;
1103  u = pool_elt_at_index (tsm->users, user_index);
1104  if (u->nstaticsessions)
1105  {
1106  head_index = u->sessions_per_user_list_head_index;
1107  head = pool_elt_at_index (tsm->list_pool, head_index);
1108  elt_index = head->next;
1109  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1110  ses_index = elt->value;
1111  while (ses_index != ~0)
1112  {
1113  s = pool_elt_at_index (tsm->sessions, ses_index);
1114  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1115  ses_index = elt->value;
1116 
1117  if (!addr_only)
1118  {
1119  if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1120  (clib_net_to_host_u16 (s->out2in.port) !=
1121  e_port))
1122  continue;
1123  }
1124 
1125  if (is_lb_session (s))
1126  continue;
1127 
1128  if (!snat_is_session_static (s))
1129  continue;
1130 
1131  nat_free_session_data (sm, s,
1132  tsm - sm->per_thread_data, 0);
1133  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1134 
1135  if (!addr_only && !sm->endpoint_dependent)
1136  break;
1137  }
1138  }
1139  }
1140  }
1141 
1142  fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1143  if (pool_elts (m->locals))
1144  return 0;
1145 
1146  m_key.addr = m->external_addr;
1147  m_key.port = m->external_port;
1148  m_key.fib_index = 0;
1149  kv.key = m_key.as_u64;
1150  clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1151 
1152  vec_free (m->tag);
1153  vec_free (m->workers);
1154  /* Delete static mapping from pool */
1155  pool_put (sm->static_mappings, m);
1156  }
1157 
1158  if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1159  return 0;
1160 
1161  /* Add/delete external address to FIB */
1162  /* *INDENT-OFF* */
1163  pool_foreach (interface, sm->interfaces,
1164  ({
1165  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1166  continue;
1167 
1168  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1169  break;
1170  }));
1171  pool_foreach (interface, sm->output_feature_interfaces,
1172  ({
1173  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1174  continue;
1175 
1176  snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1177  break;
1178  }));
1179  /* *INDENT-ON* */
1180 
1181  return 0;
1182 }
1183 
1184 int
1187  nat44_lb_addr_port_t * locals, u8 is_add,
1188  twice_nat_type_t twice_nat, u8 out2in_only,
1189  u8 * tag, u32 affinity)
1190 {
1191  snat_main_t *sm = &snat_main;
1193  snat_session_key_t m_key;
1195  snat_address_t *a = 0;
1196  int i;
1197  nat44_lb_addr_port_t *local;
1198  u32 elt_index, head_index, ses_index;
1200  snat_user_key_t u_key;
1201  snat_user_t *u;
1202  snat_session_t *s;
1203  dlist_elt_t *head, *elt;
1204  uword *bitmap = 0;
1205 
1206  if (!sm->endpoint_dependent)
1207  return VNET_API_ERROR_FEATURE_DISABLED;
1208 
1209  m_key.addr = e_addr;
1210  m_key.port = e_port;
1211  m_key.protocol = proto;
1212  m_key.fib_index = 0;
1213  kv.key = m_key.as_u64;
1214  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1215  m = 0;
1216  else
1217  m = pool_elt_at_index (sm->static_mappings, value.value);
1218 
1219  if (is_add)
1220  {
1221  if (m)
1222  return VNET_API_ERROR_VALUE_EXIST;
1223 
1224  if (vec_len (locals) < 2)
1225  return VNET_API_ERROR_INVALID_VALUE;
1226 
1227  /* Find external address in allocated addresses and reserve port for
1228  address and port pair mapping when dynamic translations enabled */
1229  if (!(sm->static_mapping_only || out2in_only))
1230  {
1231  for (i = 0; i < vec_len (sm->addresses); i++)
1232  {
1233  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1234  {
1235  a = sm->addresses + i;
1236  /* External port must be unused */
1237  switch (proto)
1238  {
1239 #define _(N, j, n, s) \
1240  case SNAT_PROTOCOL_##N: \
1241  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1242  return VNET_API_ERROR_INVALID_VALUE; \
1243  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1244  if (e_port > 1024) \
1245  { \
1246  a->busy_##n##_ports++; \
1247  a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1248  } \
1249  break;
1251 #undef _
1252  default:
1253  nat_elog_info ("unknown protocol");
1254  return VNET_API_ERROR_INVALID_VALUE_2;
1255  }
1256  break;
1257  }
1258  }
1259  /* External address must be allocated */
1260  if (!a)
1261  return VNET_API_ERROR_NO_SUCH_ENTRY;
1262  }
1263 
1264  pool_get (sm->static_mappings, m);
1265  clib_memset (m, 0, sizeof (*m));
1266  m->tag = vec_dup (tag);
1267  m->external_addr = e_addr;
1268  m->external_port = e_port;
1269  m->proto = proto;
1270  m->twice_nat = twice_nat;
1272  if (out2in_only)
1274  m->affinity = affinity;
1275 
1276  if (affinity)
1279  else
1281 
1282  m_key.addr = m->external_addr;
1283  m_key.port = m->external_port;
1284  m_key.protocol = m->proto;
1285  m_key.fib_index = 0;
1286  kv.key = m_key.as_u64;
1287  kv.value = m - sm->static_mappings;
1288  if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1289  {
1290  nat_elog_err ("static_mapping_by_external key add failed");
1291  return VNET_API_ERROR_UNSPECIFIED;
1292  }
1293 
1294  m_key.fib_index = m->fib_index;
1295  for (i = 0; i < vec_len (locals); i++)
1296  {
1297  locals[i].fib_index =
1299  locals[i].vrf_id,
1300  nat_fib_src_low);
1301  m_key.addr = locals[i].addr;
1302  m_key.fib_index = locals[i].fib_index;
1303  if (!out2in_only)
1304  {
1305  m_key.port = locals[i].port;
1306  kv.key = m_key.as_u64;
1307  kv.value = m - sm->static_mappings;
1308  clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1309  }
1310  locals[i].prefix = (i == 0) ? locals[i].probability :
1311  (locals[i - 1].prefix + locals[i].probability);
1312  pool_get (m->locals, local);
1313  *local = locals[i];
1314  if (sm->num_workers > 1)
1315  {
1316  ip4_header_t ip = {
1317  .src_address = locals[i].addr,
1318  };
1319  bitmap =
1320  clib_bitmap_set (bitmap,
1321  sm->worker_in2out_cb (&ip, m->fib_index, 0),
1322  1);
1323  }
1324  }
1325 
1326  /* Assign workers */
1327  if (sm->num_workers > 1)
1328  {
1329  /* *INDENT-OFF* */
1330  clib_bitmap_foreach (i, bitmap,
1331  ({
1332  vec_add1(m->workers, i);
1333  }));
1334  /* *INDENT-ON* */
1335  }
1336  }
1337  else
1338  {
1339  if (!m)
1340  return VNET_API_ERROR_NO_SUCH_ENTRY;
1341 
1342  if (!is_lb_static_mapping (m))
1343  return VNET_API_ERROR_INVALID_VALUE;
1344 
1345  /* Free external address port */
1346  if (!(sm->static_mapping_only || out2in_only))
1347  {
1348  for (i = 0; i < vec_len (sm->addresses); i++)
1349  {
1350  if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1351  {
1352  a = sm->addresses + i;
1353  switch (proto)
1354  {
1355 #define _(N, j, n, s) \
1356  case SNAT_PROTOCOL_##N: \
1357  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1358  if (e_port > 1024) \
1359  { \
1360  a->busy_##n##_ports--; \
1361  a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1362  } \
1363  break;
1365 #undef _
1366  default:
1367  nat_elog_info ("unknown protocol");
1368  return VNET_API_ERROR_INVALID_VALUE_2;
1369  }
1370  break;
1371  }
1372  }
1373  }
1374 
1375  m_key.addr = m->external_addr;
1376  m_key.port = m->external_port;
1377  m_key.protocol = m->proto;
1378  m_key.fib_index = 0;
1379  kv.key = m_key.as_u64;
1380  if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1381  {
1382  nat_elog_err ("static_mapping_by_external key del failed");
1383  return VNET_API_ERROR_UNSPECIFIED;
1384  }
1385 
1386  /* *INDENT-OFF* */
1387  pool_foreach (local, m->locals,
1388  ({
1389  fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1390  nat_fib_src_low);
1391  m_key.addr = local->addr;
1392  if (!out2in_only)
1393  {
1394  m_key.port = local->port;
1395  m_key.fib_index = local->fib_index;
1396  kv.key = m_key.as_u64;
1397  if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1398  {
1399  nat_elog_err ("static_mapping_by_local key del failed");
1400  return VNET_API_ERROR_UNSPECIFIED;
1401  }
1402  }
1403 
1404  if (sm->num_workers > 1)
1405  {
1406  ip4_header_t ip = {
1407  .src_address = local->addr,
1408  };
1409  tsm = vec_elt_at_index (sm->per_thread_data,
1410  sm->worker_in2out_cb (&ip, m->fib_index, 0));
1411  }
1412  else
1413  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1414 
1415  /* Delete sessions */
1416  u_key.addr = local->addr;
1417  u_key.fib_index = local->fib_index;
1418  kv.key = u_key.as_u64;
1419  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1420  {
1421  u = pool_elt_at_index (tsm->users, value.value);
1422  if (u->nstaticsessions)
1423  {
1424  head_index = u->sessions_per_user_list_head_index;
1425  head = pool_elt_at_index (tsm->list_pool, head_index);
1426  elt_index = head->next;
1427  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1428  ses_index = elt->value;
1429  while (ses_index != ~0)
1430  {
1431  s = pool_elt_at_index (tsm->sessions, ses_index);
1432  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1433  ses_index = elt->value;
1434 
1435  if (!(is_lb_session (s)))
1436  continue;
1437 
1438  if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1439  (clib_net_to_host_u16 (s->in2out.port) != local->port))
1440  continue;
1441 
1442  nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1443  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1444  }
1445  }
1446  }
1447  }));
1448  /* *INDENT-ON* */
1449  if (m->affinity)
1450  nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1451  pool_free (m->locals);
1452  vec_free (m->tag);
1453  vec_free (m->workers);
1454 
1455  pool_put (sm->static_mappings, m);
1456  }
1457 
1458  return 0;
1459 }
1460 
1461 int
1463  ip4_address_t l_addr, u16 l_port,
1465  u8 probability, u8 is_add)
1466 {
1467  snat_main_t *sm = &snat_main;
1468  snat_static_mapping_t *m = 0;
1469  snat_session_key_t m_key;
1471  nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1473  snat_user_key_t u_key;
1474  snat_user_t *u;
1475  snat_session_t *s;
1476  dlist_elt_t *head, *elt;
1477  u32 elt_index, head_index, ses_index, *locals = 0;
1478  uword *bitmap = 0;
1479  int i;
1480 
1481  if (!sm->endpoint_dependent)
1482  return VNET_API_ERROR_FEATURE_DISABLED;
1483 
1484  m_key.addr = e_addr;
1485  m_key.port = e_port;
1486  m_key.protocol = proto;
1487  m_key.fib_index = 0;
1488  kv.key = m_key.as_u64;
1489  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1490  m = pool_elt_at_index (sm->static_mappings, value.value);
1491 
1492  if (!m)
1493  return VNET_API_ERROR_NO_SUCH_ENTRY;
1494 
1495  if (!is_lb_static_mapping (m))
1496  return VNET_API_ERROR_INVALID_VALUE;
1497 
1498  /* *INDENT-OFF* */
1499  pool_foreach (local, m->locals,
1500  ({
1501  if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1502  (local->vrf_id == vrf_id))
1503  {
1504  match_local = local;
1505  break;
1506  }
1507  }));
1508  /* *INDENT-ON* */
1509 
1510  if (is_add)
1511  {
1512  if (match_local)
1513  return VNET_API_ERROR_VALUE_EXIST;
1514 
1515  pool_get (m->locals, local);
1516  clib_memset (local, 0, sizeof (*local));
1517  local->addr.as_u32 = l_addr.as_u32;
1518  local->port = l_port;
1519  local->probability = probability;
1520  local->vrf_id = vrf_id;
1521  local->fib_index =
1523  nat_fib_src_low);
1524 
1526  {
1527  m_key.addr = l_addr;
1528  m_key.port = l_port;
1529  m_key.fib_index = local->fib_index;
1530  kv.key = m_key.as_u64;
1531  kv.value = m - sm->static_mappings;
1532  if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1533  nat_elog_err ("static_mapping_by_local key add failed");
1534  }
1535  }
1536  else
1537  {
1538  if (!match_local)
1539  return VNET_API_ERROR_NO_SUCH_ENTRY;
1540 
1541  if (pool_elts (m->locals) < 3)
1542  return VNET_API_ERROR_UNSPECIFIED;
1543 
1544  fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1545  nat_fib_src_low);
1546 
1548  {
1549  m_key.addr = l_addr;
1550  m_key.port = l_port;
1551  m_key.fib_index = match_local->fib_index;
1552  kv.key = m_key.as_u64;
1553  if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1554  nat_elog_err ("static_mapping_by_local key del failed");
1555  }
1556 
1557  if (sm->num_workers > 1)
1558  {
1559  ip4_header_t ip = {
1560  .src_address = local->addr,
1561  };
1562  tsm = vec_elt_at_index (sm->per_thread_data,
1563  sm->worker_in2out_cb (&ip, m->fib_index,
1564  0));
1565  }
1566  else
1567  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1568 
1569  /* Delete sessions */
1570  u_key.addr = match_local->addr;
1571  u_key.fib_index = match_local->fib_index;
1572  kv.key = u_key.as_u64;
1573  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1574  {
1575  u = pool_elt_at_index (tsm->users, value.value);
1576  if (u->nstaticsessions)
1577  {
1578  head_index = u->sessions_per_user_list_head_index;
1579  head = pool_elt_at_index (tsm->list_pool, head_index);
1580  elt_index = head->next;
1581  elt = pool_elt_at_index (tsm->list_pool, elt_index);
1582  ses_index = elt->value;
1583  while (ses_index != ~0)
1584  {
1585  s = pool_elt_at_index (tsm->sessions, ses_index);
1586  elt = pool_elt_at_index (tsm->list_pool, elt->next);
1587  ses_index = elt->value;
1588 
1589  if (!(is_lb_session (s)))
1590  continue;
1591 
1592  if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1593  (clib_net_to_host_u16 (s->in2out.port) !=
1594  match_local->port))
1595  continue;
1596 
1597  nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1598  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1599  }
1600  }
1601  }
1602 
1603  pool_put (m->locals, match_local);
1604  }
1605 
1606  vec_free (m->workers);
1607 
1608  /* *INDENT-OFF* */
1609  pool_foreach (local, m->locals,
1610  ({
1611  vec_add1 (locals, local - m->locals);
1612  if (sm->num_workers > 1)
1613  {
1614  ip4_header_t ip;
1615  ip.src_address.as_u32 = local->addr.as_u32,
1616  bitmap = clib_bitmap_set (bitmap,
1617  sm->worker_in2out_cb (&ip, local->fib_index, 0),
1618  1);
1619  }
1620  }));
1621  /* *INDENT-ON* */
1622 
1623  ASSERT (vec_len (locals) > 1);
1624 
1625  local = pool_elt_at_index (m->locals, locals[0]);
1626  local->prefix = local->probability;
1627  for (i = 1; i < vec_len (locals); i++)
1628  {
1629  local = pool_elt_at_index (m->locals, locals[i]);
1630  prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1631  local->prefix = local->probability + prev_local->prefix;
1632  }
1633 
1634  /* Assign workers */
1635  if (sm->num_workers > 1)
1636  {
1637  /* *INDENT-OFF* */
1638  clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1639  /* *INDENT-ON* */
1640  }
1641 
1642  return 0;
1643 }
1644 
1645 int
1647  u8 twice_nat)
1648 {
1649  snat_address_t *a = 0;
1650  snat_session_t *ses;
1651  u32 *ses_to_be_removed = 0, *ses_index;
1654  snat_interface_t *interface;
1655  int i;
1656  snat_address_t *addresses =
1657  twice_nat ? sm->twice_nat_addresses : sm->addresses;
1658 
1659  /* Find SNAT address */
1660  for (i = 0; i < vec_len (addresses); i++)
1661  {
1662  if (addresses[i].addr.as_u32 == addr.as_u32)
1663  {
1664  a = addresses + i;
1665  break;
1666  }
1667  }
1668  if (!a)
1669  return VNET_API_ERROR_NO_SUCH_ENTRY;
1670 
1671  if (delete_sm)
1672  {
1673  /* *INDENT-OFF* */
1674  pool_foreach (m, sm->static_mappings,
1675  ({
1676  if (m->external_addr.as_u32 == addr.as_u32)
1677  (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1678  m->local_port, m->external_port,
1679  m->vrf_id, is_addr_only_static_mapping(m), ~0,
1680  m->proto, 0, m->twice_nat,
1681  is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1682  }));
1683  /* *INDENT-ON* */
1684  }
1685  else
1686  {
1687  /* Check if address is used in some static mapping */
1689  {
1690  nat_elog_notice ("address used in static mapping");
1691  return VNET_API_ERROR_UNSPECIFIED;
1692  }
1693  }
1694 
1695  if (a->fib_index != ~0)
1697 
1698  /* Delete sessions using address */
1699  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1700  {
1701  /* *INDENT-OFF* */
1702  vec_foreach (tsm, sm->per_thread_data)
1703  {
1704  pool_foreach (ses, tsm->sessions, ({
1705  if (ses->out2in.addr.as_u32 == addr.as_u32)
1706  {
1707  nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1708  vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1709  }
1710  }));
1711 
1712  vec_foreach (ses_index, ses_to_be_removed)
1713  {
1714  ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1715  nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1716  }
1717 
1718  vec_free (ses_to_be_removed);
1719  }
1720  /* *INDENT-ON* */
1721  }
1722 
1723 #define _(N, i, n, s) \
1724  clib_bitmap_free (a->busy_##n##_port_bitmap); \
1725  vec_free (a->busy_##n##_ports_per_thread);
1727 #undef _
1728  if (twice_nat)
1729  {
1730  vec_del1 (sm->twice_nat_addresses, i);
1731  return 0;
1732  }
1733  else
1734  vec_del1 (sm->addresses, i);
1735 
1736  /* Delete external address from FIB */
1737  /* *INDENT-OFF* */
1738  pool_foreach (interface, sm->interfaces,
1739  ({
1740  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1741  continue;
1742 
1743  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1744  break;
1745  }));
1746  pool_foreach (interface, sm->output_feature_interfaces,
1747  ({
1748  if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1749  continue;
1750 
1751  snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1752  break;
1753  }));
1754  /* *INDENT-ON* */
1755 
1756  return 0;
1757 }
1758 
1759 int
1760 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1761 {
1762  snat_main_t *sm = &snat_main;
1764  const char *feature_name, *del_feature_name;
1765  snat_address_t *ap;
1767  snat_det_map_t *dm;
1768  nat_outside_fib_t *outside_fib;
1770  sw_if_index);
1771 
1772  if (sm->out2in_dpo && !is_inside)
1773  return VNET_API_ERROR_UNSUPPORTED;
1774 
1775  /* *INDENT-OFF* */
1777  ({
1778  if (i->sw_if_index == sw_if_index)
1779  return VNET_API_ERROR_VALUE_EXIST;
1780  }));
1781  /* *INDENT-ON* */
1782 
1784  feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1785  else
1786  {
1787  if (sm->num_workers > 1 && !sm->deterministic)
1788  feature_name =
1789  is_inside ? "nat44-in2out-worker-handoff" :
1790  "nat44-out2in-worker-handoff";
1791  else if (sm->deterministic)
1792  feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1793  else if (sm->endpoint_dependent)
1794  {
1795  feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1796  }
1797  else
1798  feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1799  }
1800 
1801  if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1802  sm->fq_in2out_index =
1804 
1805  if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1806  sm->fq_out2in_index =
1808 
1809  if (!is_inside)
1810  {
1811  /* *INDENT-OFF* */
1812  vec_foreach (outside_fib, sm->outside_fibs)
1813  {
1814  if (outside_fib->fib_index == fib_index)
1815  {
1816  if (is_del)
1817  {
1818  outside_fib->refcount--;
1819  if (!outside_fib->refcount)
1820  vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1821  }
1822  else
1823  outside_fib->refcount++;
1824  goto feature_set;
1825  }
1826  }
1827  /* *INDENT-ON* */
1828  if (!is_del)
1829  {
1830  vec_add2 (sm->outside_fibs, outside_fib, 1);
1831  outside_fib->refcount = 1;
1832  outside_fib->fib_index = fib_index;
1833  }
1834  }
1835 feature_set:
1836  /* *INDENT-OFF* */
1837  pool_foreach (i, sm->interfaces,
1838  ({
1839  if (i->sw_if_index == sw_if_index)
1840  {
1841  if (is_del)
1842  {
1843  if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1844  {
1845  if (is_inside)
1846  i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1847  else
1848  i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1849 
1850  if (sm->num_workers > 1 && !sm->deterministic)
1851  {
1852  del_feature_name = "nat44-handoff-classify";
1853  feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1854  "nat44-out2in-worker-handoff";
1855  }
1856  else if (sm->deterministic)
1857  {
1858  del_feature_name = "nat44-det-classify";
1859  feature_name = !is_inside ? "nat44-det-in2out" :
1860  "nat44-det-out2in";
1861  }
1862  else if (sm->endpoint_dependent)
1863  {
1864  del_feature_name = "nat44-ed-classify";
1865  feature_name = !is_inside ? "nat-pre-in2out" :
1866  "nat-pre-out2in";
1867  }
1868  else
1869  {
1870  del_feature_name = "nat44-classify";
1871  feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1872  }
1873 
1874  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1875  if (rv)
1876  return rv;
1877  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1878  sw_if_index, 0, 0, 0);
1879  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1880  sw_if_index, 1, 0, 0);
1881  if (!is_inside)
1882  {
1883  if (sm->endpoint_dependent)
1884  vnet_feature_enable_disable ("ip4-local",
1885  "nat44-ed-hairpinning",
1886  sw_if_index, 1, 0, 0);
1887  else if (!sm->deterministic)
1888  vnet_feature_enable_disable ("ip4-local",
1889  "nat44-hairpinning",
1890  sw_if_index, 1, 0, 0);
1891  }
1892  }
1893  else
1894  {
1895  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1896  if (rv)
1897  return rv;
1898  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1899  sw_if_index, 0, 0, 0);
1900  pool_put (sm->interfaces, i);
1901  if (is_inside)
1902  {
1903  if (sm->endpoint_dependent)
1904  vnet_feature_enable_disable ("ip4-local",
1905  "nat44-ed-hairpinning",
1906  sw_if_index, 0, 0, 0);
1907  else if (!sm->deterministic)
1908  vnet_feature_enable_disable ("ip4-local",
1909  "nat44-hairpinning",
1910  sw_if_index, 0, 0, 0);
1911  }
1912  }
1913  }
1914  else
1915  {
1916  if ((nat_interface_is_inside(i) && is_inside) ||
1917  (nat_interface_is_outside(i) && !is_inside))
1918  return 0;
1919 
1920  if (sm->num_workers > 1 && !sm->deterministic)
1921  {
1922  del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1923  "nat44-out2in-worker-handoff";
1924  feature_name = "nat44-handoff-classify";
1925  }
1926  else if (sm->deterministic)
1927  {
1928  del_feature_name = !is_inside ? "nat44-det-in2out" :
1929  "nat44-det-out2in";
1930  feature_name = "nat44-det-classify";
1931  }
1932  else if (sm->endpoint_dependent)
1933  {
1934  del_feature_name = !is_inside ? "nat-pre-in2out" :
1935  "nat-pre-out2in";
1936 
1937  feature_name = "nat44-ed-classify";
1938  }
1939  else
1940  {
1941  del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1942  feature_name = "nat44-classify";
1943  }
1944 
1945  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1946  if (rv)
1947  return rv;
1948  vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1949  sw_if_index, 0, 0, 0);
1950  vnet_feature_enable_disable ("ip4-unicast", feature_name,
1951  sw_if_index, 1, 0, 0);
1952  if (!is_inside)
1953  {
1954  if (sm->endpoint_dependent)
1955  vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1956  sw_if_index, 0, 0, 0);
1957  else if (!sm->deterministic)
1958  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1959  sw_if_index, 0, 0, 0);
1960  }
1961  goto set_flags;
1962  }
1963 
1964  goto fib;
1965  }
1966  }));
1967  /* *INDENT-ON* */
1968 
1969  if (is_del)
1970  return VNET_API_ERROR_NO_SUCH_ENTRY;
1971 
1972  pool_get (sm->interfaces, i);
1973  i->sw_if_index = sw_if_index;
1974  i->flags = 0;
1975  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1976  0);
1977 
1979  if (rv)
1980  return rv;
1981 
1982  if (is_inside && !sm->out2in_dpo)
1983  {
1984  if (sm->endpoint_dependent)
1985  vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1986  sw_if_index, 1, 0, 0);
1987  else if (!sm->deterministic)
1988  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1989  sw_if_index, 1, 0, 0);
1990  }
1991 
1992 set_flags:
1993  if (is_inside)
1994  {
1995  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1996  return 0;
1997  }
1998  else
1999  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2000 
2001  /* Add/delete external addresses to FIB */
2002 fib:
2003  /* *INDENT-OFF* */
2004  vec_foreach (ap, sm->addresses)
2005  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2006 
2007  pool_foreach (m, sm->static_mappings,
2008  ({
2009  if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2010  continue;
2011 
2012  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2013  }));
2014 
2015  pool_foreach (dm, sm->det_maps,
2016  ({
2017  snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2018  }));
2019  /* *INDENT-ON* */
2020 
2021  return 0;
2022 }
2023 
2024 int
2026  u8 is_inside, int is_del)
2027 {
2028  snat_main_t *sm = &snat_main;
2030  snat_address_t *ap;
2032  nat_outside_fib_t *outside_fib;
2034  sw_if_index);
2035 
2036 
2037  if (sm->deterministic ||
2039  return VNET_API_ERROR_UNSUPPORTED;
2040 
2041  /* *INDENT-OFF* */
2042  pool_foreach (i, sm->interfaces,
2043  ({
2044  if (i->sw_if_index == sw_if_index)
2045  return VNET_API_ERROR_VALUE_EXIST;
2046  }));
2047  /* *INDENT-ON* */
2048 
2049  if (!is_inside)
2050  {
2051  /* *INDENT-OFF* */
2052  vec_foreach (outside_fib, sm->outside_fibs)
2053  {
2054  if (outside_fib->fib_index == fib_index)
2055  {
2056  if (is_del)
2057  {
2058  outside_fib->refcount--;
2059  if (!outside_fib->refcount)
2060  vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2061  }
2062  else
2063  outside_fib->refcount++;
2064  goto feature_set;
2065  }
2066  }
2067  /* *INDENT-ON* */
2068  if (!is_del)
2069  {
2070  vec_add2 (sm->outside_fibs, outside_fib, 1);
2071  outside_fib->refcount = 1;
2072  outside_fib->fib_index = fib_index;
2073  }
2074  }
2075 
2076 feature_set:
2077  if (is_inside)
2078  {
2079  if (sm->endpoint_dependent)
2080  {
2081  int rv =
2082  ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2083  if (rv)
2084  return rv;
2085  rv =
2087  !is_del);
2088  if (rv)
2089  return rv;
2090  vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2091  sw_if_index, !is_del, 0, 0);
2092  vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2093  sw_if_index, !is_del, 0, 0);
2094  }
2095  else
2096  {
2097  int rv =
2098  ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2099  if (rv)
2100  return rv;
2101  rv =
2103  !is_del);
2104  if (rv)
2105  return rv;
2106  vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2107  sw_if_index, !is_del, 0, 0);
2108  vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2109  sw_if_index, !is_del, 0, 0);
2110  }
2111  goto fq;
2112  }
2113 
2114  if (sm->num_workers > 1)
2115  {
2116  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2117  if (rv)
2118  return rv;
2119  rv =
2120  ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2121  if (rv)
2122  return rv;
2123  vnet_feature_enable_disable ("ip4-unicast",
2124  "nat44-out2in-worker-handoff",
2125  sw_if_index, !is_del, 0, 0);
2126  vnet_feature_enable_disable ("ip4-output",
2127  "nat44-in2out-output-worker-handoff",
2128  sw_if_index, !is_del, 0, 0);
2129  }
2130  else
2131  {
2132  if (sm->endpoint_dependent)
2133  {
2134  int rv =
2135  ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2136  if (rv)
2137  return rv;
2138  rv =
2140  !is_del);
2141  if (rv)
2142  return rv;
2143  vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2144  sw_if_index, !is_del, 0, 0);
2145  vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2146  sw_if_index, !is_del, 0, 0);
2147  }
2148  else
2149  {
2150  int rv =
2151  ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2152  if (rv)
2153  return rv;
2154  rv =
2156  !is_del);
2157  if (rv)
2158  return rv;
2159  vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2160  sw_if_index, !is_del, 0, 0);
2161  vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2162  sw_if_index, !is_del, 0, 0);
2163  }
2164  }
2165 
2166 fq:
2167  if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2170 
2171  if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2172  sm->fq_out2in_index =
2174 
2175  /* *INDENT-OFF* */
2177  ({
2178  if (i->sw_if_index == sw_if_index)
2179  {
2180  if (is_del)
2181  pool_put (sm->output_feature_interfaces, i);
2182  else
2183  return VNET_API_ERROR_VALUE_EXIST;
2184 
2185  goto fib;
2186  }
2187  }));
2188  /* *INDENT-ON* */
2189 
2190  if (is_del)
2191  return VNET_API_ERROR_NO_SUCH_ENTRY;
2192 
2193  pool_get (sm->output_feature_interfaces, i);
2194  i->sw_if_index = sw_if_index;
2195  i->flags = 0;
2196  if (is_inside)
2197  i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2198  else
2199  i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2200 
2201  /* Add/delete external addresses to FIB */
2202 fib:
2203  if (is_inside)
2204  return 0;
2205 
2206  /* *INDENT-OFF* */
2207  vec_foreach (ap, sm->addresses)
2208  snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2209 
2210  pool_foreach (m, sm->static_mappings,
2211  ({
2212  if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2213  continue;
2214 
2215  snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2216  }));
2217  /* *INDENT-ON* */
2218 
2219  return 0;
2220 }
2221 
2222 int
2224 {
2225  snat_main_t *sm = &snat_main;
2226  int i, j = 0;
2227 
2228  if (sm->num_workers < 2)
2229  return VNET_API_ERROR_FEATURE_DISABLED;
2230 
2231  if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2232  return VNET_API_ERROR_INVALID_WORKER;
2233 
2234  vec_free (sm->workers);
2235  /* *INDENT-OFF* */
2236  clib_bitmap_foreach (i, bitmap,
2237  ({
2238  vec_add1(sm->workers, i);
2241  j++;
2242  }));
2243  /* *INDENT-ON* */
2244 
2245  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2246  sm->num_snat_thread = _vec_len (sm->workers);
2247 
2248  return 0;
2249 }
2250 
2251 static void
2253  u32 old_fib_index)
2254 {
2255  snat_main_t *sm = &snat_main;
2256  nat_outside_fib_t *outside_fib;
2258  u8 is_add = 1;
2259  u8 match = 0;
2260 
2261  if (new_fib_index == old_fib_index)
2262  return;
2263 
2264  if (!vec_len (sm->outside_fibs))
2265  return;
2266 
2267  /* *INDENT-OFF* */
2268  pool_foreach (i, sm->interfaces,
2269  ({
2270  if (i->sw_if_index == sw_if_index)
2271  {
2272  if (!(nat_interface_is_outside (i)))
2273  return;
2274  match = 1;
2275  }
2276  }));
2277 
2278  pool_foreach (i, sm->output_feature_interfaces,
2279  ({
2280  if (i->sw_if_index == sw_if_index)
2281  {
2282  if (!(nat_interface_is_outside (i)))
2283  return;
2284  match = 1;
2285  }
2286  }));
2287  /* *INDENT-ON* */
2288 
2289  if (!match)
2290  return;
2291 
2292  vec_foreach (outside_fib, sm->outside_fibs)
2293  {
2294  if (outside_fib->fib_index == old_fib_index)
2295  {
2296  outside_fib->refcount--;
2297  if (!outside_fib->refcount)
2298  vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2299  break;
2300  }
2301  }
2302 
2303  vec_foreach (outside_fib, sm->outside_fibs)
2304  {
2305  if (outside_fib->fib_index == new_fib_index)
2306  {
2307  outside_fib->refcount++;
2308  is_add = 0;
2309  break;
2310  }
2311  }
2312 
2313  if (is_add)
2314  {
2315  vec_add2 (sm->outside_fibs, outside_fib, 1);
2316  outside_fib->refcount = 1;
2317  outside_fib->fib_index = new_fib_index;
2318  }
2319 }
2320 
2321 static void
2323  uword opaque,
2324  u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2325 {
2326  snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2327 }
2328 
2329 static void
2331  uword opaque,
2332  u32 sw_if_index,
2334  u32 address_length,
2335  u32 if_address_index, u32 is_delete);
2336 
2337 static void
2339  uword opaque,
2340  u32 sw_if_index,
2341  ip4_address_t * address,
2342  u32 address_length,
2343  u32 if_address_index, u32 is_delete);
2344 
2345 static int
2347  u32 fib_index,
2348  u32 thread_index,
2349  snat_session_key_t * k,
2350  u16 port_per_thread, u32 snat_thread_index);
2351 
2352 static clib_error_t *
2354 {
2355  snat_main_t *sm = &snat_main;
2356  clib_error_t *error = 0;
2357  ip4_main_t *im = &ip4_main;
2358  ip_lookup_main_t *lm = &im->lookup_main;
2359  uword *p;
2362  uword *bitmap = 0;
2363  u32 i;
2365  vlib_node_t *node;
2366 
2367  sm->vlib_main = vm;
2368  sm->vnet_main = vnet_get_main ();
2369  sm->ip4_main = im;
2370  sm->ip4_lookup_main = lm;
2371  sm->api_main = vlibapi_get_main ();
2372  sm->first_worker_index = 0;
2373  sm->num_workers = 0;
2374  sm->num_snat_thread = 1;
2375  sm->workers = 0;
2376  sm->port_per_thread = 0xffff - 1024;
2377  sm->fq_in2out_index = ~0;
2378  sm->fq_in2out_output_index = ~0;
2379  sm->fq_out2in_index = ~0;
2380 
2381 
2383  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2384  sm->forwarding_enabled = 0;
2385  sm->log_class = vlib_log_register_class ("nat", 0);
2386  sm->log_level = SNAT_LOG_ERROR;
2387  sm->mss_clamping = 0;
2388 
2389  node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2390  sm->error_node_index = node->index;
2391 
2392  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2393  sm->pre_in2out_node_index = node->index;
2394  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2395  sm->pre_out2in_node_index = node->index;
2396 
2397  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2398  sm->pre_in2out_node_index = node->index;
2399 
2400  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2401  sm->pre_out2in_node_index = node->index;
2402 
2403  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2404  sm->in2out_node_index = node->index;
2405  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2406  sm->in2out_output_node_index = node->index;
2407  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2408  sm->in2out_fast_node_index = node->index;
2409  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2410  sm->in2out_slowpath_node_index = node->index;
2411  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2413 
2414  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2415  sm->ed_in2out_node_index = node->index;
2416  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2418 
2419  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2420  sm->out2in_node_index = node->index;
2421  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2422  sm->out2in_fast_node_index = node->index;
2423 
2424  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2425  sm->ed_out2in_node_index = node->index;
2426  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2428 
2429  node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2430  sm->det_in2out_node_index = node->index;
2431  node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2432  sm->det_out2in_node_index = node->index;
2433 
2434  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2435  sm->hairpinning_node_index = node->index;
2436  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2437  sm->hairpin_dst_node_index = node->index;
2438  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2439  sm->hairpin_src_node_index = node->index;
2440  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2441  sm->ed_hairpinning_node_index = node->index;
2442  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2443  sm->ed_hairpin_dst_node_index = node->index;
2444  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2445  sm->ed_hairpin_src_node_index = node->index;
2446 
2447  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2448  if (p)
2449  {
2450  tr = (vlib_thread_registration_t *) p[0];
2451  if (tr)
2452  {
2453  sm->num_workers = tr->count;
2454  sm->first_worker_index = tr->first_index;
2455  }
2456  }
2457 
2458  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2459 
2460  /* Use all available workers by default */
2461  if (sm->num_workers > 1)
2462  {
2463  for (i = 0; i < sm->num_workers; i++)
2464  bitmap = clib_bitmap_set (bitmap, i, 1);
2465  snat_set_workers (bitmap);
2466  clib_bitmap_free (bitmap);
2467  }
2468  else
2469  {
2471  }
2472 
2473  error = snat_api_init (vm, sm);
2474  if (error)
2475  return error;
2476 
2477  /* Set up the interface address add/del callback */
2479  cb4.function_opaque = 0;
2480 
2482 
2484  cb4.function_opaque = 0;
2485 
2487 
2489 
2490  /* Init counters */
2491  sm->total_users.name = "total-users";
2492  sm->total_users.stat_segment_name = "/nat44/total-users";
2495  sm->total_sessions.name = "total-sessions";
2496  sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2499 
2500  /* Init IPFIX logging */
2502 
2503  /* Init NAT64 */
2504  error = nat64_init (vm);
2505  if (error)
2506  return error;
2507 
2508  dslite_init (vm);
2509 
2510  nat66_init (vm);
2511 
2512  ip4_table_bind_callback_t cbt4 = {
2514  };
2516 
2517  nat_fib_src_hi = fib_source_allocate ("nat-hi",
2520  nat_fib_src_low = fib_source_allocate ("nat-low",
2523 
2524  return error;
2525 }
2526 
2528 
2529 void
2531  u32 thread_index, snat_session_key_t * k)
2532 {
2533  snat_address_t *a;
2534  u32 address_index;
2535  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2536 
2537  for (address_index = 0; address_index < vec_len (addresses);
2538  address_index++)
2539  {
2540  if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2541  break;
2542  }
2543 
2544  ASSERT (address_index < vec_len (addresses));
2545 
2546  a = addresses + address_index;
2547 
2548  switch (k->protocol)
2549  {
2550 #define _(N, i, n, s) \
2551  case SNAT_PROTOCOL_##N: \
2552  ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2553  port_host_byte_order) == 1); \
2554  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2555  port_host_byte_order, 0); \
2556  a->busy_##n##_ports--; \
2557  a->busy_##n##_ports_per_thread[thread_index]--; \
2558  break;
2560 #undef _
2561  default:
2562  nat_elog_info ("unknown protocol");
2563  return;
2564  }
2565 }
2566 
2567 static int
2569  u32 thread_index, snat_session_key_t * k)
2570 {
2571  snat_address_t *a = 0;
2572  u32 address_index;
2573  u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2574 
2575  for (address_index = 0; address_index < vec_len (addresses);
2576  address_index++)
2577  {
2578  if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2579  continue;
2580 
2581  a = addresses + address_index;
2582  switch (k->protocol)
2583  {
2584 #define _(N, j, n, s) \
2585  case SNAT_PROTOCOL_##N: \
2586  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
2587  return VNET_API_ERROR_INSTANCE_IN_USE; \
2588  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
2589  a->busy_##n##_ports_per_thread[thread_index]++; \
2590  a->busy_##n##_ports++; \
2591  return 0;
2593 #undef _
2594  default:
2595  nat_elog_info ("unknown protocol");
2596  return 1;
2597  }
2598  }
2599 
2600  return VNET_API_ERROR_NO_SUCH_ENTRY;
2601 }
2602 
2603 int
2605  snat_session_key_t match,
2606  snat_session_key_t * mapping,
2607  u8 by_external,
2608  u8 * is_addr_only,
2609  twice_nat_type_t * twice_nat,
2610  lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2611  u8 * is_identity_nat)
2612 {
2615  snat_session_key_t m_key;
2616  clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2617  u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2618  u8 backend_index;
2619  nat44_lb_addr_port_t *local;
2620 
2621  m_key.fib_index = match.fib_index;
2622  if (by_external)
2623  {
2624  mapping_hash = &sm->static_mapping_by_external;
2625  m_key.fib_index = 0;
2626  }
2627 
2628  m_key.addr = match.addr;
2629  m_key.port = clib_net_to_host_u16 (match.port);
2630  m_key.protocol = match.protocol;
2631 
2632  kv.key = m_key.as_u64;
2633 
2634  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2635  {
2636  /* Try address only mapping */
2637  m_key.port = 0;
2638  m_key.protocol = 0;
2639  kv.key = m_key.as_u64;
2640  if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2641  return 1;
2642  }
2643 
2644  m = pool_elt_at_index (sm->static_mappings, value.value);
2645 
2646  if (by_external)
2647  {
2648  if (is_lb_static_mapping (m))
2649  {
2650  if (PREDICT_FALSE (lb != 0))
2651  *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2652  if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2653  match.addr,
2654  match.protocol,
2655  match.port,
2656  &backend_index))
2657  {
2658  local = pool_elt_at_index (m->locals, backend_index);
2659  mapping->addr = local->addr;
2660  mapping->port = clib_host_to_net_u16 (local->port);
2661  mapping->fib_index = local->fib_index;
2662  goto end;
2663  }
2664  // pick locals matching this worker
2665  if (PREDICT_FALSE (sm->num_workers > 1))
2666  {
2667  u32 thread_index = vlib_get_thread_index ();
2668  /* *INDENT-OFF* */
2670  ({
2671  local = pool_elt_at_index (m->locals, i);
2672 
2673  ip4_header_t ip = {
2674  .src_address = local->addr,
2675  };
2676 
2677  if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2678  thread_index)
2679  {
2680  vec_add1 (tmp, i);
2681  }
2682  }));
2683  /* *INDENT-ON* */
2684  ASSERT (vec_len (tmp) != 0);
2685  }
2686  else
2687  {
2688  /* *INDENT-OFF* */
2690  ({
2691  vec_add1 (tmp, i);
2692  }));
2693  /* *INDENT-ON* */
2694  }
2695  hi = vec_len (tmp) - 1;
2696  local = pool_elt_at_index (m->locals, tmp[hi]);
2697  rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2698  while (lo < hi)
2699  {
2700  mid = ((hi - lo) >> 1) + lo;
2701  local = pool_elt_at_index (m->locals, tmp[mid]);
2702  (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2703  }
2704  local = pool_elt_at_index (m->locals, tmp[lo]);
2705  if (!(local->prefix >= rand))
2706  return 1;
2707  mapping->addr = local->addr;
2708  mapping->port = clib_host_to_net_u16 (local->port);
2709  mapping->fib_index = local->fib_index;
2710  if (m->affinity)
2711  {
2712  if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2713  match.protocol, match.port,
2714  tmp[lo], m->affinity,
2716  nat_elog_info ("create affinity record failed");
2717  }
2718  vec_free (tmp);
2719  }
2720  else
2721  {
2722  if (PREDICT_FALSE (lb != 0))
2723  *lb = NO_LB_NAT;
2724  mapping->fib_index = m->fib_index;
2725  mapping->addr = m->local_addr;
2726  /* Address only mapping doesn't change port */
2727  mapping->port = is_addr_only_static_mapping (m) ? match.port
2728  : clib_host_to_net_u16 (m->local_port);
2729  }
2730  mapping->protocol = m->proto;
2731  }
2732  else
2733  {
2734  mapping->addr = m->external_addr;
2735  /* Address only mapping doesn't change port */
2736  mapping->port = is_addr_only_static_mapping (m) ? match.port
2737  : clib_host_to_net_u16 (m->external_port);
2738  mapping->fib_index = sm->outside_fib_index;
2739  }
2740 
2741 end:
2742  if (PREDICT_FALSE (is_addr_only != 0))
2743  *is_addr_only = is_addr_only_static_mapping (m);
2744 
2745  if (PREDICT_FALSE (twice_nat != 0))
2746  *twice_nat = m->twice_nat;
2747 
2748  if (PREDICT_FALSE (is_identity_nat != 0))
2749  *is_identity_nat = is_identity_static_mapping (m);
2750 
2751  return 0;
2752 }
2753 
2756 {
2757  snat_main_t *sm = &snat_main;
2758  return min + random_u32 (&sm->random_seed) /
2759  (random_u32_max () / (max - min + 1) + 1);
2760 }
2761 
2762 int
2764  u32 fib_index,
2765  u32 thread_index,
2766  snat_session_key_t * k,
2767  u16 port_per_thread,
2768  u32 snat_thread_index)
2769 {
2770  snat_main_t *sm = &snat_main;
2771 
2772  return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2773  port_per_thread, snat_thread_index);
2774 }
2775 
2776 static int
2778  u32 fib_index,
2779  u32 thread_index,
2780  snat_session_key_t * k,
2781  u16 port_per_thread, u32 snat_thread_index)
2782 {
2783  int i;
2784  snat_address_t *a, *ga = 0;
2785  u32 portnum;
2786 
2787  for (i = 0; i < vec_len (addresses); i++)
2788  {
2789  a = addresses + i;
2790  switch (k->protocol)
2791  {
2792 #define _(N, j, n, s) \
2793  case SNAT_PROTOCOL_##N: \
2794  if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2795  { \
2796  if (a->fib_index == fib_index) \
2797  { \
2798  while (1) \
2799  { \
2800  portnum = (port_per_thread * \
2801  snat_thread_index) + \
2802  snat_random_port(1, port_per_thread) + 1024; \
2803  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2804  continue; \
2805  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2806  a->busy_##n##_ports_per_thread[thread_index]++; \
2807  a->busy_##n##_ports++; \
2808  k->addr = a->addr; \
2809  k->port = clib_host_to_net_u16(portnum); \
2810  return 0; \
2811  } \
2812  } \
2813  else if (a->fib_index == ~0) \
2814  { \
2815  ga = a; \
2816  } \
2817  } \
2818  break;
2820 #undef _
2821  default:
2822  nat_elog_info ("unknown protocol");
2823  return 1;
2824  }
2825 
2826  }
2827 
2828  if (ga)
2829  {
2830  a = ga;
2831  switch (k->protocol)
2832  {
2833 #define _(N, j, n, s) \
2834  case SNAT_PROTOCOL_##N: \
2835  while (1) \
2836  { \
2837  portnum = (port_per_thread * \
2838  snat_thread_index) + \
2839  snat_random_port(1, port_per_thread) + 1024; \
2840  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2841  continue; \
2842  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2843  a->busy_##n##_ports_per_thread[thread_index]++; \
2844  a->busy_##n##_ports++; \
2845  k->addr = a->addr; \
2846  k->port = clib_host_to_net_u16(portnum); \
2847  return 0; \
2848  }
2849  break;
2851 #undef _
2852  default:
2853  nat_elog_info ("unknown protocol");
2854  return 1;
2855  }
2856  }
2857 
2858  /* Totally out of translations to use... */
2859  snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2860  return 1;
2861 }
2862 
2863 static int
2865  u32 fib_index,
2866  u32 thread_index,
2867  snat_session_key_t * k,
2868  u16 port_per_thread, u32 snat_thread_index)
2869 {
2870  snat_main_t *sm = &snat_main;
2871  snat_address_t *a = addresses;
2872  u16 m, ports, portnum, A, j;
2873  m = 16 - (sm->psid_offset + sm->psid_length);
2874  ports = (1 << (16 - sm->psid_length)) - (1 << m);
2875 
2876  if (!vec_len (addresses))
2877  goto exhausted;
2878 
2879  switch (k->protocol)
2880  {
2881 #define _(N, i, n, s) \
2882  case SNAT_PROTOCOL_##N: \
2883  if (a->busy_##n##_ports < ports) \
2884  { \
2885  while (1) \
2886  { \
2887  A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2888  j = snat_random_port(0, pow2_mask(m)); \
2889  portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2890  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2891  continue; \
2892  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2893  a->busy_##n##_ports++; \
2894  k->addr = a->addr; \
2895  k->port = clib_host_to_net_u16 (portnum); \
2896  return 0; \
2897  } \
2898  } \
2899  break;
2901 #undef _
2902  default:
2903  nat_elog_info ("unknown protocol");
2904  return 1;
2905  }
2906 
2907 exhausted:
2908  /* Totally out of translations to use... */
2909  snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2910  return 1;
2911 }
2912 
2913 static int
2915  u32 fib_index,
2916  u32 thread_index,
2917  snat_session_key_t * k,
2918  u16 port_per_thread, u32 snat_thread_index)
2919 {
2920  snat_main_t *sm = &snat_main;
2921  snat_address_t *a = addresses;
2922  u16 portnum, ports;
2923 
2924  ports = sm->end_port - sm->start_port + 1;
2925 
2926  if (!vec_len (addresses))
2927  goto exhausted;
2928 
2929  switch (k->protocol)
2930  {
2931 #define _(N, i, n, s) \
2932  case SNAT_PROTOCOL_##N: \
2933  if (a->busy_##n##_ports < ports) \
2934  { \
2935  while (1) \
2936  { \
2937  portnum = snat_random_port(sm->start_port, sm->end_port); \
2938  if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2939  continue; \
2940  clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2941  a->busy_##n##_ports++; \
2942  k->addr = a->addr; \
2943  k->port = clib_host_to_net_u16 (portnum); \
2944  return 0; \
2945  } \
2946  } \
2947  break;
2949 #undef _
2950  default:
2951  nat_elog_info ("unknown protocol");
2952  return 1;
2953  }
2954 
2955 exhausted:
2956  /* Totally out of translations to use... */
2957  snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2958  return 1;
2959 }
2960 
2961 void
2963 {
2964  dpo_id_t dpo_v4 = DPO_INVALID;
2965  fib_prefix_t pfx = {
2967  .fp_len = 32,
2968  .fp_addr.ip4.as_u32 = addr.as_u32,
2969  };
2970 
2971  if (is_add)
2972  {
2973  nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2975  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2976  dpo_reset (&dpo_v4);
2977  }
2978  else
2979  {
2981  }
2982 }
2983 
2984 u8 *
2985 format_session_kvp (u8 * s, va_list * args)
2986 {
2987  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2989 
2990  k.as_u64 = v->key;
2991 
2992  s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2993 
2994  return s;
2995 }
2996 
2997 u8 *
2998 format_static_mapping_kvp (u8 * s, va_list * args)
2999 {
3000  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3002 
3003  k.as_u64 = v->key;
3004 
3005  s = format (s, "%U static-mapping-index %llu",
3007 
3008  return s;
3009 }
3010 
3011 u8 *
3012 format_user_kvp (u8 * s, va_list * args)
3013 {
3014  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3015  snat_user_key_t k;
3016 
3017  k.as_u64 = v->key;
3018 
3019  s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
3020  k.fib_index, v->value);
3021 
3022  return s;
3023 }
3024 
3025 u8 *
3026 format_ed_session_kvp (u8 * s, va_list * args)
3027 {
3028  clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3029  nat_ed_ses_key_t k;
3030 
3031  k.as_u64[0] = v->key[0];
3032  k.as_u64[1] = v->key[1];
3033 
3034  s =
3035  format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
3036  format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
3037  format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
3039 
3040  return s;
3041 }
3042 
3043 static u32
3045  u8 is_output)
3046 {
3047  snat_main_t *sm = &snat_main;
3048  u32 next_worker_index = 0;
3049  u32 hash;
3050 
3051  next_worker_index = sm->first_worker_index;
3052  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3053  (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3054 
3055  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3056  next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3057  else
3058  next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3059 
3060  return next_worker_index;
3061 }
3062 
3063 static u32
3065  u32 rx_fib_index0, u8 is_output)
3066 {
3067  snat_main_t *sm = &snat_main;
3068  udp_header_t *udp;
3069  u16 port;
3070  snat_session_key_t m_key;
3073  u32 proto;
3074  u32 next_worker_index = 0;
3075 
3076  /* first try static mappings without port */
3078  {
3079  m_key.addr = ip0->dst_address;
3080  m_key.port = 0;
3081  m_key.protocol = 0;
3082  m_key.fib_index = rx_fib_index0;
3083  kv.key = m_key.as_u64;
3084  if (!clib_bihash_search_8_8
3085  (&sm->static_mapping_by_external, &kv, &value))
3086  {
3087  m = pool_elt_at_index (sm->static_mappings, value.value);
3088  return m->workers[0];
3089  }
3090  }
3091 
3092  proto = ip_proto_to_snat_proto (ip0->protocol);
3093  udp = ip4_next_header (ip0);
3094  port = udp->dst_port;
3095 
3096  /* unknown protocol */
3097  if (PREDICT_FALSE (proto == ~0))
3098  {
3099  /* use current thread */
3100  return vlib_get_thread_index ();
3101  }
3102 
3103  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3104  {
3105  icmp46_header_t *icmp = (icmp46_header_t *) udp;
3106  icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3108  (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3109  port = vnet_buffer (b)->ip.reass.l4_src_port;
3110  else
3111  {
3112  /* if error message, then it's not fragmented and we can access it */
3113  ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3114  proto = ip_proto_to_snat_proto (inner_ip->protocol);
3115  void *l4_header = ip4_next_header (inner_ip);
3116  switch (proto)
3117  {
3118  case SNAT_PROTOCOL_ICMP:
3119  icmp = (icmp46_header_t *) l4_header;
3120  echo = (icmp_echo_header_t *) (icmp + 1);
3121  port = echo->identifier;
3122  break;
3123  case SNAT_PROTOCOL_UDP:
3124  case SNAT_PROTOCOL_TCP:
3125  port = ((tcp_udp_header_t *) l4_header)->src_port;
3126  break;
3127  default:
3128  return vlib_get_thread_index ();
3129  }
3130  }
3131  }
3132 
3133  /* try static mappings with port */
3135  {
3136  m_key.addr = ip0->dst_address;
3137  m_key.port = clib_net_to_host_u16 (port);
3138  m_key.protocol = proto;
3139  m_key.fib_index = rx_fib_index0;
3140  kv.key = m_key.as_u64;
3141  if (!clib_bihash_search_8_8
3142  (&sm->static_mapping_by_external, &kv, &value))
3143  {
3144  m = pool_elt_at_index (sm->static_mappings, value.value);
3145  return m->workers[0];
3146  }
3147  }
3148 
3149  /* worker by outside port */
3150  next_worker_index = sm->first_worker_index;
3151  next_worker_index +=
3152  sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3153  return next_worker_index;
3154 }
3155 
3156 static u32
3158  u8 is_output)
3159 {
3160  snat_main_t *sm = &snat_main;
3161  u32 next_worker_index = sm->first_worker_index;
3162  u32 hash;
3163 
3164  clib_bihash_kv_16_8_t kv16, value16;
3166  udp_header_t *udp;
3167 
3168  if (PREDICT_FALSE (is_output))
3169  {
3170  u32 fib_index = sm->outside_fib_index;
3171  nat_outside_fib_t *outside_fib;
3173  fib_prefix_t pfx = {
3175  .fp_len = 32,
3176  .fp_addr = {
3177  .ip4.as_u32 = ip->dst_address.as_u32,
3178  }
3179  ,
3180  };
3181 
3182  udp = ip4_next_header (ip);
3183 
3184  switch (vec_len (sm->outside_fibs))
3185  {
3186  case 0:
3187  fib_index = sm->outside_fib_index;
3188  break;
3189  case 1:
3190  fib_index = sm->outside_fibs[0].fib_index;
3191  break;
3192  default:
3193  /* *INDENT-OFF* */
3194  vec_foreach (outside_fib, sm->outside_fibs)
3195  {
3196  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3197  if (FIB_NODE_INDEX_INVALID != fei)
3198  {
3199  if (fib_entry_get_resolving_interface (fei) != ~0)
3200  {
3201  fib_index = outside_fib->fib_index;
3202  break;
3203  }
3204  }
3205  }
3206  /* *INDENT-ON* */
3207  break;
3208  }
3209 
3210  make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
3211  ip->protocol, fib_index, udp->src_port, udp->dst_port);
3212 
3213  /* *INDENT-OFF* */
3214  vec_foreach (tsm, sm->per_thread_data)
3215  {
3216  if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3217  &kv16, &value16)))
3218  {
3219  next_worker_index += tsm->thread_index;
3220 
3222  "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3223  next_worker_index, fib_index,
3224  clib_net_to_host_u32 (ip->src_address.as_u32),
3225  clib_net_to_host_u32 (ip->dst_address.as_u32));
3226 
3227  return next_worker_index;
3228  }
3229  }
3230  /* *INDENT-ON* */
3231  }
3232 
3233  hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3234  (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3235 
3236  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3237  next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3238  else
3239  next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3240 
3241  if (PREDICT_TRUE (!is_output))
3242  {
3243  nat_elog_debug_handoff ("HANDOFF IN2OUT",
3244  next_worker_index, rx_fib_index,
3245  clib_net_to_host_u32 (ip->src_address.as_u32),
3246  clib_net_to_host_u32 (ip->dst_address.as_u32));
3247  }
3248  else
3249  {
3250  nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3251  next_worker_index, rx_fib_index,
3252  clib_net_to_host_u32 (ip->src_address.as_u32),
3253  clib_net_to_host_u32 (ip->dst_address.as_u32));
3254  }
3255 
3256  return next_worker_index;
3257 }
3258 
3259 static u32
3261  u32 rx_fib_index, u8 is_output)
3262 {
3263  snat_main_t *sm = &snat_main;
3265  clib_bihash_kv_16_8_t kv16, value16;
3267 
3268  u32 proto, next_worker_index = 0;
3269  udp_header_t *udp;
3270  u16 port;
3272  u32 hash;
3273 
3274  proto = ip_proto_to_snat_proto (ip->protocol);
3275 
3276  if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3277  {
3278  udp = ip4_next_header (ip);
3279 
3280  make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
3281  ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
3282 
3283  /* *INDENT-OFF* */
3284  vec_foreach (tsm, sm->per_thread_data)
3285  {
3286  if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3287  &kv16, &value16)))
3288  {
3289  next_worker_index = sm->first_worker_index + tsm->thread_index;
3290  nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3291  next_worker_index, rx_fib_index,
3292  clib_net_to_host_u32 (ip->src_address.as_u32),
3293  clib_net_to_host_u32 (ip->dst_address.as_u32));
3294  return next_worker_index;
3295  }
3296  }
3297  /* *INDENT-ON* */
3298  }
3299  else if (proto == SNAT_PROTOCOL_ICMP)
3300  {
3302 
3303  if (!get_icmp_o2i_ed_key (b, ip, &key))
3304  {
3305 
3306  key.fib_index = rx_fib_index;
3307  kv16.key[0] = key.as_u64[0];
3308  kv16.key[1] = key.as_u64[1];
3309 
3310  /* *INDENT-OFF* */
3311  vec_foreach (tsm, sm->per_thread_data)
3312  {
3313  if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3314  &kv16, &value16)))
3315  {
3316  next_worker_index = sm->first_worker_index +
3317  tsm->thread_index;
3318  nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3319  next_worker_index, rx_fib_index,
3320  clib_net_to_host_u32 (ip->src_address.as_u32),
3321  clib_net_to_host_u32 (ip->dst_address.as_u32));
3322  return next_worker_index;
3323  }
3324  }
3325  /* *INDENT-ON* */
3326  }
3327  }
3328 
3329  /* first try static mappings without port */
3331  {
3332  make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3333  if (!clib_bihash_search_8_8
3334  (&sm->static_mapping_by_external, &kv, &value))
3335  {
3336  m = pool_elt_at_index (sm->static_mappings, value.value);
3337  next_worker_index = m->workers[0];
3338  goto done;
3339  }
3340  }
3341 
3342  /* unknown protocol */
3343  if (PREDICT_FALSE (proto == ~0))
3344  {
3345  /* use current thread */
3346  next_worker_index = vlib_get_thread_index ();
3347  goto done;
3348  }
3349 
3350  udp = ip4_next_header (ip);
3351  port = udp->dst_port;
3352 
3353  if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3354  {
3355  icmp46_header_t *icmp = (icmp46_header_t *) udp;
3356  icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3358  (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3359  port = vnet_buffer (b)->ip.reass.l4_src_port;
3360  else
3361  {
3362  /* if error message, then it's not fragmented and we can access it */
3363  ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3364  proto = ip_proto_to_snat_proto (inner_ip->protocol);
3365  void *l4_header = ip4_next_header (inner_ip);
3366  switch (proto)
3367  {
3368  case SNAT_PROTOCOL_ICMP:
3369  icmp = (icmp46_header_t *) l4_header;
3370  echo = (icmp_echo_header_t *) (icmp + 1);
3371  port = echo->identifier;
3372  break;
3373  case SNAT_PROTOCOL_UDP:
3374  case SNAT_PROTOCOL_TCP:
3375  port = ((tcp_udp_header_t *) l4_header)->src_port;
3376  break;
3377  default:
3378  next_worker_index = vlib_get_thread_index ();
3379  goto done;
3380  }
3381  }
3382  }
3383 
3384  /* try static mappings with port */
3386  {
3387  make_sm_kv (&kv, &ip->dst_address, proto, 0,
3388  clib_net_to_host_u16 (port));
3389  if (!clib_bihash_search_8_8
3390  (&sm->static_mapping_by_external, &kv, &value))
3391  {
3392  m = pool_elt_at_index (sm->static_mappings, value.value);
3393  if (!is_lb_static_mapping (m))
3394  {
3395  next_worker_index = m->workers[0];
3396  goto done;
3397  }
3398 
3399  hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3400  (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3401 
3402  if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3403  next_worker_index =
3404  m->workers[hash & (_vec_len (m->workers) - 1)];
3405  else
3406  next_worker_index = m->workers[hash % _vec_len (m->workers)];
3407  goto done;
3408  }
3409  }
3410 
3411  /* worker by outside port */
3412  next_worker_index = sm->first_worker_index;
3413  next_worker_index +=
3414  sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3415 
3416 done:
3417  nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3418  clib_net_to_host_u32 (ip->src_address.as_u32),
3419  clib_net_to_host_u32 (ip->dst_address.as_u32));
3420  return next_worker_index;
3421 }
3422 
3423 void
3424 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3425  ip4_address_t * out_addr, u16 out_port,
3426  ip4_address_t * eh_addr, u16 eh_port,
3427  ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3428  u32 fib_index, u16 flags, u32 thread_index)
3429 {
3430  snat_main_t *sm = &snat_main;
3432  snat_user_t *u;
3433  snat_session_t *s;
3435  f64 now = vlib_time_now (sm->vlib_main);
3436  nat_outside_fib_t *outside_fib;
3439  fib_prefix_t pfx = {
3441  .fp_len = 32,
3442  .fp_addr = {
3443  .ip4.as_u32 = eh_addr->as_u32,
3444  },
3445  };
3446 
3447  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3448 
3449  key.addr.as_u32 = out_addr->as_u32;
3450  key.port = out_port;
3451  key.protocol = proto;
3452 
3453  if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3454  {
3456  (sm->addresses, thread_index, &key))
3457  return;
3458  }
3459 
3460  u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3461  if (!u)
3462  return;
3463 
3464  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3465  if (!s)
3466  return;
3467 
3468  s->last_heard = now;
3469  s->flags = flags;
3470  s->ext_host_addr.as_u32 = eh_addr->as_u32;
3471  s->ext_host_port = eh_port;
3473  switch (vec_len (sm->outside_fibs))
3474  {
3475  case 0:
3476  key.fib_index = sm->outside_fib_index;
3477  break;
3478  case 1:
3479  key.fib_index = sm->outside_fibs[0].fib_index;
3480  break;
3481  default:
3482  /* *INDENT-OFF* */
3483  vec_foreach (outside_fib, sm->outside_fibs)
3484  {
3485  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3486  if (FIB_NODE_INDEX_INVALID != fei)
3487  {
3488  if (fib_entry_get_resolving_interface (fei) != ~0)
3489  {
3490  key.fib_index = outside_fib->fib_index;
3491  break;
3492  }
3493  }
3494  }
3495  /* *INDENT-ON* */
3496  break;
3497  }
3498  s->out2in = key;
3499  kv.key = key.as_u64;
3500  kv.value = s - tsm->sessions;
3501  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3502  nat_elog_warn ("out2in key add failed");
3503 
3504  key.addr.as_u32 = in_addr->as_u32;
3505  key.port = in_port;
3506  key.fib_index = fib_index;
3507  s->in2out = key;
3508  kv.key = key.as_u64;
3509  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3510  nat_elog_warn ("in2out key add failed");
3511 }
3512 
3513 void
3514 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3515  ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3516  u32 ti)
3517 {
3518  snat_main_t *sm = &snat_main;
3521  u32 thread_index;
3522  snat_session_t *s;
3524 
3525  if (sm->num_workers > 1)
3526  thread_index =
3527  sm->first_worker_index +
3528  (sm->workers[(clib_net_to_host_u16 (out_port) -
3529  1024) / sm->port_per_thread]);
3530  else
3531  thread_index = sm->num_workers;
3532  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3533 
3534  key.addr.as_u32 = out_addr->as_u32;
3535  key.port = out_port;
3536  key.protocol = proto;
3537  key.fib_index = fib_index;
3538  kv.key = key.as_u64;
3539  if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3540  return;
3541 
3542  s = pool_elt_at_index (tsm->sessions, value.value);
3543  nat_free_session_data (sm, s, thread_index, 1);
3544  nat44_delete_session (sm, s, thread_index);
3545 }
3546 
3547 void
3548 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3549  ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3550  u32 total_pkts, u64 total_bytes, u32 thread_index)
3551 {
3552  snat_main_t *sm = &snat_main;
3555  snat_session_t *s;
3557 
3558  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3559 
3560  key.addr.as_u32 = out_addr->as_u32;
3561  key.port = out_port;
3562  key.protocol = proto;
3563  key.fib_index = fib_index;
3564  kv.key = key.as_u64;
3565  if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3566  return;
3567 
3568  s = pool_elt_at_index (tsm->sessions, value.value);
3569  s->total_pkts = total_pkts;
3570  s->total_bytes = total_bytes;
3571 }
3572 
3573 void
3575  ip4_address_t * out_addr, u16 out_port,
3576  ip4_address_t * eh_addr, u16 eh_port,
3577  ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3578  u32 fib_index, u16 flags, u32 thread_index)
3579 {
3580  snat_main_t *sm = &snat_main;
3582  snat_user_t *u;
3583  snat_session_t *s;
3585  f64 now = vlib_time_now (sm->vlib_main);
3586  nat_outside_fib_t *outside_fib;
3589  fib_prefix_t pfx = {
3591  .fp_len = 32,
3592  .fp_addr = {
3593  .ip4.as_u32 = eh_addr->as_u32,
3594  },
3595  };
3596 
3597  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3598 
3599  key.addr.as_u32 = out_addr->as_u32;
3600  key.port = out_port;
3601  key.protocol = proto;
3602 
3603  if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3604  {
3606  (sm->addresses, thread_index, &key))
3607  return;
3608  }
3609 
3610  key.addr.as_u32 = ehn_addr->as_u32;
3611  key.port = ehn_port;
3612  if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3613  {
3615  (sm->twice_nat_addresses, thread_index, &key))
3616  return;
3617  }
3618 
3619  u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3620  if (!u)
3621  return;
3622 
3623  s = nat_ed_session_alloc (sm, u, thread_index, now);
3624  if (!s)
3625  return;
3626 
3627  s->last_heard = now;
3628  s->flags = flags;
3629  s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3630  s->ext_host_nat_port = s->ext_host_port = eh_port;
3631  if (is_twice_nat_session (s))
3632  {
3633  s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3634  s->ext_host_nat_port = ehn_port;
3635  }
3637  switch (vec_len (sm->outside_fibs))
3638  {
3639  case 0:
3640  key.fib_index = sm->outside_fib_index;
3641  break;
3642  case 1:
3643  key.fib_index = sm->outside_fibs[0].fib_index;
3644  break;
3645  default:
3646  /* *INDENT-OFF* */
3647  vec_foreach (outside_fib, sm->outside_fibs)
3648  {
3649  fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3650  if (FIB_NODE_INDEX_INVALID != fei)
3651  {
3652  if (fib_entry_get_resolving_interface (fei) != ~0)
3653  {
3654  key.fib_index = outside_fib->fib_index;
3655  break;
3656  }
3657  }
3658  }
3659  /* *INDENT-ON* */
3660  break;
3661  }
3662  key.addr.as_u32 = out_addr->as_u32;
3663  key.port = out_port;
3664  s->out2in = key;
3665  kv.value = s - tsm->sessions;
3666 
3667  key.addr.as_u32 = in_addr->as_u32;
3668  key.port = in_port;
3669  key.fib_index = fib_index;
3670  s->in2out = key;
3671 
3672  make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
3673  snat_proto_to_ip_proto (proto), fib_index, in_port,
3674  s->ext_host_nat_port);
3675  if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3676  nat_elog_warn ("in2out key add failed");
3677 
3678  make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3679  s->out2in.fib_index, out_port, eh_port);
3680  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3681  nat_elog_warn ("out2in key add failed");
3682 }
3683 
3684 void
3685 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3686  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3687  u32 fib_index, u32 ti)
3688 {
3689  snat_main_t *sm = &snat_main;
3692  u32 thread_index;
3693  snat_session_t *s;
3695 
3696  if (sm->num_workers > 1)
3697  thread_index =
3698  sm->first_worker_index +
3699  (sm->workers[(clib_net_to_host_u16 (out_port) -
3700  1024) / sm->port_per_thread]);
3701  else
3702  thread_index = sm->num_workers;
3703  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3704 
3705  key.l_addr.as_u32 = out_addr->as_u32;
3706  key.l_port = out_port;
3707  key.r_addr.as_u32 = eh_addr->as_u32;
3708  key.r_port = eh_port;
3709  key.proto = proto;
3710  key.fib_index = fib_index;
3711  kv.key[0] = key.as_u64[0];
3712  kv.key[1] = key.as_u64[1];
3713  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3714  return;
3715 
3716  s = pool_elt_at_index (tsm->sessions, value.value);
3717  nat_free_session_data (sm, s, thread_index, 1);
3718  nat44_delete_session (sm, s, thread_index);
3719 }
3720 
3721 void
3722 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3723  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3724  u32 fib_index, u32 total_pkts, u64 total_bytes,
3725  u32 thread_index)
3726 {
3727  snat_main_t *sm = &snat_main;
3730  snat_session_t *s;
3732 
3733  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3734 
3735  key.l_addr.as_u32 = out_addr->as_u32;
3736  key.l_port = out_port;
3737  key.r_addr.as_u32 = eh_addr->as_u32;
3738  key.r_port = eh_port;
3739  key.proto = proto;
3740  key.fib_index = fib_index;
3741  kv.key[0] = key.as_u64[0];
3742  kv.key[1] = key.as_u64[1];
3743  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3744  return;
3745 
3746  s = pool_elt_at_index (tsm->sessions, value.value);
3747  s->total_pkts = total_pkts;
3748  s->total_bytes = total_bytes;
3749 }
3750 
3751 static clib_error_t *
3753 {
3754  snat_main_t *sm = &snat_main;
3755  nat66_main_t *nm = &nat66_main;
3756  dslite_main_t *dm = &dslite_main;
3758 
3759  u32 static_mapping_buckets = 1024;
3760  u32 static_mapping_memory_size = 64 << 20;
3761 
3762  u32 nat64_bib_buckets = 1024;
3763  u32 nat64_bib_memory_size = 128 << 20;
3764 
3765  u32 nat64_st_buckets = 2048;
3766  u32 nat64_st_memory_size = 256 << 20;
3767 
3768  u32 user_buckets = 128;
3769  u32 user_memory_size = 64 << 20;
3770  u32 translation_buckets = 1024;
3771  u32 translation_memory_size = 128 << 20;
3772 
3773  u32 max_translations_per_user = ~0;
3774 
3775  u32 outside_vrf_id = 0;
3776  u32 outside_ip6_vrf_id = 0;
3777  u32 inside_vrf_id = 0;
3778  u8 static_mapping_only = 0;
3779  u8 static_mapping_connection_tracking = 0;
3780 
3781  u32 udp_timeout = SNAT_UDP_TIMEOUT;
3782  u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
3783 
3784  u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3785  u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3786 
3787  sm->deterministic = 0;
3788  sm->out2in_dpo = 0;
3789  sm->endpoint_dependent = 0;
3790 
3791  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3792  {
3793  if (unformat
3794  (input, "translation hash buckets %d", &translation_buckets))
3795  ;
3796  else if (unformat (input, "udp timeout %d", &udp_timeout))
3797  ;
3798  else if (unformat (input, "icmp timeout %d", &icmp_timeout))
3799  ;
3800  else if (unformat (input, "tcp transitory timeout %d",
3801  &tcp_transitory_timeout));
3802  else if (unformat (input, "tcp established timeout %d",
3803  &tcp_established_timeout));
3804  else if (unformat (input, "translation hash memory %d",
3805  &translation_memory_size));
3806  else if (unformat (input, "user hash buckets %d", &user_buckets))
3807  ;
3808  else if (unformat (input, "user hash memory %d", &user_memory_size))
3809  ;
3810  else if (unformat (input, "max translations per user %d",
3811  &max_translations_per_user))
3812  ;
3813  else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3814  ;
3815  else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3816  ;
3817  else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3818  ;
3819  else if (unformat (input, "static mapping only"))
3820  {
3821  static_mapping_only = 1;
3822  if (unformat (input, "connection tracking"))
3823  static_mapping_connection_tracking = 1;
3824  }
3825  else if (unformat (input, "deterministic"))
3826  sm->deterministic = 1;
3827  else if (unformat (input, "nat64 bib hash buckets %d",
3828  &nat64_bib_buckets))
3829  ;
3830  else if (unformat (input, "nat64 bib hash memory %d",
3831  &nat64_bib_memory_size))
3832  ;
3833  else
3834  if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3835  ;
3836  else if (unformat (input, "nat64 st hash memory %d",
3837  &nat64_st_memory_size))
3838  ;
3839  else if (unformat (input, "out2in dpo"))
3840  sm->out2in_dpo = 1;
3841  else if (unformat (input, "dslite ce"))
3842  dslite_set_ce (dm, 1);
3843  else if (unformat (input, "endpoint-dependent"))
3844  sm->endpoint_dependent = 1;
3845  else
3846  return clib_error_return (0, "unknown input '%U'",
3847  format_unformat_error, input);
3848  }
3849 
3850  if (sm->deterministic && sm->endpoint_dependent)
3851  return clib_error_return (0,
3852  "deterministic and endpoint-dependent modes are mutually exclusive");
3853 
3854  if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
3855  return clib_error_return (0,
3856  "static mapping only mode available only for simple nat");
3857 
3858  if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
3859  return clib_error_return (0,
3860  "out2in dpo mode available only for simple nat");
3861 
3862  /* optionally configurable timeouts for testing purposes */
3863  sm->udp_timeout = udp_timeout;
3864  sm->icmp_timeout = icmp_timeout;
3865  sm->tcp_transitory_timeout = tcp_transitory_timeout;
3866  sm->tcp_established_timeout = tcp_established_timeout;
3867 
3868  sm->user_buckets = user_buckets;
3869  sm->user_memory_size = user_memory_size;
3870 
3871  sm->translation_buckets = translation_buckets;
3872  sm->translation_memory_size = translation_memory_size;
3873 
3874  /* do not exceed load factor 10 */
3875  sm->max_translations = 10 * translation_buckets;
3876  sm->max_translations_per_user = max_translations_per_user == ~0 ?
3877  sm->max_translations : max_translations_per_user;
3878 
3879  sm->outside_vrf_id = outside_vrf_id;
3881  outside_vrf_id,
3882  nat_fib_src_hi);
3883  nm->outside_vrf_id = outside_ip6_vrf_id;
3885  outside_ip6_vrf_id,
3886  nat_fib_src_hi);
3887  sm->inside_vrf_id = inside_vrf_id;
3889  inside_vrf_id,
3890  nat_fib_src_hi);
3891  sm->static_mapping_only = static_mapping_only;
3892  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
3893 
3894  nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
3895  nat64_st_memory_size);
3896 
3897  if (sm->deterministic)
3898  {
3900  sm->in2out_output_node_index = ~0;
3904  }
3905  else
3906  {
3907  if (sm->endpoint_dependent)
3908  {
3911 
3915 
3919 
3922  nat_affinity_init (vm);
3925  }
3926  else
3927  {
3930 
3934 
3935  sm->in2out_node_index = snat_in2out_node.index;
3937  sm->out2in_node_index = snat_out2in_node.index;
3941  }
3942  if (!static_mapping_only ||
3943  (static_mapping_only && static_mapping_connection_tracking))
3944  {
3945  /* *INDENT-OFF* */
3946  vec_foreach (tsm, sm->per_thread_data)
3947  {
3948  if (sm->endpoint_dependent)
3949  {
3950  clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3951  translation_buckets,
3952  translation_memory_size);
3953  clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3955 
3956  clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3957  translation_buckets,
3958  translation_memory_size);
3959  clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3961  }
3962  else
3963  {
3964  clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3965  translation_buckets,
3966  translation_memory_size);
3967  clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
3969 
3970  clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3971  translation_buckets,
3972  translation_memory_size);
3973  clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
3975  }
3976 
3977  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3978  user_memory_size);
3979  clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
3980  format_user_kvp);
3981  }
3982  /* *INDENT-ON* */
3983 
3984  }
3985  else
3986  {
3989  }
3990  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3991  "static_mapping_by_local", static_mapping_buckets,
3992  static_mapping_memory_size);
3993  clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
3995 
3996  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3997  "static_mapping_by_external",
3998  static_mapping_buckets,
3999  static_mapping_memory_size);
4000  clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
4002  }
4003 
4004  return 0;
4005 }
4006 
4008 
4009 static void
4011  uword opaque,
4012  u32 sw_if_index,
4014  u32 address_length,
4015  u32 if_address_index, u32 is_delete)
4016 {
4017  snat_main_t *sm = &snat_main;
4020  snat_session_key_t m_key;
4022  int i, rv;
4023  ip4_address_t l_addr;
4024 
4025  for (i = 0; i < vec_len (sm->to_resolve); i++)
4026  {
4027  rp = sm->to_resolve + i;
4028  if (rp->addr_only == 0)
4029  continue;
4030  if (rp->sw_if_index == sw_if_index)
4031  goto match;
4032  }
4033 
4034  return;
4035 
4036 match:
4037  m_key.addr.as_u32 = address->as_u32;
4038  m_key.port = rp->addr_only ? 0 : rp->e_port;
4039  m_key.protocol = rp->addr_only ? 0 : rp->proto;
4040  m_key.fib_index = sm->outside_fib_index;
4041  kv.key = m_key.as_u64;
4042  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4043  m = 0;
4044  else
4045  m = pool_elt_at_index (sm->static_mappings, value.value);
4046 
4047  if (!is_delete)
4048  {
4049  /* Don't trip over lease renewal, static config */
4050  if (m)
4051  return;
4052  }
4053  else
4054  {
4055  if (!m)
4056  return;
4057  }
4058 
4059  /* Indetity mapping? */
4060  if (rp->l_addr.as_u32 == 0)
4061  l_addr.as_u32 = address[0].as_u32;
4062  else
4063  l_addr.as_u32 = rp->l_addr.as_u32;
4064  /* Add the static mapping */
4065  rv = snat_add_static_mapping (l_addr,
4066  address[0],
4067  rp->l_port,
4068  rp->e_port,
4069  rp->vrf_id,
4070  rp->addr_only, ~0 /* sw_if_index */ ,
4071  rp->proto, !is_delete, rp->twice_nat,
4072  rp->out2in_only, rp->tag, rp->identity_nat);
4073  if (rv)
4074  nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4075 }
4076 
4077 static void
4079  uword opaque,
4080  u32 sw_if_index,
4082  u32 address_length,
4083  u32 if_address_index, u32 is_delete)
4084 {
4085  snat_main_t *sm = &snat_main;
4087  ip4_address_t l_addr;
4088  int i, j;
4089  int rv;
4090  u8 twice_nat = 0;
4091  snat_address_t *addresses = sm->addresses;
4092 
4093  for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4094  {
4095  if (sw_if_index == sm->auto_add_sw_if_indices[i])
4096  goto match;
4097  }
4098 
4099  for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4100  {
4101  twice_nat = 1;
4102  addresses = sm->twice_nat_addresses;
4103  if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4104  goto match;
4105  }
4106 
4107  return;
4108 
4109 match:
4110  if (!is_delete)
4111  {
4112  /* Don't trip over lease renewal, static config */
4113  for (j = 0; j < vec_len (addresses); j++)
4114  if (addresses[j].addr.as_u32 == address->as_u32)
4115  return;
4116 
4117  (void) snat_add_address (sm, address, ~0, twice_nat);
4118  /* Scan static map resolution vector */
4119  for (j = 0; j < vec_len (sm->to_resolve); j++)
4120  {
4121  rp = sm->to_resolve + j;
4122  if (rp->addr_only)
4123  continue;
4124  /* On this interface? */
4125  if (rp->sw_if_index == sw_if_index)
4126  {
4127  /* Indetity mapping? */
4128  if (rp->l_addr.as_u32 == 0)
4129  l_addr.as_u32 = address[0].as_u32;
4130  else
4131  l_addr.as_u32 = rp->l_addr.as_u32;
4132  /* Add the static mapping */
4133  rv = snat_add_static_mapping (l_addr,
4134  address[0],
4135  rp->l_port,
4136  rp->e_port,
4137  rp->vrf_id,
4138  rp->addr_only,
4139  ~0 /* sw_if_index */ ,
4140  rp->proto,
4141  rp->is_add, rp->twice_nat,
4142  rp->out2in_only, rp->tag,
4143  rp->identity_nat);
4144  if (rv)
4145  nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4146  "i4", rv);
4147  }
4148  }
4149  return;
4150  }
4151  else
4152  {
4153  (void) snat_del_address (sm, address[0], 1, twice_nat);
4154  return;
4155  }
4156 }
4157 
4158 
4159 int
4161  u8 twice_nat)
4162 {
4163  ip4_main_t *ip4_main = sm->ip4_main;
4164  ip4_address_t *first_int_addr;
4166  u32 *indices_to_delete = 0;
4167  int i, j;
4168  u32 *auto_add_sw_if_indices =
4169  twice_nat ? sm->
4170  auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4171 
4172  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4173  );
4174 
4175  for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4176  {
4177  if (auto_add_sw_if_indices[i] == sw_if_index)
4178  {
4179  if (is_del)
4180  {
4181  /* if have address remove it */
4182  if (first_int_addr)
4183  (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4184  else
4185  {
4186  for (j = 0; j < vec_len (sm->to_resolve); j++)
4187  {
4188  rp = sm->to_resolve + j;
4189  if (rp->sw_if_index == sw_if_index)
4190  vec_add1 (indices_to_delete, j);
4191  }
4192  if (vec_len (indices_to_delete))
4193  {
4194  for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4195  vec_del1 (sm->to_resolve, j);
4196  vec_free (indices_to_delete);
4197  }
4198  }
4199  if (twice_nat)
4201  else
4203  }
4204  else
4205  return VNET_API_ERROR_VALUE_EXIST;
4206 
4207  return 0;
4208  }
4209  }
4210 
4211  if (is_del)
4212  return VNET_API_ERROR_NO_SUCH_ENTRY;
4213 
4214  /* add to the auto-address list */
4215  if (twice_nat)
4216  vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4217  else
4218  vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4219 
4220  /* If the address is already bound - or static - add it now */
4221  if (first_int_addr)
4222  (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4223 
4224  return 0;
4225 }
4226 
4227 int
4229  snat_protocol_t proto, u32 vrf_id, int is_in)
4230 {
4233  ip4_header_t ip;
4234  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4236  snat_session_t *s;
4237  clib_bihash_8_8_t *t;
4238 
4239  if (sm->endpoint_dependent)
4240  return VNET_API_ERROR_UNSUPPORTED;
4241 
4242  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4243  if (sm->num_workers > 1)
4244  tsm =
4246  sm->worker_in2out_cb (&ip, fib_index, 0));
4247  else
4248  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4249 
4250  key.addr.as_u32 = addr->as_u32;
4251  key.port = clib_host_to_net_u16 (port);
4252  key.protocol = proto;
4253  key.fib_index = fib_index;
4254  kv.key = key.as_u64;
4255  t = is_in ? &tsm->in2out : &tsm->out2in;
4256  if (!clib_bihash_search_8_8 (t, &kv, &value))
4257  {
4258  if (pool_is_free_index (tsm->sessions, value.value))
4259  return VNET_API_ERROR_UNSPECIFIED;
4260 
4261  s = pool_elt_at_index (tsm->sessions, value.value);
4262  nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4263  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4264  return 0;
4265  }
4266 
4267  return VNET_API_ERROR_NO_SUCH_ENTRY;
4268 }
4269 
4270 int
4272  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4273  u32 vrf_id, int is_in)
4274 {
4275  ip4_header_t ip;
4276  clib_bihash_16_8_t *t;
4279  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4280  snat_session_t *s;
4282 
4283  if (!sm->endpoint_dependent)
4284  return VNET_API_ERROR_FEATURE_DISABLED;
4285 
4286  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4287  if (sm->num_workers > 1)
4288  tsm =
4290  sm->worker_in2out_cb (&ip, fib_index, 0));
4291  else
4292  tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4293 
4294  t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4295  key.l_addr.as_u32 = addr->as_u32;
4296  key.r_addr.as_u32 = eh_addr->as_u32;
4297  key.l_port = clib_host_to_net_u16 (port);
4298  key.r_port = clib_host_to_net_u16 (eh_port);
4299  key.proto = proto;
4300  key.fib_index = fib_index;
4301  kv.key[0] = key.as_u64[0];
4302  kv.key[1] = key.as_u64[1];
4303  if (clib_bihash_search_16_8 (t, &kv, &value))
4304  return VNET_API_ERROR_NO_SUCH_ENTRY;
4305 
4306  if (pool_is_free_index (tsm->sessions, value.value))
4307  return VNET_API_ERROR_UNSPECIFIED;
4308  s = pool_elt_at_index (tsm->sessions, value.value);
4309  nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4310  nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4311  return 0;
4312 }
4313 
4314 void
4315 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4316 {
4317  snat_main_t *sm = &snat_main;
4318 
4319  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4321  sm->psid = psid;
4322  sm->psid_offset = psid_offset;
4323  sm->psid_length = psid_length;
4324 }
4325 
4326 void
4328 {
4329  snat_main_t *sm = &snat_main;
4330 
4331  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4333  sm->start_port = start_port;
4334  sm->end_port = end_port;
4335 }
4336 
4337 void
4339 {
4340  snat_main_t *sm = &snat_main;
4341 
4342  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4344 }
4345 
4348  vlib_frame_t * frame)
4349 {
4350  return 0;
4351 }
4352 
4353 /* *INDENT-OFF* */
4355  .name = "nat-default",
4356  .vector_size = sizeof (u32),
4357  .format_trace = 0,
4359  .n_errors = 0,
4360  .n_next_nodes = NAT_N_NEXT,
4361  .next_nodes = {
4362  [NAT_NEXT_DROP] = "error-drop",
4363  [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4364  [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4365  [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4366  [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4367  [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4368  [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4369  [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4370  [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4371  },
4372 };
4373 /* *INDENT-ON* */
4374 
4375 /*
4376  * fd.io coding-style-patch-verification: ON
4377  *
4378  * Local Variables:
4379  * eval: (c-set-style "gnu")
4380  * End:
4381  */
ip4_address_t external_addr
Definition: nat.h:443
u32 user_memory_size
Definition: nat.h:668
vlib_log_class_t vlib_log_register_class(char *class, char *subclass)
Definition: log.c:176
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
clib_error_t * snat_api_init(vlib_main_t *vm, snat_main_t *sm)
Definition: nat_api.c:3429
void dslite_set_ce(dslite_main_t *dm, u8 set)
Definition: dslite.c:94
u32 next
Definition: dlist.h:30
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
static void snat_update_outside_fib(u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
Definition: nat.c:2252
nat_outside_fib_t * outside_fibs
Definition: nat.h:598
void snat_ipfix_logging_max_entries_per_user(u32 thread_index, u32 limit, u32 src_ip)
Generate maximum entries per user exceeded event.
enum fib_source_t_ fib_source_t
The different sources that can create a route.
format_function_t format_ip_protocol
Definition: format.h:45
#define snat_is_session_static(s)
Check if SNAT session is created from static mapping.
Definition: nat.h:765
u32 sessions_per_user_list_head_index
Definition: nat.h:349
vlib_node_registration_t nat_default_node
(constructor) VLIB_REGISTER_NODE (nat_default_node)
Definition: nat.c:4354
vlib_node_registration_t nat44_ed_in2out_output_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_output_node)
Definition: in2out_ed.c:1747
#define nat_elog_debug_handoff(_str, _tid, _fib, _src, _dst)
Definition: nat.h:923
u8 proto
Definition: acl_types.api:47
ip4_table_bind_function_t * function
Definition: ip4.h:92
int nat_affinity_create_and_lock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port, u8 backend_index, u32 sticky_time, u32 affinity_per_service_list_head_index)
Create affinity record and take reference counting lock.
Definition: nat_affinity.c:191
int snat_del_address(snat_main_t *sm, ip4_address_t addr, u8 delete_sm, u8 twice_nat)
Delete external address from NAT44 pool.
Definition: nat.c:1646
u32 hairpin_dst_node_index
Definition: nat.h:645
void dslite_init(vlib_main_t *vm)
Definition: dslite.c:22
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:139
u32 ed_hairpinning_node_index
Definition: nat.h:647
a
Definition: bitmap.h:538
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u32 icmp_timeout
Definition: nat.h:677
int ip4_sv_reass_enable_disable_with_refcnt(u32 sw_if_index, int is_enable)
ip4_address_t src_address
Definition: ip4_packet.h:170
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define nat_elog_info(nat_elog_str)
Definition: nat.h:1031
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, int twice_nat, int out2in_only, int identity_nat)
Definition: nat.c:651
static u32 nat44_session_get_timeout(snat_main_t *sm, snat_session_t *s)
Definition: nat_inlines.h:394
u16 start_port
Definition: nat.h:594
u32 fq_in2out_output_index
Definition: nat.h:615
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...
u32 ed_out2in_node_index
Definition: nat.h:639
#define nat_elog_notice(nat_elog_str)
Definition: nat.h:1023
static int nat_alloc_addr_and_port_range(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2914
#define SNAT_TCP_ESTABLISHED_TIMEOUT
Definition: nat.h:38
#define PREDICT_TRUE(x)
Definition: clib.h:112
u32 nsessions
Definition: nat.h:350
#define is_ed_session(s)
Check if NAT session is endpoint dependent.
Definition: nat.h:795
unsigned long u64
Definition: types.h:89
ip4_address_t addr
Definition: nat.h:407
static u32 nat44_ed_get_worker_out2in_cb(vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u8 is_output)
Definition: nat.c:3260
#define NULL
Definition: clib.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 index
Definition: node.h:280
snat_protocol_t proto
Definition: nat.h:454
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:279
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:989
static void make_sm_kv(clib_bihash_kv_8_8_t *kv, ip4_address_t *addr, u8 proto, u32 fib_index, u16 port)
Definition: nat_inlines.h:458
u16 port_per_thread
Definition: nat.h:564
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1810
void nat_free_session_data(snat_main_t *sm, snat_session_t *s, u32 thread_index, u8 is_ha)
Free NAT44 session data (lookup keys, external addrres port)
Definition: nat.c:194
add paths without path extensions
Definition: fib_source.h:205
int ip4_sv_reass_output_enable_disable_with_refcnt(u32 sw_if_index, int is_enable)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
u32 nstaticsessions
Definition: nat.h:351
void nat_ha_sref_ed_cb(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 total_pkts, u64 total_bytes, u32 thread_index)
Definition: nat.c:3722
u32 ed_out2in_slowpath_node_index
Definition: nat.h:640
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:328
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
#define NAT_INTERFACE_FLAG_IS_OUTSIDE
Definition: nat.h:292
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
u8 * format_user_kvp(u8 *s, va_list *args)
Definition: nat.c:3012
void nat_syslog_nat44_sdel(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *idaddr, u16 idport, ip4_address_t *xsaddr, u16 xsport, ip4_address_t *xdaddr, u16 xdport, snat_protocol_t proto, u8 is_twicenat)
Definition: nat_syslog.c:211
ip_lookup_main_t lookup_main
Definition: ip4.h:107
#define nat_elog_warn(nat_elog_str)
Definition: nat.h:1025
vlib_node_registration_t snat_det_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_det_out2in_node)
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:259
int nat44_del_ed_session(snat_main_t *sm, ip4_address_t *addr, u16 port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 vrf_id, int is_in)
Delete NAT44 endpoint-dependent session.
Definition: nat.c:4271
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u32 fib_index
Definition: nat.h:348
format_function_t format_snat_key
Definition: nat.h:754
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:530
#define VLIB_NODE_FN(node)
Definition: node.h:202
vl_api_prefix_t prefix
Definition: ip.api:144
#define nat_elog_addr(_level, _str, _addr)
Definition: nat.h:898
nat_alloc_out_addr_and_port_function_t * alloc_addr_and_port
Definition: nat.h:586
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:4078
u32 num_snat_thread
Definition: nat.h:565
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:237
dlist_elt_t * list_pool
Definition: nat.h:512
#define snat_is_unk_proto_session(s)
Check if SNAT session for unknown protocol.
Definition: nat.h:771
vhost_vring_addr_t addr
Definition: vhost_user.h:147
static int nat_alloc_addr_and_port_mape(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2864
static int nat_alloc_addr_and_port_default(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Definition: nat.c:2777
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:582
unsigned char u8
Definition: types.h:56
u8 deterministic
Definition: nat.h:661
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del)
Enable/disable NAT44 feature on the interface.
Definition: nat.c:1760
u32 icmp_match_out2in_ed(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)
Definition: out2in_ed.c:441
VNET_FEATURE_INIT(nat_pre_in2out, static)
u32 handoff_in2out_index
Definition: nat.h:623
u16 l_port
Definition: nat.h:108
nat44_lb_addr_port_t * locals
Definition: nat.h:462
u32 user_buckets
Definition: nat.h:667
double f64
Definition: types.h:142
clib_bihash_8_8_t user_hash
Definition: nat.h:503
int nat44_add_del_lb_static_mapping(ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, nat44_lb_addr_port_t *locals, u8 is_add, twice_nat_type_t twice_nat, u8 out2in_only, u8 *tag, u32 affinity)
Add/delete static mapping with load-balancing (multiple backends)
Definition: nat.c:1185
snat_session_t * nat_session_alloc_or_recycle(snat_main_t *sm, snat_user_t *u, u32 thread_index, f64 now)
Allocate new NAT session or recycle last used.
Definition: nat.c:375
#define NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY
Definition: nat.h:296
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:805
u32 max_translations_per_user
Definition: nat.h:669
clib_bihash_8_8_t in2out
Definition: nat.h:496
Definition: nat.h:63
nat66_main_t nat66_main
Definition: nat66.c:24
void nat_ha_sadd_cb(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index)
Definition: nat.c:3424
u32 in2out_output_node_index
Definition: nat.h:631
u32 ed_in2out_node_index
Definition: nat.h:635
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
format_function_t format_ip4_address
Definition: format.h:73
snat_get_worker_out2in_function_t * worker_out2in_cb
Definition: nat.h:563
#define static_always_inline
Definition: clib.h:99
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
vl_api_interface_index_t sw_if_index
Definition: gre.api:59
u16 r_port
Definition: nat.h:109
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
vlib_node_registration_t snat_out2in_node
(constructor) VLIB_REGISTER_NODE (snat_out2in_node)
Definition: out2in.c:1384
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:424
u8 * format_static_mapping_kvp(u8 *s, va_list *args)
Definition: nat.c:2998
ip4_address_t dst_address
Definition: ip4_packet.h:170
void nat_ha_sadd_ed_cb(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index)
Definition: nat.c:3574
u32 det_in2out_node_index
Definition: nat.h:641
int snat_add_address(snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, u8 twice_nat)
Add external address to NAT44 pool.
Definition: nat.c:558
u32 translation_buckets
Definition: nat.h:664
u8 * format_ed_session_kvp(u8 *s, va_list *args)
Definition: nat.c:3026
lb_nat_type_t
Definition: nat.h:428
ip4_address_t addr
Definition: nat.h:347
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregate type for a prefix.
Definition: fib_types.h:203
u8 probability
Definition: nat.api:820
#define clib_error_return(e, args...)
Definition: error.h:99
#define is_fwd_bypass_session(s)
Check if NAT session is forwarding bypass.
Definition: nat.h:789
static u32 snat_get_worker_in2out_cb(ip4_header_t *ip0, u32 rx_fib_index0, u8 is_output)
Definition: nat.c:3044
void snat_ipfix_logging_init(vlib_main_t *vm)
Initialize NAT plugin IPFIX logging.
ip4_main_t * ip4_main
Definition: nat.h:700
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
void snat_ipfix_logging_addresses_exhausted(u32 thread_index, u32 pool_id)
Generate NAT addresses exhausted event.
unsigned int u32
Definition: types.h:88
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:1097
void nat_ha_sdel_ed_cb(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 ti)
Definition: nat.c:3685
ip4_address_t local_addr
Definition: nat.h:441
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:68
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:4010
void nat_affinity_unlock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port)
Release a reference counting lock for affinity.
Definition: nat_affinity.c:242
u64 as_u64[2]
Definition: nat.h:111
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, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat)
Match NAT44 static mapping.
Definition: nat.c:2604
snat_protocol_t proto
Definition: nat.h:482
fib_source_t fib_source_allocate(const char *name, fib_source_priority_t prio, fib_source_behaviour_t bh)
Definition: fib_source.c:118
void snat_free_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k)
Free outside address and port pair.
Definition: nat.c:2530
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...
static void nat44_delete_session(snat_main_t *sm, snat_session_t *ses, u32 thread_index)
Definition: nat_inlines.h:289
char * name
The counter collection&#39;s name.
Definition: counter.h:64
vl_api_fib_path_type_t type
Definition: fib_types.api:123
twice_nat_type_t twice_nat
Definition: nat.h:449
static u32 snat_get_worker_out2in_cb(vlib_buffer_t *b, ip4_header_t *ip0, u32 rx_fib_index0, u8 is_output)
Definition: nat.c:3064
u32 max_translations
Definition: nat.h:666
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
u32 * auto_add_sw_if_indices_twice_nat
Definition: nat.h:605
Definition: fib_entry.h:117
void nat66_init(vlib_main_t *vm)
Definition: nat66.c:46
vlib_node_registration_t nat44_ed_out2in_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_out2in_node)
Definition: out2in_ed.c:1644
int snat_alloc_outside_address_and_port(snat_address_t *addresses, u32 fib_index, u32 thread_index, snat_session_key_t *k, u16 port_per_thread, u32 snat_thread_index)
Alloc outside address and port.
Definition: nat.c:2763
u32 fib_index
Definition: nat.h:107
snat_user_t * nat_user_get_or_create(snat_main_t *sm, ip4_address_t *addr, u32 fib_index, u32 thread_index)
Find or create NAT user.
Definition: nat.c:328
Definition: fib_entry.h:116
#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:519
u32 fib_index
Definition: nat.h:370
void nat_dpo_module_init(void)
Definition: nat_dpo.c:68
u32 handoff_in2out_output_index
Definition: nat.h:624
nat_addr_and_port_alloc_alg_t addr_and_port_alloc_alg
Definition: nat.h:588
#define FIB_SOURCE_PRIORITY_HI
Some priority values that plugins might use when they are not to concerned where in the list they&#39;ll ...
Definition: fib_source.h:273
clib_bihash_16_8_t out2in_ed
Definition: nat.h:499
static_always_inline u8 icmp_type_is_error_message(u8 icmp_type)
Definition: nat_inlines.h:174
static uword clib_bitmap_last_set(uword *ai)
Return the higest numbered set bit in a bitmap.
Definition: bitmap.h:423
u64 key
the key
Definition: bihash_8_8.h:35
void nat_ha_sdel_cb(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 ti)
Definition: nat.c:3514
lo
IPv4 shallow virtual reassembly.
void nat_ha_sref_cb(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 total_pkts, u64 total_bytes, u32 thread_index)
Definition: nat.c:3548
u16 mss_clamping
Definition: nat.h:682
vlib_main_t * vlib_main
Definition: nat.h:698
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u32 pre_in2out_node_index
Definition: nat.h:628
u16 protocol
Definition: nat.h:92
u8 out2in_dpo
Definition: nat.h:662
snat_session_t * nat_ed_session_alloc(snat_main_t *sm, snat_user_t *u, u32 thread_index, f64 now)
Allocate NAT endpoint-dependent session.
Definition: nat.c:450
#define SNAT_UDP_TIMEOUT
Definition: nat.h:36
snat_static_mapping_t * static_mappings
Definition: nat.h:577
u32 inside_fib_index
Definition: nat.h:673
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:287
u32 udp_timeout
Definition: nat.h:676
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:376
u8 static_mapping_only
Definition: nat.h:659
#define NAT_FQ_NELTS
Definition: nat.h:42
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:182
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:806
u32 hairpin_src_node_index
Definition: nat.h:646
clib_bihash_8_8_t static_mapping_by_external
Definition: nat.h:574
u32 in2out_slowpath_output_node_index
Definition: nat.h:634
u8 psid_offset
Definition: nat.h:590
static void vlib_set_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 value)
Set a simple counter.
Definition: counter.h:94
u32 handoff_out2in_index
Definition: nat.h:622
void nat_set_alloc_addr_and_port_default(void)
Set address and port assignment algorithm to default/standard.
Definition: nat.c:4338
api_main_t * api_main
Definition: nat.h:702
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:1291
vlib_main_t * vm
Definition: in2out_ed.c:1810
u8 psid_length
Definition: nat.h:591
u32 refcount
Definition: nat.h:371
vnet_main_t * vnet_main
Definition: nat.h:699
u32 inside_vrf_id
Definition: nat.h:672
Definition: nat.h:433
#define is_lb_session(s)
Check if NAT session is load-balancing.
Definition: nat.h:783
u8 log_level
Definition: nat.h:695
u32 fq_out2in_index
Definition: nat.h:616
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1458
snat_interface_t * output_feature_interfaces
Definition: nat.h:581
snat_main_t snat_main
Definition: nat.c:39
u32 pre_out2in_node_index
Definition: nat.h:627
u32 ed_hairpin_src_node_index
Definition: nat.h:649
#define pool_free(p)
Free a pool.
Definition: pool.h:412
void snat_ipfix_logging_nat44_ses_delete(u32 thread_index, 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 snat_det_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_det_in2out_node)
u64 value
the value
Definition: bihash_8_8.h:36
snat_user_t * users
Definition: nat.h:506
vlib_node_registration_t nat_pre_in2out_node
(constructor) VLIB_REGISTER_NODE (nat_pre_in2out_node)
Definition: in2out_ed.c:1817
#define is_affinity_sessions(s)
Check if NAT session has affinity record.
Definition: nat.h:801
u32 random_seed
Definition: nat.h:611
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
u32 flags
Definition: vhost_user.h:141
static u8 snat_proto_to_ip_proto(snat_protocol_t snat_proto)
Definition: nat_inlines.h:162
#define NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT
Definition: nat.h:297
u32 nat_affinity_get_per_service_list_head_index(void)
Get new affinity per service list head index.
Definition: nat_affinity.c:81
static void clib_dlist_addhead(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:71
clib_bihash_8_8_t out2in
Definition: nat.h:495
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:218
fib_source_t nat_fib_src_low
Definition: nat.c:42
u32 outside_vrf_id
Definition: nat.h:670
void nat44_add_del_address_dpo(ip4_address_t addr, u8 is_add)
Add/delete external address to FIB DPO (out2in DPO mode)
Definition: nat.c:2962
vlib_node_registration_t snat_in2out_node
(constructor) VLIB_REGISTER_NODE (snat_in2out_node)
Definition: in2out.c:1644
ip4_address_t l_addr
Definition: nat.h:105
u8 static_mapping_connection_tracking
Definition: nat.h:660
u16 end_port
Definition: nat.h:595
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:342
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:886
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:73
deterministic NAT definitions
int nat_affinity_find_and_lock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port, u8 *backend_index)
Find service backend index for client-IP and take a reference counting lock.
Definition: nat_affinity.c:127
u32 ed_in2out_slowpath_node_index
Definition: nat.h:636
u32 error_node_index
Definition: nat.h:619
VLIB_PLUGIN_REGISTER()
int snat_interface_add_del_output_feature(u32 sw_if_index, u8 is_inside, int is_del)
Enable/disable NAT44 output feature on the interface (postrouting NAT)
Definition: nat.c:2025
#define nat_elog_notice_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
Definition: nat.h:1034
u16 psid
Definition: nat.h:592
dslite_main_t dslite_main
Definition: dslite.c:19
u32 outside_fib_index
Definition: nat.h:671
static void snat_ip4_table_bind(ip4_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
Definition: nat.c:2322
u8 * format_session_kvp(u8 *s, va_list *args)
Definition: nat.c:2985
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:284
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
ip4_address_t addr
Definition: nat.h:90
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
u32 ed_hairpin_dst_node_index
Definition: nat.h:648
fib_source_t nat_fib_src_hi
Definition: nat.c:41
static void make_ed_kv(clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr, ip4_address_t *r_addr, u8 proto, u32 fib_index, u16 l_port, u16 r_port)
Definition: nat_inlines.h:441
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:459
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
u32 tcp_transitory_timeout
Definition: nat.h:678
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, twice_nat_type_t twice_nat, u8 out2in_only, u8 *tag, u8 identity_nat)
Add/delete NAT44 static mapping.
Definition: nat.c:694
void fib_table_lock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Release a reference counting lock on the table.
Definition: fib_table.c:1310
ip4_address_t r_addr
Definition: nat.h:106
u32 * auto_add_sw_if_indices
Definition: nat.h:604
u32 in2out_fast_node_index
Definition: nat.h:632
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:324
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:79
static_always_inline u16 snat_random_port(u16 min, u16 max)
Definition: nat.c:2755
u8 value
Definition: qos.api:54
#define ASSERT(truth)
#define NAT_INTERFACE_FLAG_IS_INSIDE
Definition: nat.h:291
#define is_addr_only_static_mapping(sm)
Check if NAT static mapping is address only (1:1NAT).
Definition: nat.h:825
u32 num_workers
Definition: nat.h:559
manual_print typedef address
Definition: ip_types.api:84
u32 first_worker_index
Definition: nat.h:560
#define is_identity_static_mapping(sm)
Check if NAT static mapping is identity NAT.
Definition: nat.h:837
u32 det_out2in_node_index
Definition: nat.h:642
ip4_address_t l_addr
Definition: nat.h:477
clib_error_t * nat_affinity_init(vlib_main_t *vm)
Initialize NAT client-IP based affinity.
Definition: nat_affinity.c:47
u32 in2out_slowpath_node_index
Definition: nat.h:633
snat_icmp_match_function_t * icmp_match_out2in_cb
Definition: nat.h:556
vlib_log_class_t log_class
Definition: nat.h:693
IPv4 main type.
Definition: ip4.h:105
#define SNAT_SESSION_FLAG_TWICE_NAT
Definition: nat.h:284
u64 as_u64
Definition: nat.h:140
void nat_set_alloc_addr_and_port_range(u16 start_port, u16 end_port)
Set address and port assignment algorithm for port range.
Definition: nat.c:4327
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:1156
ip4_address_t addr
Definition: nat.h:137
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
u32 fq_in2out_index
Definition: nat.h:614
static void vlib_zero_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Clear a simple counter Clears the set of per-thread u16 counters, and the u64 counter.
Definition: counter.h:139
uword * thread_registrations_by_name
Definition: threads.h:294
u32 out2in_node_index
Definition: nat.h:637
ip4_address_t addr
Definition: nat.h:356
vlib_node_registration_t nat44_ed_in2out_node
(constructor) VLIB_REGISTER_NODE (nat44_ed_in2out_node)
Definition: in2out_ed.c:1727
#define FIB_SOURCE_PRIORITY_LOW
Definition: fib_source.h:274
int nat44_del_session(snat_main_t *sm, ip4_address_t *addr, u16 port, snat_protocol_t proto, u32 vrf_id, int is_in)
Delete NAT44 session.
Definition: nat.c:4228
static_always_inline int get_icmp_o2i_ed_key(vlib_buffer_t *b, ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
Definition: nat_inlines.h:525
snat_address_t * twice_nat_addresses
Definition: nat.h:601
#define VNET_FEATURES(...)
Definition: feature.h:442
#define A(x)
Definition: main.c:1021
void nat_syslog_nat44_apmdel(u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, snat_protocol_t proto)
Definition: nat_syslog.c:118
vl_api_ip4_address_t hi
Definition: arp.api:37
static clib_error_t * snat_init(vlib_main_t *vm)
Definition: nat.c:2353
void nat_ha_sdel(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
Create session delete HA event.
Definition: nat_ha.c:715
static uword is_pow2(uword x)
Definition: clib.h:235
u32 value
Definition: dlist.h:32
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:462
ip4_table_bind_callback_t * table_bind_callbacks
Functions to call when interface to table biding changes.
Definition: ip4.h:146
clib_error_t * nat64_init(vlib_main_t *vm)
Initialize NAT64.
Definition: nat64.c:201
typedef key
Definition: ipsec_types.api:83
NAT64 global declarations.
#define is_lb_static_mapping(sm)
Check if NAT static mapping is load-balancing.
Definition: nat.h:843
void increment_v4_address(ip4_address_t *a)
Increment IPv4 address.
Definition: nat.c:642
Definition: nat.h:431
char * stat_segment_name
Name in stat segment directory.
Definition: counter.h:65
vlib_simple_counter_main_t total_users
Definition: nat.h:686
#define nat_elog_err(nat_elog_str)
Definition: nat.h:1027
vl_api_address_t ip
Definition: l2.api:490
static u32 ip_proto_to_snat_proto(u8 ip_proto)
Definition: nat_inlines.h:147
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
format_function_t format_static_mapping_key
Definition: nat.h:755
static void user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
Definition: nat_inlines.h:255
twice_nat_type_t
Definition: nat.h:418
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 hairpinning_node_index
Definition: nat.h:644
u32 outside_fib_index
Definition: nat66.h:63
#define is_out2in_only_static_mapping(sm)
Check if NAT static mapping match only out2in direction.
Definition: nat.h:831
Definition: fib_entry.h:113
VLIB buffer representation.
Definition: buffer.h:102
u32 * workers
Definition: nat.h:561
u64 uword
Definition: types.h:112
snat_main_per_thread_data_t * per_thread_data
Definition: nat.h:568
snat_protocol_t
Definition: nat.h:189
void nat_affinity_flush_service(u32 affinity_per_service_list_head_index)
Flush all service affinity data.
Definition: nat_affinity.c:97
NAT syslog logging.
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:197
u32 affinity_per_service_list_head_index
Definition: nat.h:464
u32 fib_index
Definition: nat.h:138
snat_address_t * addresses
Definition: nat.h:584
u16 port
Definition: lb_types.api:72
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)
Add/delete NAT44 pool address from specific interfce.
Definition: nat.c:4160
u32 out2in_fast_node_index
Definition: nat.h:638
#define hash_get_mem(h, key)
Definition: hash.h:269
u32 in2out_node_index
Definition: nat.h:630
#define SNAT_ICMP_TIMEOUT
Definition: nat.h:39
snat_get_worker_in2out_function_t * worker_in2out_cb
Definition: nat.h:562
snat_static_map_resolve_t * to_resolve
Definition: nat.h:608
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:378
#define vnet_buffer(b)
Definition: buffer.h:408
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define SNAT_SESSION_FLAG_STATIC_MAPPING
Definition: nat.h:281
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1079
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
u32 outside_vrf_id
Definition: nat66.h:62
u8 forwarding_enabled
Definition: nat.h:656
static u32 get_thread_idx_by_port(u16 e_port)
Definition: nat.c:680
u32 translation_memory_size
Definition: nat.h:665
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#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:1676
f64 end
end of the time range
Definition: mactime.api:44
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
int snat_set_workers(uword *bitmap)
Set NAT plugin workers.
Definition: nat.c:2223
u32 icmp_match_in2out_ed(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b, ip4_header_t *ip, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, void *d, void *e)
Definition: in2out_ed.c:513
#define is_twice_nat_session(s)
Check if NAT session is twice NAT.
Definition: nat.h:777
clib_bihash_16_8_t in2out_ed
Definition: nat.h:500
u32 vrf_id
Definition: nat.api:821
u8 endpoint_dependent
Definition: nat.h:663
static clib_error_t * snat_config(vlib_main_t *vm, unformat_input_t *input)
Definition: nat.c:3752
static u32 nat44_ed_get_worker_in2out_cb(ip4_header_t *ip, u32 rx_fib_index, u8 is_output)
Definition: nat.c:3157
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:543
void nat_set_alloc_addr_and_port_mape(u16 psid, u16 psid_offset, u16 psid_length)
Set address and port assignment algorithm for MAP-E CE.
Definition: nat.c:4315
NAT66 global declarations.
NAT plugin client-IP based session affinity for load-balancing.
vlib_simple_counter_main_t total_sessions
Definition: nat.h:687
#define SNAT_TCP_TRANSITORY_TIMEOUT
Definition: nat.h:37
ip_lookup_main_t * ip4_lookup_main
Definition: nat.h:701
#define NAT_STATIC_MAPPING_FLAG_LB
Definition: nat.h:298
static int is_snat_address_used_in_static_mapping(snat_main_t *sm, ip4_address_t addr)
Definition: nat.c:623
#define NAT_STATIC_MAPPING_FLAG_ADDR_ONLY
Definition: nat.h:295
snat_session_t * sessions
Definition: nat.h:509
snat_icmp_match_function_t * icmp_match_in2out_cb
Definition: nat.h:555
clib_bihash_8_8_t static_mapping_by_local
Definition: nat.h:571
int nat44_lb_static_mapping_add_del_local(ip4_address_t e_addr, u16 e_port, ip4_address_t l_addr, u16 l_port, snat_protocol_t proto, u32 vrf_id, u8 probability, u8 is_add)
Definition: nat.c:1462
u32 fib_index
Definition: nat.h:357
snat_interface_t * interfaces
Definition: nat.h:580
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
NAT active-passive HA.
void nat_ha_init(vlib_main_t *vm, nat_ha_sadd_cb_t sadd_cb, nat_ha_sdel_cb_t sdel_cb, nat_ha_sref_cb_t sref_cb)
Initialize NAT HA.
Definition: nat_ha.c:313
u16 fib_index
Definition: nat.h:92
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:304
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
vlib_node_registration_t nat_pre_out2in_node
(constructor) VLIB_REGISTER_NODE (nat_pre_out2in_node)
Definition: out2in_ed.c:1694
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117
static int nat_set_outside_address_and_port(snat_address_t *addresses, u32 thread_index, snat_session_key_t *k)
Definition: nat.c:2568
u32 tcp_established_timeout
Definition: nat.h:679
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128