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