nat: NAT44ED configuration refactor
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed.c
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 <vpp/app/version.h>
19
20 #include <vnet/vnet.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/ip/ip4.h>
23 #include <vnet/ip/ip_table.h>
24 #include <vnet/ip/reass/ip4_sv_reass.h>
25 #include <vnet/fib/fib_table.h>
26 #include <vnet/fib/ip4_fib.h>
27 #include <vnet/plugin/plugin.h>
28 #include <vppinfra/bihash_16_8.h>
29
30 #include <nat/lib/log.h>
31 #include <nat/lib/nat_syslog.h>
32 #include <nat/lib/nat_inlines.h>
33 #include <nat/lib/ipfix_logging.h>
34
35 #include <nat/nat44-ed/nat44_ed.h>
36 #include <nat/nat44-ed/nat44_ed_affinity.h>
37 #include <nat/nat44-ed/nat44_ed_inlines.h>
38
39 #include <vpp/stats/stat_segment.h>
40
41 snat_main_t snat_main;
42
43 static_always_inline void nat_validate_interface_counters (snat_main_t *sm,
44                                                            u32 sw_if_index);
45
46 #define skip_if_disabled()                                                    \
47   do                                                                          \
48     {                                                                         \
49       snat_main_t *sm = &snat_main;                                           \
50       if (PREDICT_FALSE (!sm->enabled))                                       \
51         return;                                                               \
52     }                                                                         \
53   while (0)
54
55 #define fail_if_enabled()                                                     \
56   do                                                                          \
57     {                                                                         \
58       snat_main_t *sm = &snat_main;                                           \
59       if (PREDICT_FALSE (sm->enabled))                                        \
60         {                                                                     \
61           nat_log_err ("plugin enabled");                                     \
62           return 1;                                                           \
63         }                                                                     \
64     }                                                                         \
65   while (0)
66
67 #define fail_if_disabled()                                                    \
68   do                                                                          \
69     {                                                                         \
70       snat_main_t *sm = &snat_main;                                           \
71       if (PREDICT_FALSE (!sm->enabled))                                       \
72         {                                                                     \
73           nat_log_err ("plugin disabled");                                    \
74           return 1;                                                           \
75         }                                                                     \
76     }                                                                         \
77   while (0)
78
79 /* Hook up input features */
80 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
81   .arc_name = "ip4-unicast",
82   .node_name = "nat-pre-in2out",
83   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
84                                "ip4-sv-reassembly-feature"),
85 };
86 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
87   .arc_name = "ip4-unicast",
88   .node_name = "nat-pre-out2in",
89   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
90                                "ip4-dhcp-client-detect",
91                                "ip4-sv-reassembly-feature"),
92 };
93 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
94   .arc_name = "ip4-unicast",
95   .node_name = "nat44-in2out-worker-handoff",
96   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
97 };
98 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
99   .arc_name = "ip4-unicast",
100   .node_name = "nat44-out2in-worker-handoff",
101   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
102                                "ip4-dhcp-client-detect"),
103 };
104 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
105   .arc_name = "ip4-unicast",
106   .node_name = "nat44-in2out",
107   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
108 };
109 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
110   .arc_name = "ip4-unicast",
111   .node_name = "nat44-out2in",
112   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
113                                "ip4-dhcp-client-detect"),
114 };
115 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
116   .arc_name = "ip4-unicast",
117   .node_name = "nat44-ed-in2out",
118   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
119 };
120 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
121   .arc_name = "ip4-unicast",
122   .node_name = "nat44-ed-out2in",
123   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
124                                "ip4-dhcp-client-detect"),
125 };
126 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
127   .arc_name = "ip4-unicast",
128   .node_name = "nat44-ed-classify",
129   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
130 };
131 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
132   .arc_name = "ip4-unicast",
133   .node_name = "nat44-handoff-classify",
134   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
135 };
136 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
137   .arc_name = "ip4-unicast",
138   .node_name = "nat44-in2out-fast",
139   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
140 };
141 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
142   .arc_name = "ip4-unicast",
143   .node_name = "nat44-out2in-fast",
144   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
145                                "ip4-dhcp-client-detect"),
146 };
147
148 /* Hook up output features */
149 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
150   .arc_name = "ip4-output",
151   .node_name = "nat44-in2out-output",
152   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
153   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
154 };
155 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
156   .arc_name = "ip4-output",
157   .node_name = "nat44-in2out-output-worker-handoff",
158   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
159   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
160 };
161 VNET_FEATURE_INIT (nat_pre_in2out_output, static) = {
162   .arc_name = "ip4-output",
163   .node_name = "nat-pre-in2out-output",
164   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
165   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
166 };
167 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
168   .arc_name = "ip4-output",
169   .node_name = "nat44-ed-in2out-output",
170   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
171   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
172 };
173
174 VLIB_PLUGIN_REGISTER () = {
175     .version = VPP_BUILD_VER,
176     .description = "Network Address Translation (NAT)",
177 };
178
179 static void nat44_ed_db_init (u32 translations, u32 translation_buckets);
180
181 static void nat44_ed_db_free ();
182
183 u32 nat_calc_bihash_buckets (u32 n_elts);
184
185 u8 *
186 format_session_kvp (u8 * s, va_list * args)
187 {
188   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
189
190   s = format (s, "%U thread-index %llu session-index %llu", format_snat_key,
191               v->key, nat_value_get_thread_index (v),
192               nat_value_get_session_index (v));
193
194   return s;
195 }
196
197 u8 *
198 format_static_mapping_kvp (u8 * s, va_list * args)
199 {
200   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
201
202   s = format (s, "%U static-mapping-index %llu",
203               format_snat_key, v->key, v->value);
204
205   return s;
206 }
207
208 u8 *
209 format_ed_session_kvp (u8 * s, va_list * args)
210 {
211   clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
212
213   u8 proto;
214   u16 r_port, l_port;
215   ip4_address_t l_addr, r_addr;
216   u32 fib_index;
217
218   split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
219   s = format (s,
220               "local %U:%d remote %U:%d proto %U fib %d thread-index %u "
221               "session-index %u",
222               format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
223               format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
224               format_ip_protocol, proto, fib_index,
225               ed_value_get_thread_index (v), ed_value_get_session_index (v));
226
227   return s;
228 }
229
230 void
231 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
232                        u8 is_ha)
233 {
234       per_vrf_sessions_unregister_session (s, thread_index);
235
236       if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 0))
237         nat_elog_warn (sm, "flow hash del failed");
238
239       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
240         nat_elog_warn (sm, "flow hash del failed");
241
242   if (is_fwd_bypass_session (s))
243     {
244       return;
245     }
246
247       if (is_affinity_sessions (s))
248         nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
249                              s->nat_proto, s->out2in.port);
250
251       if (!is_ha)
252         nat_syslog_nat44_sdel (
253           0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port,
254           &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr,
255           s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto,
256           is_twice_nat_session (s));
257
258   if (snat_is_unk_proto_session (s))
259     return;
260
261   if (!is_ha)
262     {
263       /* log NAT event */
264       nat_ipfix_logging_nat44_ses_delete (thread_index,
265                                           s->in2out.addr.as_u32,
266                                           s->out2in.addr.as_u32,
267                                           s->nat_proto,
268                                           s->in2out.port,
269                                           s->out2in.port,
270                                           s->in2out.fib_index);
271     }
272
273   /* Twice NAT address and port for external host */
274   if (is_twice_nat_session (s))
275     {
276       snat_free_outside_address_and_port (sm->twice_nat_addresses,
277                                           thread_index,
278                                           &s->ext_host_nat_addr,
279                                           s->ext_host_nat_port, s->nat_proto);
280     }
281
282   if (snat_is_session_static (s))
283     return;
284
285   snat_free_outside_address_and_port (sm->addresses, thread_index,
286                                       &s->out2in.addr, s->out2in.port,
287                                       s->nat_proto);
288 }
289
290 void
291 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
292                           int is_add)
293 {
294   snat_main_t *sm = &snat_main;
295   fib_prefix_t prefix = {
296     .fp_len = p_len,
297     .fp_proto = FIB_PROTOCOL_IP4,
298     .fp_addr = {
299                 .ip4.as_u32 = addr->as_u32,
300                 },
301   };
302   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
303
304   if (is_add)
305     fib_table_entry_update_one_path (fib_index,
306                                      &prefix,
307                                      sm->fib_src_low,
308                                      (FIB_ENTRY_FLAG_CONNECTED |
309                                       FIB_ENTRY_FLAG_LOCAL |
310                                       FIB_ENTRY_FLAG_EXCLUSIVE),
311                                      DPO_PROTO_IP4,
312                                      NULL,
313                                      sw_if_index,
314                                      ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
315   else
316     fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low);
317 }
318
319 static int
320 is_snat_address_used_in_static_mapping (snat_main_t *sm, ip4_address_t addr)
321 {
322   snat_static_mapping_t *m;
323   pool_foreach (m, sm->static_mappings)
324     {
325       if (is_sm_addr_only (m->flags) || is_sm_out2in_only (m->flags) ||
326           is_sm_identity_nat (m->flags))
327         continue;
328       if (m->external_addr.as_u32 == addr.as_u32)
329         return 1;
330     }
331   return 0;
332 }
333
334 int
335 nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat)
336 {
337   snat_main_t *sm = &snat_main;
338   vlib_thread_main_t *tm = vlib_get_thread_main ();
339   snat_address_t *ap, *addresses;
340   snat_interface_t *i;
341
342   addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
343
344   if (!sm->enabled)
345     {
346       return VNET_API_ERROR_UNSUPPORTED;
347     }
348
349   // check if address already exists
350   vec_foreach (ap, addresses)
351     {
352       if (ap->addr.as_u32 == addr->as_u32)
353         {
354           nat_log_err ("address exist");
355           return VNET_API_ERROR_VALUE_EXIST;
356         }
357     }
358
359   if (twice_nat)
360     {
361       vec_add2 (sm->twice_nat_addresses, ap, 1);
362     }
363   else
364     {
365       vec_add2 (sm->addresses, ap, 1);
366     }
367
368   ap->fib_index = ~0;
369   ap->addr = *addr;
370
371   if (vrf_id != ~0)
372     {
373       ap->fib_index = fib_table_find_or_create_and_lock (
374         FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
375     }
376
377 #define _(N, i, n, s)                                                         \
378   clib_memset (ap->busy_##n##_port_refcounts, 0,                              \
379                sizeof (ap->busy_##n##_port_refcounts));                       \
380   ap->busy_##n##_ports = 0;                                                   \
381   ap->busy_##n##_ports_per_thread = 0;                                        \
382   vec_validate_init_empty (ap->busy_##n##_ports_per_thread,                   \
383                            tm->n_vlib_mains - 1, 0);
384   foreach_nat_protocol
385 #undef _
386
387     if (!twice_nat)
388   {
389     pool_foreach (i, sm->interfaces)
390       {
391         if (!nat_interface_is_inside (i))
392           {
393             snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
394             break;
395           }
396       }
397     pool_foreach (i, sm->output_feature_interfaces)
398       {
399         if (!nat_interface_is_inside (i))
400           {
401             snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
402             break;
403           }
404       }
405   }
406   return 0;
407 }
408
409 int
410 nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat)
411 {
412   snat_main_t *sm = &snat_main;
413   snat_address_t *a = 0, *addresses;
414   snat_session_t *ses;
415   u32 *ses_to_be_removed = 0, *ses_index;
416   snat_main_per_thread_data_t *tsm;
417   snat_static_mapping_t *m;
418   snat_interface_t *i;
419   int j;
420
421   addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
422
423   for (j = 0; j < vec_len (addresses); j++)
424     {
425       if (addresses[j].addr.as_u32 == addr.as_u32)
426         {
427           a = addresses + j;
428           break;
429         }
430     }
431   if (!a)
432     {
433       nat_log_err ("no such address");
434       return VNET_API_ERROR_NO_SUCH_ENTRY;
435     }
436
437   if (delete_sm)
438     {
439       pool_foreach (m, sm->static_mappings)
440         {
441           if (m->external_addr.as_u32 == addr.as_u32)
442             {
443               nat44_ed_del_static_mapping (m->local_addr, m->external_addr,
444                                            m->local_port, m->external_port,
445                                            m->proto, m->vrf_id, ~0, m->flags);
446             }
447         }
448     }
449   else
450     {
451       // TODO: why ?
452       // check if address is used in some static mapping
453       if (is_snat_address_used_in_static_mapping (sm, addr))
454         {
455           nat_log_err ("address used in static mapping");
456           return VNET_API_ERROR_UNSPECIFIED;
457         }
458     }
459
460   if (a->fib_index != ~0)
461     {
462       fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
463     }
464
465   // delete sessions using address
466   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
467     {
468       vec_foreach (tsm, sm->per_thread_data)
469         {
470           pool_foreach (ses, tsm->sessions)
471             {
472               if (ses->out2in.addr.as_u32 == addr.as_u32)
473                 {
474                   nat_free_session_data (sm, ses, tsm - sm->per_thread_data,
475                                          0);
476                   vec_add1 (ses_to_be_removed, ses - tsm->sessions);
477                 }
478             }
479           vec_foreach (ses_index, ses_to_be_removed)
480             {
481               ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
482               nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1);
483             }
484           vec_free (ses_to_be_removed);
485         }
486     }
487
488 #define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
489   foreach_nat_protocol
490 #undef _
491
492     if (!twice_nat)
493   {
494     vec_del1 (sm->addresses, j);
495     // delete external address from FIB
496     pool_foreach (i, sm->interfaces)
497       {
498         if (!nat_interface_is_inside (i))
499           {
500             snat_add_del_addr_to_fib (&addr, 32, i->sw_if_index, 0);
501             break;
502           }
503       }
504     pool_foreach (i, sm->output_feature_interfaces)
505       {
506         if (!nat_interface_is_inside (i))
507           {
508             snat_add_del_addr_to_fib (&addr, 32, i->sw_if_index, 0);
509             break;
510           }
511       }
512   }
513   else { vec_del1 (sm->twice_nat_addresses, j); }
514   return 0;
515 }
516
517 u32
518 get_thread_idx_by_port (u16 e_port)
519 {
520   snat_main_t *sm = &snat_main;
521   u32 thread_idx = sm->num_workers;
522   if (sm->num_workers > 1)
523     {
524       thread_idx =
525         sm->first_worker_index +
526         sm->workers[(e_port - 1024) / sm->port_per_thread];
527     }
528   return thread_idx;
529 }
530
531 void
532 nat_ed_static_mapping_del_sessions (snat_main_t * sm,
533                                     snat_main_per_thread_data_t * tsm,
534                                     ip4_address_t l_addr,
535                                     u16 l_port,
536                                     u8 protocol,
537                                     u32 fib_index, int addr_only,
538                                     ip4_address_t e_addr, u16 e_port)
539 {
540   snat_session_t *s;
541   u32 *indexes_to_free = NULL;
542   pool_foreach (s, tsm->sessions) {
543     if (s->in2out.fib_index != fib_index ||
544         s->in2out.addr.as_u32 != l_addr.as_u32)
545       {
546         continue;
547       }
548     if (!addr_only)
549       {
550         if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
551             s->out2in.port != e_port ||
552             s->in2out.port != l_port ||
553             s->nat_proto != protocol)
554           continue;
555       }
556
557     if (is_lb_session (s))
558       continue;
559     if (!snat_is_session_static (s))
560       continue;
561     nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
562     vec_add1 (indexes_to_free, s - tsm->sessions);
563     if (!addr_only)
564       break;
565   }
566   u32 *ses_index;
567   vec_foreach (ses_index, indexes_to_free)
568   {
569     s = pool_elt_at_index (tsm->sessions, *ses_index);
570     nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
571   }
572   vec_free (indexes_to_free);
573 }
574
575 int
576 nat44_ed_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
577 {
578   u32 ti = get_thread_idx_by_port (port);
579   snat_main_t *sm = &snat_main;
580   snat_address_t *a = 0;
581   int i;
582
583   for (i = 0; i < vec_len (sm->addresses); i++)
584     {
585       a = sm->addresses + i;
586
587       if (a->addr.as_u32 != addr.as_u32)
588         continue;
589
590       switch (proto)
591         {
592 #define _(N, j, n, s)                                                         \
593   case NAT_PROTOCOL_##N:                                                      \
594     if (a->busy_##n##_port_refcounts[port])                                   \
595       goto done;                                                              \
596     ++a->busy_##n##_port_refcounts[port];                                     \
597     if (port > 1024)                                                          \
598       {                                                                       \
599         a->busy_##n##_ports++;                                                \
600         a->busy_##n##_ports_per_thread[ti]++;                                 \
601       }                                                                       \
602     break;
603           foreach_nat_protocol
604 #undef _
605             default : nat_elog_info (sm, "unknown protocol");
606           goto done;
607         }
608
609       return 0;
610     }
611
612 done:
613   return 1;
614 }
615
616 int
617 nat44_ed_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
618 {
619   u32 ti = get_thread_idx_by_port (port);
620   snat_main_t *sm = &snat_main;
621   snat_address_t *a = 0;
622   int i;
623
624   for (i = 0; i < vec_len (sm->addresses); i++)
625     {
626       a = sm->addresses + i;
627
628       if (a->addr.as_u32 != addr.as_u32)
629         continue;
630
631       switch (proto)
632         {
633 #define _(N, j, n, s)                                                         \
634   case NAT_PROTOCOL_##N:                                                      \
635     --a->busy_##n##_port_refcounts[port];                                     \
636     if (port > 1024)                                                          \
637       {                                                                       \
638         a->busy_##n##_ports--;                                                \
639         a->busy_##n##_ports_per_thread[ti]--;                                 \
640       }                                                                       \
641     break;
642           foreach_nat_protocol
643 #undef _
644             default : nat_elog_info (sm, "unknown protocol");
645           goto done;
646         }
647
648       return 0;
649     }
650
651 done:
652   return 1;
653 }
654
655 void
656 nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
657                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
658                              u32 flags, ip4_address_t pool_addr, u8 *tag)
659 {
660   snat_static_map_resolve_t *rp;
661   snat_main_t *sm = &snat_main;
662
663   vec_add2 (sm->to_resolve, rp, 1);
664   rp->l_addr.as_u32 = l_addr.as_u32;
665   rp->l_port = l_port;
666   rp->e_port = e_port;
667   rp->sw_if_index = sw_if_index;
668   rp->vrf_id = vrf_id;
669   rp->proto = proto;
670   rp->flags = flags;
671   rp->pool_addr = pool_addr;
672   rp->tag = vec_dup (tag);
673 }
674
675 int
676 nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
677                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
678                              u32 flags, int *out)
679 {
680   snat_static_map_resolve_t *rp;
681   snat_main_t *sm = &snat_main;
682   int i;
683
684   for (i = 0; i < vec_len (sm->to_resolve); i++)
685     {
686       rp = sm->to_resolve + i;
687
688       if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id)
689         {
690           if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags))
691             {
692               if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
693                 {
694                   if (rp->e_port != e_port || rp->proto != proto)
695                     {
696                       continue;
697                     }
698                 }
699             }
700           else if (rp->l_addr.as_u32 == l_addr.as_u32)
701             {
702               if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
703                 {
704                   if (rp->l_port != l_port || rp->e_port != e_port ||
705                       rp->proto != proto)
706                     {
707                       continue;
708                     }
709                 }
710             }
711           else
712             {
713               continue;
714             }
715           if (out)
716             {
717               *out = i;
718             }
719           return 0;
720         }
721     }
722   return 1;
723 }
724
725 int
726 nat44_ed_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
727                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
728                              u32 flags)
729 {
730   snat_main_t *sm = &snat_main;
731   int i;
732   if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
733                                     sw_if_index, flags, &i))
734     {
735       vec_del1 (sm->to_resolve, i);
736       return 0;
737     }
738   return 1;
739 }
740
741 static_always_inline int
742 nat44_ed_validate_sm_input (u32 flags)
743 {
744   // identity nat can be initiated only from inside interface
745   if (is_sm_identity_nat (flags) && is_sm_out2in_only (flags))
746     {
747       return VNET_API_ERROR_UNSUPPORTED;
748     }
749
750   if (is_sm_twice_nat (flags) || is_sm_self_twice_nat (flags))
751     {
752       if (is_sm_addr_only (flags) || is_sm_identity_nat (flags))
753         {
754           return VNET_API_ERROR_UNSUPPORTED;
755         }
756     }
757   return 0;
758 }
759
760 int
761 nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
762                              u16 l_port, u16 e_port, nat_protocol_t proto,
763                              u32 vrf_id, u32 sw_if_index, u32 flags,
764                              ip4_address_t pool_addr, u8 *tag)
765 {
766   snat_main_t *sm = &snat_main;
767   clib_bihash_kv_8_8_t kv, value;
768   snat_interface_t *interface;
769   nat44_lb_addr_port_t *local;
770   snat_static_mapping_t *m;
771   u32 fib_index = ~0;
772   int rv;
773
774   if (!sm->enabled)
775     {
776       return VNET_API_ERROR_UNSUPPORTED;
777     }
778
779   rv = nat44_ed_validate_sm_input (flags);
780   if (rv != 0)
781     {
782       return rv;
783     }
784
785   if (is_sm_addr_only (flags))
786     {
787       e_port = l_port = proto = 0;
788     }
789
790   if (is_sm_switch_address (flags))
791     {
792       // this mapping is interface bound
793       ip4_address_t *first_int_addr;
794
795       // check if this record isn't registered for resolve
796       if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
797                                         sw_if_index, flags, 0))
798         {
799           return VNET_API_ERROR_VALUE_EXIST;
800         }
801       // register record for resolve
802       nat44_ed_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
803                                    sw_if_index, flags, pool_addr, tag);
804
805       first_int_addr =
806         ip4_interface_first_address (sm->ip4_main, sw_if_index, 0);
807       if (!first_int_addr)
808         {
809           // dhcp resolution required
810           return 0;
811         }
812
813       e_addr.as_u32 = first_int_addr->as_u32;
814     }
815
816   if (is_sm_identity_nat (flags))
817     {
818       l_port = e_port;
819       l_addr.as_u32 = e_addr.as_u32;
820     }
821
822   // fib index 0
823   init_nat_k (&kv, e_addr, e_port, 0, proto);
824
825   if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
826     {
827       m = pool_elt_at_index (sm->static_mappings, value.value);
828       if (!is_sm_identity_nat (m->flags))
829         {
830           return VNET_API_ERROR_VALUE_EXIST;
831         }
832
833       // case:
834       // adding local identity nat record for different vrf table
835       pool_foreach (local, m->locals)
836         {
837           if (local->vrf_id == vrf_id)
838             {
839               return VNET_API_ERROR_VALUE_EXIST;
840             }
841         }
842
843       pool_get (m->locals, local);
844
845       local->vrf_id = vrf_id;
846       local->fib_index = fib_table_find_or_create_and_lock (
847         FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
848
849       init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
850                    m->proto, 0, m - sm->static_mappings);
851       clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
852
853       return 0;
854     }
855
856   if (vrf_id != ~0)
857     {
858       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
859                                                      sm->fib_src_low);
860     }
861   else
862     {
863       // fallback to default vrf
864       vrf_id = sm->inside_vrf_id;
865       fib_index = sm->inside_fib_index;
866       fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
867     }
868
869   // test if local mapping record doesn't exist
870   // identity nat supports multiple records in local mapping
871   if (!(is_sm_out2in_only (flags) || is_sm_identity_nat (flags)))
872     {
873       init_nat_k (&kv, l_addr, l_port, fib_index, proto);
874       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
875         {
876           return VNET_API_ERROR_VALUE_EXIST;
877         }
878     }
879
880   if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) ||
881         sm->static_mapping_only))
882     {
883       if (nat44_ed_reserve_port (e_addr, e_port, proto))
884         {
885           // remove resolve record
886           if (is_sm_switch_address (flags) && !is_sm_identity_nat (flags))
887             {
888               nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto,
889                                            vrf_id, sw_if_index, flags);
890             }
891           return VNET_API_ERROR_NO_SUCH_ENTRY;
892         }
893     }
894
895   pool_get (sm->static_mappings, m);
896   clib_memset (m, 0, sizeof (*m));
897
898   m->flags = flags;
899   m->local_addr = l_addr;
900   m->external_addr = e_addr;
901
902   m->tag = vec_dup (tag);
903
904   if (is_sm_exact_address (flags) && is_sm_twice_nat (flags))
905     {
906       m->pool_addr = pool_addr;
907     }
908
909   if (!is_sm_addr_only (flags))
910     {
911       m->local_port = l_port;
912       m->external_port = e_port;
913       m->proto = proto;
914     }
915
916   if (is_sm_identity_nat (flags))
917     {
918       pool_get (m->locals, local);
919
920       local->vrf_id = vrf_id;
921       local->fib_index = fib_index;
922     }
923   else
924     {
925       m->vrf_id = vrf_id;
926       m->fib_index = fib_index;
927     }
928
929   if (!is_sm_out2in_only (flags))
930     {
931       init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
932                    m - sm->static_mappings);
933       clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
934     }
935
936   init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
937                m - sm->static_mappings);
938   clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
939
940   if (sm->num_workers > 1)
941     {
942       // store worker index for this record
943       ip4_header_t ip = {
944         .src_address = m->local_addr,
945       };
946       u32 worker_index;
947       worker_index =
948         nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0);
949       vec_add1 (m->workers, worker_index);
950     }
951
952   if (is_sm_identity_nat (flags) || !is_sm_addr_only (flags))
953     return 0;
954
955   pool_foreach (interface, sm->interfaces)
956     {
957       if (nat_interface_is_inside (interface))
958         continue;
959
960       snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 1);
961       break;
962     }
963
964   pool_foreach (interface, sm->output_feature_interfaces)
965     {
966       if (nat_interface_is_inside (interface))
967         continue;
968
969       snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 1);
970       break;
971     }
972
973   return 0;
974 }
975
976 int
977 nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
978                              u16 l_port, u16 e_port, nat_protocol_t proto,
979                              u32 vrf_id, u32 sw_if_index, u32 flags)
980 {
981   snat_main_per_thread_data_t *tsm;
982   snat_main_t *sm = &snat_main;
983
984   clib_bihash_kv_8_8_t kv, value;
985   snat_interface_t *interface;
986   nat44_lb_addr_port_t *local;
987   snat_static_mapping_t *m;
988   u32 fib_index = ~0;
989   int rv;
990
991   if (!sm->enabled)
992     {
993       return VNET_API_ERROR_UNSUPPORTED;
994     }
995
996   rv = nat44_ed_validate_sm_input (flags);
997   if (rv != 0)
998     {
999       return rv;
1000     }
1001
1002   if (is_sm_addr_only (flags))
1003     {
1004       e_port = l_port = proto = 0;
1005     }
1006
1007   if (is_sm_switch_address (flags))
1008     {
1009       // this mapping is interface bound
1010       ip4_address_t *first_int_addr;
1011
1012       // delete record registered for resolve
1013       if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
1014                                        sw_if_index, flags))
1015         {
1016           return VNET_API_ERROR_NO_SUCH_ENTRY;
1017         }
1018
1019       first_int_addr =
1020         ip4_interface_first_address (sm->ip4_main, sw_if_index, 0);
1021       if (!first_int_addr)
1022         {
1023           // dhcp resolution required
1024           return 0;
1025         }
1026
1027       e_addr.as_u32 = first_int_addr->as_u32;
1028     }
1029
1030   if (is_sm_identity_nat (flags))
1031     {
1032       l_port = e_port;
1033       l_addr.as_u32 = e_addr.as_u32;
1034     }
1035
1036   // fib index 0
1037   init_nat_k (&kv, e_addr, e_port, 0, proto);
1038
1039   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1040     {
1041       if (is_sm_switch_address (flags))
1042         {
1043           return 0;
1044         }
1045       return VNET_API_ERROR_NO_SUCH_ENTRY;
1046     }
1047
1048   m = pool_elt_at_index (sm->static_mappings, value.value);
1049
1050   if (is_sm_identity_nat (flags))
1051     {
1052       u8 failure = 1;
1053
1054       if (!is_sm_switch_address (flags))
1055         {
1056           vrf_id = sm->inside_vrf_id;
1057         }
1058
1059       pool_foreach (local, m->locals)
1060         {
1061           if (local->vrf_id == vrf_id)
1062             {
1063               local = pool_elt_at_index (m->locals, local - m->locals);
1064               fib_index = local->fib_index;
1065               pool_put (m->locals, local);
1066               failure = 0;
1067             }
1068         }
1069
1070       if (failure)
1071         {
1072           return VNET_API_ERROR_NO_SUCH_ENTRY;
1073         }
1074     }
1075   else
1076     {
1077       fib_index = m->fib_index;
1078     }
1079
1080   if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) ||
1081         sm->static_mapping_only))
1082     {
1083       if (nat44_ed_free_port (e_addr, e_port, proto))
1084         {
1085           return VNET_API_ERROR_INVALID_VALUE;
1086         }
1087     }
1088
1089   if (!is_sm_out2in_only (flags))
1090     {
1091       init_nat_k (&kv, l_addr, l_port, fib_index, proto);
1092       clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1093     }
1094
1095   if (!sm->static_mapping_only || sm->static_mapping_connection_tracking)
1096     {
1097       // delete sessions for static mapping
1098       if (sm->num_workers > 1)
1099         tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1100       else
1101         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1102
1103       nat_ed_static_mapping_del_sessions (
1104         sm, tsm, m->local_addr, m->local_port, m->proto, fib_index,
1105         is_sm_addr_only (flags), e_addr, e_port);
1106     }
1107
1108   fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1109
1110   if (pool_elts (m->locals))
1111     return 0;
1112
1113   // fib_index 0
1114   init_nat_k (&kv, e_addr, e_port, 0, proto);
1115   clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1116
1117   vec_free (m->tag);
1118   vec_free (m->workers);
1119   pool_put (sm->static_mappings, m);
1120
1121   if (is_sm_identity_nat (flags) || !is_sm_addr_only (flags))
1122     return 0;
1123
1124   pool_foreach (interface, sm->interfaces)
1125     {
1126       if (nat_interface_is_inside (interface))
1127         continue;
1128
1129       snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 0);
1130       break;
1131     }
1132
1133   pool_foreach (interface, sm->output_feature_interfaces)
1134     {
1135       if (nat_interface_is_inside (interface))
1136         continue;
1137
1138       snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 0);
1139       break;
1140     }
1141
1142   return 0;
1143 }
1144
1145 int
1146 nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1147                                 nat_protocol_t proto,
1148                                 nat44_lb_addr_port_t *locals, u32 flags,
1149                                 u8 *tag, u32 affinity)
1150 {
1151   snat_main_t *sm = &snat_main;
1152   snat_static_mapping_t *m;
1153   clib_bihash_kv_8_8_t kv, value;
1154   snat_address_t *a = 0;
1155
1156   nat44_lb_addr_port_t *local;
1157   uword *bitmap = 0;
1158
1159   int i;
1160
1161   if (!sm->enabled)
1162     {
1163       return VNET_API_ERROR_UNSUPPORTED;
1164     }
1165
1166   init_nat_k (&kv, e_addr, e_port, 0, proto);
1167   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1168     m = 0;
1169   else
1170     m = pool_elt_at_index (sm->static_mappings, value.value);
1171
1172   if (m)
1173     return VNET_API_ERROR_VALUE_EXIST;
1174
1175   if (vec_len (locals) < 2)
1176     return VNET_API_ERROR_INVALID_VALUE;
1177
1178   /* Find external address in allocated addresses and reserve port for
1179      address and port pair mapping when dynamic translations enabled */
1180   if (!(sm->static_mapping_only || is_sm_out2in_only (flags)))
1181     {
1182       for (i = 0; i < vec_len (sm->addresses); i++)
1183         {
1184           if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1185             {
1186               a = sm->addresses + i;
1187               /* External port must be unused */
1188               switch (proto)
1189                 {
1190 #define _(N, j, n, s)                                                         \
1191   case NAT_PROTOCOL_##N:                                                      \
1192     if (a->busy_##n##_port_refcounts[e_port])                                 \
1193       return VNET_API_ERROR_INVALID_VALUE;                                    \
1194     ++a->busy_##n##_port_refcounts[e_port];                                   \
1195     if (e_port > 1024)                                                        \
1196       {                                                                       \
1197         a->busy_##n##_ports++;                                                \
1198         a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++;    \
1199       }                                                                       \
1200     break;
1201                   foreach_nat_protocol
1202 #undef _
1203                     default : nat_elog_info (sm, "unknown protocol");
1204                   return VNET_API_ERROR_INVALID_VALUE_2;
1205                 }
1206               break;
1207             }
1208         }
1209       /* External address must be allocated */
1210       if (!a)
1211         return VNET_API_ERROR_NO_SUCH_ENTRY;
1212     }
1213
1214   pool_get (sm->static_mappings, m);
1215   clib_memset (m, 0, sizeof (*m));
1216   m->tag = vec_dup (tag);
1217   m->external_addr = e_addr;
1218   m->external_port = e_port;
1219   m->affinity = affinity;
1220   m->proto = proto;
1221
1222   m->flags = flags;
1223   m->flags |= NAT_SM_FLAG_LB;
1224
1225   if (affinity)
1226     m->affinity_per_service_list_head_index =
1227       nat_affinity_get_per_service_list_head_index ();
1228   else
1229     m->affinity_per_service_list_head_index = ~0;
1230
1231   init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
1232                m - sm->static_mappings);
1233   if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1234     {
1235       nat_elog_err (sm, "static_mapping_by_external key add failed");
1236       return VNET_API_ERROR_UNSPECIFIED;
1237     }
1238
1239   for (i = 0; i < vec_len (locals); i++)
1240     {
1241       locals[i].fib_index = fib_table_find_or_create_and_lock (
1242         FIB_PROTOCOL_IP4, locals[i].vrf_id, sm->fib_src_low);
1243       if (!is_sm_out2in_only (flags))
1244         {
1245           init_nat_kv (&kv, locals[i].addr, locals[i].port,
1246                        locals[i].fib_index, m->proto, 0,
1247                        m - sm->static_mappings);
1248           clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1249         }
1250       locals[i].prefix = (i == 0) ?
1251                            locals[i].probability :
1252                            (locals[i - 1].prefix + locals[i].probability);
1253       pool_get (m->locals, local);
1254       *local = locals[i];
1255       if (sm->num_workers > 1)
1256         {
1257           ip4_header_t ip = {
1258             .src_address = locals[i].addr,
1259           };
1260           bitmap = clib_bitmap_set (
1261             bitmap, nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0),
1262             1);
1263         }
1264     }
1265
1266   /* Assign workers */
1267   if (sm->num_workers > 1)
1268     {
1269       clib_bitmap_foreach (i, bitmap)
1270         {
1271           vec_add1 (m->workers, i);
1272         }
1273     }
1274
1275   return 0;
1276 }
1277
1278 int
1279 nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1280                                 nat_protocol_t proto, u32 flags)
1281 {
1282   snat_main_t *sm = &snat_main;
1283   snat_static_mapping_t *m;
1284   clib_bihash_kv_8_8_t kv, value;
1285   snat_address_t *a = 0;
1286
1287   nat44_lb_addr_port_t *local;
1288   snat_main_per_thread_data_t *tsm;
1289   snat_session_t *s;
1290   int i;
1291
1292   if (!sm->enabled)
1293     {
1294       return VNET_API_ERROR_UNSUPPORTED;
1295     }
1296
1297   init_nat_k (&kv, e_addr, e_port, 0, proto);
1298   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1299     m = 0;
1300   else
1301     m = pool_elt_at_index (sm->static_mappings, value.value);
1302
1303   if (!m)
1304     return VNET_API_ERROR_NO_SUCH_ENTRY;
1305
1306   if (!is_sm_lb (m->flags))
1307     return VNET_API_ERROR_INVALID_VALUE;
1308
1309   /* Free external address port */
1310   if (!(sm->static_mapping_only || is_sm_out2in_only (flags)))
1311     {
1312       for (i = 0; i < vec_len (sm->addresses); i++)
1313         {
1314           if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1315             {
1316               a = sm->addresses + i;
1317               switch (proto)
1318                 {
1319 #define _(N, j, n, s)                                                         \
1320   case NAT_PROTOCOL_##N:                                                      \
1321     --a->busy_##n##_port_refcounts[e_port];                                   \
1322     if (e_port > 1024)                                                        \
1323       {                                                                       \
1324         a->busy_##n##_ports--;                                                \
1325         a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--;    \
1326       }                                                                       \
1327     break;
1328                   foreach_nat_protocol
1329 #undef _
1330                     default : nat_elog_info (sm, "unknown protocol");
1331                   return VNET_API_ERROR_INVALID_VALUE_2;
1332                 }
1333               break;
1334             }
1335         }
1336     }
1337
1338   init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1339   if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1340     {
1341       nat_elog_err (sm, "static_mapping_by_external key del failed");
1342       return VNET_API_ERROR_UNSPECIFIED;
1343     }
1344
1345   pool_foreach (local, m->locals)
1346     {
1347       fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1348       if (!is_sm_out2in_only (flags))
1349         {
1350           init_nat_k (&kv, local->addr, local->port, local->fib_index,
1351                       m->proto);
1352           if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1353             {
1354               nat_elog_err (sm, "static_mapping_by_local key del failed");
1355               return VNET_API_ERROR_UNSPECIFIED;
1356             }
1357         }
1358
1359       if (sm->num_workers > 1)
1360         {
1361           ip4_header_t ip = {
1362             .src_address = local->addr,
1363           };
1364           tsm = vec_elt_at_index (
1365             sm->per_thread_data,
1366             nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0));
1367         }
1368       else
1369         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1370
1371       /* Delete sessions */
1372       pool_foreach (s, tsm->sessions)
1373         {
1374           if (!(is_lb_session (s)))
1375             continue;
1376
1377           if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1378               s->in2out.port != local->port)
1379             continue;
1380
1381           nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1382           nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1383         }
1384     }
1385
1386   if (m->affinity)
1387     {
1388       nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1389     }
1390
1391   pool_free (m->locals);
1392   vec_free (m->tag);
1393   vec_free (m->workers);
1394   pool_put (sm->static_mappings, m);
1395
1396   return 0;
1397 }
1398
1399 int
1400 nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port,
1401                                           ip4_address_t l_addr, u16 l_port,
1402                                           nat_protocol_t proto, u32 vrf_id,
1403                                           u8 probability, u8 is_add)
1404 {
1405   snat_main_t *sm = &snat_main;
1406   snat_static_mapping_t *m = 0;
1407   clib_bihash_kv_8_8_t kv, value;
1408   nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1409   snat_main_per_thread_data_t *tsm;
1410   snat_session_t *s;
1411   u32 *locals = 0;
1412   uword *bitmap = 0;
1413   int i;
1414
1415   if (!sm->enabled)
1416     {
1417       return VNET_API_ERROR_UNSUPPORTED;
1418     }
1419
1420   init_nat_k (&kv, e_addr, e_port, 0, proto);
1421   if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1422     m = pool_elt_at_index (sm->static_mappings, value.value);
1423
1424   if (!m)
1425     return VNET_API_ERROR_NO_SUCH_ENTRY;
1426
1427   if (!is_sm_lb (m->flags))
1428     return VNET_API_ERROR_INVALID_VALUE;
1429
1430   pool_foreach (local, m->locals)
1431    {
1432     if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1433         (local->vrf_id == vrf_id))
1434       {
1435         match_local = local;
1436         break;
1437       }
1438   }
1439
1440   if (is_add)
1441     {
1442       if (match_local)
1443         return VNET_API_ERROR_VALUE_EXIST;
1444
1445       pool_get (m->locals, local);
1446       clib_memset (local, 0, sizeof (*local));
1447       local->addr.as_u32 = l_addr.as_u32;
1448       local->port = l_port;
1449       local->probability = probability;
1450       local->vrf_id = vrf_id;
1451       local->fib_index =
1452         fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1453                                            sm->fib_src_low);
1454
1455       if (!is_sm_out2in_only (m->flags))
1456         {
1457           init_nat_kv (&kv, l_addr, l_port, local->fib_index, proto, 0,
1458                        m - sm->static_mappings);
1459           if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1460             nat_elog_err (sm, "static_mapping_by_local key add failed");
1461         }
1462     }
1463   else
1464     {
1465       if (!match_local)
1466         return VNET_API_ERROR_NO_SUCH_ENTRY;
1467
1468       if (pool_elts (m->locals) < 3)
1469         return VNET_API_ERROR_UNSPECIFIED;
1470
1471       fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1472                         sm->fib_src_low);
1473
1474       if (!is_sm_out2in_only (m->flags))
1475         {
1476           init_nat_k (&kv, l_addr, l_port, match_local->fib_index, proto);
1477           if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1478             nat_elog_err (sm, "static_mapping_by_local key del failed");
1479         }
1480
1481       if (sm->num_workers > 1)
1482         {
1483           ip4_header_t ip = {
1484             .src_address = local->addr,
1485           };
1486           tsm = vec_elt_at_index (
1487             sm->per_thread_data,
1488             nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0));
1489         }
1490       else
1491         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1492
1493       /* Delete sessions */
1494       pool_foreach (s, tsm->sessions) {
1495         if (!(is_lb_session (s)))
1496           continue;
1497
1498         if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1499             s->in2out.port != match_local->port)
1500           continue;
1501
1502         nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1503         nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1504       }
1505
1506       pool_put (m->locals, match_local);
1507     }
1508
1509   vec_free (m->workers);
1510
1511   pool_foreach (local, m->locals)
1512    {
1513     vec_add1 (locals, local - m->locals);
1514     if (sm->num_workers > 1)
1515       {
1516         ip4_header_t ip;
1517         ip.src_address.as_u32 = local->addr.as_u32,
1518         bitmap = clib_bitmap_set (
1519           bitmap,
1520           nat44_ed_get_in2out_worker_index (0, &ip, local->fib_index, 0), 1);
1521       }
1522   }
1523
1524   ASSERT (vec_len (locals) > 1);
1525
1526   local = pool_elt_at_index (m->locals, locals[0]);
1527   local->prefix = local->probability;
1528   for (i = 1; i < vec_len (locals); i++)
1529     {
1530       local = pool_elt_at_index (m->locals, locals[i]);
1531       prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1532       local->prefix = local->probability + prev_local->prefix;
1533     }
1534
1535   /* Assign workers */
1536   if (sm->num_workers > 1)
1537     {
1538       clib_bitmap_foreach (i, bitmap)  { vec_add1(m->workers, i); }
1539     }
1540
1541   return 0;
1542 }
1543
1544 void
1545 expire_per_vrf_sessions (u32 fib_index)
1546 {
1547   per_vrf_sessions_t *per_vrf_sessions;
1548   snat_main_per_thread_data_t *tsm;
1549   snat_main_t *sm = &snat_main;
1550
1551   vec_foreach (tsm, sm->per_thread_data)
1552     {
1553       vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
1554         {
1555           if ((per_vrf_sessions->rx_fib_index == fib_index) ||
1556               (per_vrf_sessions->tx_fib_index == fib_index))
1557             {
1558               per_vrf_sessions->expired = 1;
1559             }
1560         }
1561     }
1562 }
1563
1564 void
1565 update_per_vrf_sessions_vec (u32 fib_index, int is_del)
1566 {
1567   snat_main_t *sm = &snat_main;
1568   nat_fib_t *fib;
1569
1570   // we don't care if it is outside/inside fib
1571   // we just care about their ref_count
1572   // if it reaches 0 sessions should expire
1573   // because the fib isn't valid for NAT anymore
1574
1575   vec_foreach (fib, sm->fibs)
1576   {
1577     if (fib->fib_index == fib_index)
1578       {
1579         if (is_del)
1580           {
1581             fib->ref_count--;
1582             if (!fib->ref_count)
1583               {
1584                 vec_del1 (sm->fibs, fib - sm->fibs);
1585                 expire_per_vrf_sessions (fib_index);
1586               }
1587             return;
1588           }
1589         else
1590           fib->ref_count++;
1591       }
1592   }
1593   if (!is_del)
1594     {
1595       vec_add2 (sm->fibs, fib, 1);
1596       fib->ref_count = 1;
1597       fib->fib_index = fib_index;
1598     }
1599 }
1600
1601 static_always_inline nat_outside_fib_t *
1602 nat44_ed_get_outside_fib (nat_outside_fib_t *outside_fibs, u32 fib_index)
1603 {
1604   nat_outside_fib_t *f;
1605   vec_foreach (f, outside_fibs)
1606     {
1607       if (f->fib_index == fib_index)
1608         {
1609           return f;
1610         }
1611     }
1612   return 0;
1613 }
1614
1615 static_always_inline snat_interface_t *
1616 nat44_ed_get_interface (snat_interface_t *interfaces, u32 sw_if_index)
1617 {
1618   snat_interface_t *i;
1619   pool_foreach (i, interfaces)
1620     {
1621       if (i->sw_if_index == sw_if_index)
1622         {
1623           return i;
1624         }
1625     }
1626   return 0;
1627 }
1628
1629 int
1630 nat44_ed_add_interface (u32 sw_if_index, u8 is_inside)
1631 {
1632   const char *del_feature_name, *feature_name;
1633   snat_main_t *sm = &snat_main;
1634
1635   nat_outside_fib_t *outside_fib;
1636   snat_static_mapping_t *m;
1637   snat_interface_t *i;
1638   snat_address_t *ap;
1639   u32 fib_index;
1640   int rv;
1641
1642   if (!sm->enabled)
1643     {
1644       nat_log_err ("nat44 is disabled");
1645       return VNET_API_ERROR_UNSUPPORTED;
1646     }
1647
1648   if (nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index))
1649     {
1650       nat_log_err ("error interface already configured");
1651       return VNET_API_ERROR_VALUE_EXIST;
1652     }
1653
1654   i = nat44_ed_get_interface (sm->interfaces, sw_if_index);
1655   if (i)
1656     {
1657       if ((nat_interface_is_inside (i) && is_inside) ||
1658           (nat_interface_is_outside (i) && !is_inside))
1659         {
1660           return 0;
1661         }
1662       if (sm->num_workers > 1)
1663         {
1664           del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1665                                           "nat44-out2in-worker-handoff";
1666           feature_name = "nat44-handoff-classify";
1667         }
1668       else
1669         {
1670           del_feature_name = !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1671
1672           feature_name = "nat44-ed-classify";
1673         }
1674
1675       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1676       if (rv)
1677         return rv;
1678       vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1679                                    sw_if_index, 0, 0, 0);
1680       vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1681                                    0, 0);
1682     }
1683   else
1684     {
1685       if (sm->num_workers > 1)
1686         {
1687           feature_name = is_inside ? "nat44-in2out-worker-handoff" :
1688                                      "nat44-out2in-worker-handoff";
1689         }
1690       else
1691         {
1692           feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1693         }
1694
1695       nat_validate_interface_counters (sm, sw_if_index);
1696       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1697       if (rv)
1698         return rv;
1699       vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1700                                    0, 0);
1701
1702       pool_get (sm->interfaces, i);
1703       i->sw_if_index = sw_if_index;
1704       i->flags = 0;
1705     }
1706
1707   fib_index =
1708     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1709
1710   update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
1711
1712   if (!is_inside)
1713     {
1714       i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1715
1716       outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1717       if (outside_fib)
1718         {
1719           outside_fib->refcount++;
1720         }
1721       else
1722         {
1723           vec_add2 (sm->outside_fibs, outside_fib, 1);
1724           outside_fib->fib_index = fib_index;
1725           outside_fib->refcount = 1;
1726         }
1727
1728       vec_foreach (ap, sm->addresses)
1729         {
1730           snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 1);
1731         }
1732       pool_foreach (m, sm->static_mappings)
1733         {
1734           if (!(is_sm_addr_only (m->flags)) ||
1735               (m->local_addr.as_u32 == m->external_addr.as_u32))
1736             {
1737               continue;
1738             }
1739           snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 1);
1740         }
1741     }
1742   else
1743     {
1744       i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1745     }
1746
1747   return 0;
1748 }
1749
1750 int
1751 nat44_ed_del_interface (u32 sw_if_index, u8 is_inside)
1752 {
1753   const char *del_feature_name, *feature_name;
1754   snat_main_t *sm = &snat_main;
1755
1756   nat_outside_fib_t *outside_fib;
1757   snat_static_mapping_t *m;
1758   snat_interface_t *i;
1759   snat_address_t *ap;
1760   u32 fib_index;
1761   int rv;
1762
1763   if (!sm->enabled)
1764     {
1765       nat_log_err ("nat44 is disabled");
1766       return VNET_API_ERROR_UNSUPPORTED;
1767     }
1768
1769   i = nat44_ed_get_interface (sm->interfaces, sw_if_index);
1770   if (i == 0)
1771     {
1772       nat_log_err ("error interface couldn't be found");
1773       return VNET_API_ERROR_NO_SUCH_ENTRY;
1774     }
1775
1776   if (nat_interface_is_inside (i) && nat_interface_is_outside (i))
1777     {
1778       if (sm->num_workers > 1)
1779         {
1780           del_feature_name = "nat44-handoff-classify";
1781           feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1782                                       "nat44-out2in-worker-handoff";
1783         }
1784       else
1785         {
1786           del_feature_name = "nat44-ed-classify";
1787           feature_name = !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1788         }
1789
1790       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1791       if (rv)
1792         {
1793           return rv;
1794         }
1795       vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1796                                    sw_if_index, 0, 0, 0);
1797       vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1798                                    0, 0);
1799
1800       if (is_inside)
1801         {
1802           i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1803         }
1804       else
1805         {
1806           i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1807         }
1808     }
1809   else
1810     {
1811       if (sm->num_workers > 1)
1812         {
1813           feature_name = is_inside ? "nat44-in2out-worker-handoff" :
1814                                      "nat44-out2in-worker-handoff";
1815         }
1816       else
1817         {
1818           feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1819         }
1820
1821       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1822       if (rv)
1823         {
1824           return rv;
1825         }
1826       vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 0,
1827                                    0, 0);
1828
1829       // remove interface
1830       pool_put (sm->interfaces, i);
1831     }
1832
1833   fib_index =
1834     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1835
1836   update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
1837
1838   if (!is_inside)
1839     {
1840       outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1841       if (outside_fib)
1842         {
1843           outside_fib->refcount--;
1844           if (!outside_fib->refcount)
1845             {
1846               vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1847             }
1848         }
1849
1850       vec_foreach (ap, sm->addresses)
1851         {
1852           snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 0);
1853         }
1854
1855       pool_foreach (m, sm->static_mappings)
1856         {
1857           if (!(is_sm_addr_only (m->flags)) ||
1858               (m->local_addr.as_u32 == m->external_addr.as_u32))
1859             {
1860               continue;
1861             }
1862           snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 0);
1863         }
1864     }
1865
1866   return 0;
1867 }
1868
1869 int
1870 nat44_ed_add_output_interface (u32 sw_if_index)
1871 {
1872   snat_main_t *sm = &snat_main;
1873
1874   nat_outside_fib_t *outside_fib;
1875   snat_static_mapping_t *m;
1876   snat_interface_t *i;
1877   snat_address_t *ap;
1878   u32 fib_index;
1879   int rv;
1880
1881   if (!sm->enabled)
1882     {
1883       nat_log_err ("nat44 is disabled");
1884       return VNET_API_ERROR_UNSUPPORTED;
1885     }
1886
1887   if (nat44_ed_get_interface (sm->interfaces, sw_if_index))
1888     {
1889       nat_log_err ("error interface already configured");
1890       return VNET_API_ERROR_VALUE_EXIST;
1891     }
1892
1893   if (nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index))
1894     {
1895       nat_log_err ("error interface already configured");
1896       return VNET_API_ERROR_VALUE_EXIST;
1897     }
1898
1899   if (sm->num_workers > 1)
1900     {
1901       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1902       if (rv)
1903         {
1904           return rv;
1905         }
1906
1907       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
1908       if (rv)
1909         {
1910           return rv;
1911         }
1912
1913       vnet_feature_enable_disable (
1914         "ip4-unicast", "nat44-out2in-worker-handoff", sw_if_index, 1, 0, 0);
1915       vnet_feature_enable_disable ("ip4-output",
1916                                    "nat44-in2out-output-worker-handoff",
1917                                    sw_if_index, 1, 0, 0);
1918     }
1919   else
1920     {
1921       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1922       if (rv)
1923         {
1924           return rv;
1925         }
1926
1927       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
1928       if (rv)
1929         {
1930           return rv;
1931         }
1932
1933       vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
1934                                    sw_if_index, 1, 0, 0);
1935       vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output",
1936                                    sw_if_index, 1, 0, 0);
1937     }
1938
1939   nat_validate_interface_counters (sm, sw_if_index);
1940
1941   pool_get (sm->output_feature_interfaces, i);
1942   i->sw_if_index = sw_if_index;
1943   i->flags = 0;
1944   i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1945   i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1946
1947   fib_index =
1948     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1949   update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
1950
1951   outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1952   if (outside_fib)
1953     {
1954       outside_fib->refcount++;
1955     }
1956   else
1957     {
1958       vec_add2 (sm->outside_fibs, outside_fib, 1);
1959       outside_fib->fib_index = fib_index;
1960       outside_fib->refcount = 1;
1961     }
1962
1963   vec_foreach (ap, sm->addresses)
1964     {
1965       snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 1);
1966     }
1967
1968   pool_foreach (m, sm->static_mappings)
1969     {
1970       if (!((is_sm_addr_only (m->flags))) ||
1971           (m->local_addr.as_u32 == m->external_addr.as_u32))
1972         {
1973           continue;
1974         }
1975       snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 1);
1976     }
1977
1978   return 0;
1979 }
1980
1981 int
1982 nat44_ed_del_output_interface (u32 sw_if_index)
1983 {
1984   snat_main_t *sm = &snat_main;
1985
1986   nat_outside_fib_t *outside_fib;
1987   snat_static_mapping_t *m;
1988   snat_interface_t *i;
1989   snat_address_t *ap;
1990   u32 fib_index;
1991   int rv;
1992
1993   if (!sm->enabled)
1994     {
1995       nat_log_err ("nat44 is disabled");
1996       return VNET_API_ERROR_UNSUPPORTED;
1997     }
1998
1999   i = nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index);
2000   if (!i)
2001     {
2002       nat_log_err ("error interface couldn't be found");
2003       return VNET_API_ERROR_NO_SUCH_ENTRY;
2004     }
2005
2006   if (sm->num_workers > 1)
2007     {
2008       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2009       if (rv)
2010         {
2011           return rv;
2012         }
2013
2014       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
2015       if (rv)
2016         {
2017           return rv;
2018         }
2019
2020       vnet_feature_enable_disable (
2021         "ip4-unicast", "nat44-out2in-worker-handoff", sw_if_index, 0, 0, 0);
2022       vnet_feature_enable_disable ("ip4-output",
2023                                    "nat44-in2out-output-worker-handoff",
2024                                    sw_if_index, 0, 0, 0);
2025     }
2026   else
2027     {
2028       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2029       if (rv)
2030         {
2031           return rv;
2032         }
2033
2034       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
2035       if (rv)
2036         {
2037           return rv;
2038         }
2039
2040       vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2041                                    sw_if_index, 0, 0, 0);
2042       vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output",
2043                                    sw_if_index, 0, 0, 0);
2044     }
2045
2046   // remove interface
2047   pool_put (sm->output_feature_interfaces, i);
2048
2049   fib_index =
2050     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
2051   update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
2052
2053   outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
2054   if (outside_fib)
2055     {
2056       outside_fib->refcount--;
2057       if (!outside_fib->refcount)
2058         {
2059           vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2060         }
2061     }
2062
2063   vec_foreach (ap, sm->addresses)
2064     {
2065       snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 0);
2066     }
2067
2068   pool_foreach (m, sm->static_mappings)
2069     {
2070       if (!((is_sm_addr_only (m->flags))) ||
2071           (m->local_addr.as_u32 == m->external_addr.as_u32))
2072         {
2073           continue;
2074         }
2075       snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 0);
2076     }
2077
2078   return 0;
2079 }
2080
2081 int
2082 snat_set_workers (uword * bitmap)
2083 {
2084   snat_main_t *sm = &snat_main;
2085   int i, j = 0;
2086
2087   if (sm->num_workers < 2)
2088     return VNET_API_ERROR_FEATURE_DISABLED;
2089
2090   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2091     return VNET_API_ERROR_INVALID_WORKER;
2092
2093   vec_free (sm->workers);
2094   clib_bitmap_foreach (i, bitmap)
2095     {
2096       vec_add1(sm->workers, i);
2097       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2098       sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2099       j++;
2100     }
2101
2102   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2103
2104   return 0;
2105 }
2106
2107 int
2108 nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts)
2109 {
2110   fail_if_enabled ();
2111   snat_main_t *sm = &snat_main;
2112   sm->frame_queue_nelts = frame_queue_nelts;
2113   return 0;
2114 }
2115
2116 static void
2117 nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index,
2118                                 u32 new_fib_index, u32 old_fib_index)
2119 {
2120   snat_main_t *sm = &snat_main;
2121   nat_outside_fib_t *outside_fib;
2122   snat_interface_t *i;
2123   u8 is_add = 1;
2124   u8 match = 0;
2125
2126   if (!sm->enabled || (new_fib_index == old_fib_index)
2127       || (!vec_len (sm->outside_fibs)))
2128     {
2129       return;
2130     }
2131
2132   pool_foreach (i, sm->interfaces)
2133      {
2134       if (i->sw_if_index == sw_if_index)
2135         {
2136           if (!(nat_interface_is_outside (i)))
2137             return;
2138           match = 1;
2139         }
2140     }
2141
2142   pool_foreach (i, sm->output_feature_interfaces)
2143      {
2144       if (i->sw_if_index == sw_if_index)
2145         {
2146           if (!(nat_interface_is_outside (i)))
2147             return;
2148           match = 1;
2149         }
2150     }
2151
2152   if (!match)
2153     return;
2154
2155   vec_foreach (outside_fib, sm->outside_fibs)
2156   {
2157     if (outside_fib->fib_index == old_fib_index)
2158       {
2159         outside_fib->refcount--;
2160         if (!outside_fib->refcount)
2161           vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2162         break;
2163       }
2164   }
2165
2166   vec_foreach (outside_fib, sm->outside_fibs)
2167   {
2168     if (outside_fib->fib_index == new_fib_index)
2169       {
2170         outside_fib->refcount++;
2171         is_add = 0;
2172         break;
2173       }
2174   }
2175
2176   if (is_add)
2177     {
2178       vec_add2 (sm->outside_fibs, outside_fib, 1);
2179       outside_fib->refcount = 1;
2180       outside_fib->fib_index = new_fib_index;
2181     }
2182 }
2183
2184 static void nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque,
2185                                             u32 sw_if_index, u32 new_fib_index,
2186                                             u32 old_fib_index);
2187
2188 static void nat44_ed_add_del_interface_address_cb (
2189   ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
2190   u32 address_length, u32 if_address_index, u32 is_delete);
2191
2192 static void nat44_ed_add_del_sm_addr_only_cb (
2193   ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
2194   u32 address_length, u32 if_address_index, u32 is_delete);
2195
2196 void
2197 test_key_calc_split ()
2198 {
2199   ip4_address_t l_addr;
2200   l_addr.as_u8[0] = 1;
2201   l_addr.as_u8[1] = 1;
2202   l_addr.as_u8[2] = 1;
2203   l_addr.as_u8[3] = 1;
2204   ip4_address_t r_addr;
2205   r_addr.as_u8[0] = 2;
2206   r_addr.as_u8[1] = 2;
2207   r_addr.as_u8[2] = 2;
2208   r_addr.as_u8[3] = 2;
2209   u16 l_port = 40001;
2210   u16 r_port = 40301;
2211   u8 proto = 9;
2212   u32 fib_index = 9000001;
2213   u32 thread_index = 3000000001;
2214   u32 session_index = 3000000221;
2215   clib_bihash_kv_16_8_t kv;
2216   init_ed_kv (&kv, l_addr, l_port, r_addr, r_port, fib_index, proto,
2217               thread_index, session_index);
2218   ip4_address_t l_addr2;
2219   ip4_address_t r_addr2;
2220   clib_memset (&l_addr2, 0, sizeof (l_addr2));
2221   clib_memset (&r_addr2, 0, sizeof (r_addr2));
2222   u16 l_port2 = 0;
2223   u16 r_port2 = 0;
2224   u8 proto2 = 0;
2225   u32 fib_index2 = 0;
2226   split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
2227                &r_port2);
2228   ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2229   ASSERT (r_addr.as_u32 == r_addr2.as_u32);
2230   ASSERT (l_port == l_port2);
2231   ASSERT (r_port == r_port2);
2232   ASSERT (proto == proto2);
2233   ASSERT (fib_index == fib_index2);
2234   ASSERT (thread_index == ed_value_get_thread_index (&kv));
2235   ASSERT (session_index == ed_value_get_session_index (&kv));
2236
2237   fib_index = 7001;
2238   proto = 5;
2239   nat_protocol_t proto3 = ~0;
2240   u64 key = calc_nat_key (l_addr, l_port, fib_index, proto);
2241   split_nat_key (key, &l_addr2, &l_port2, &fib_index2, &proto3);
2242   ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2243   ASSERT (l_port == l_port2);
2244   ASSERT (proto == proto3);
2245   ASSERT (fib_index == fib_index2);
2246 }
2247
2248 static clib_error_t *
2249 nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
2250 {
2251   u32 fib_index;
2252   if (!is_add)
2253     {
2254       fib_index = ip4_fib_index_from_table_id (table_id);
2255       if (fib_index != ~0)
2256         {
2257           expire_per_vrf_sessions (fib_index);
2258         }
2259     }
2260   return 0;
2261 }
2262
2263 VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del);
2264
2265 void
2266 nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm)
2267 {
2268   vlib_node_t *node;
2269
2270   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2271   sm->out2in_node_index = node->index;
2272
2273   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2274   sm->in2out_node_index = node->index;
2275
2276   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output");
2277   sm->in2out_output_node_index = node->index;
2278 }
2279
2280 #define nat_validate_simple_counter(c, i)                                     \
2281   do                                                                          \
2282     {                                                                         \
2283       vlib_validate_simple_counter (&c, i);                                   \
2284       vlib_zero_simple_counter (&c, i);                                       \
2285     }                                                                         \
2286   while (0);
2287
2288 #define nat_init_simple_counter(c, n, sn)                                     \
2289   do                                                                          \
2290     {                                                                         \
2291       c.name = n;                                                             \
2292       c.stat_segment_name = sn;                                               \
2293       nat_validate_simple_counter (c, 0);                                     \
2294     }                                                                         \
2295   while (0);
2296
2297 static_always_inline void
2298 nat_validate_interface_counters (snat_main_t *sm, u32 sw_if_index)
2299 {
2300 #define _(x)                                                                  \
2301   nat_validate_simple_counter (sm->counters.fastpath.in2out.x, sw_if_index);  \
2302   nat_validate_simple_counter (sm->counters.fastpath.out2in.x, sw_if_index);  \
2303   nat_validate_simple_counter (sm->counters.slowpath.in2out.x, sw_if_index);  \
2304   nat_validate_simple_counter (sm->counters.slowpath.out2in.x, sw_if_index);
2305   foreach_nat_counter;
2306 #undef _
2307   nat_validate_simple_counter (sm->counters.hairpinning, sw_if_index);
2308 }
2309
2310 static clib_error_t *
2311 nat_init (vlib_main_t * vm)
2312 {
2313   snat_main_t *sm = &snat_main;
2314   vlib_thread_main_t *tm = vlib_get_thread_main ();
2315   vlib_thread_registration_t *tr;
2316   ip4_add_del_interface_address_callback_t cbi = { 0 };
2317   ip4_table_bind_callback_t cbt = { 0 };
2318   u32 i, num_threads = 0;
2319   uword *p, *bitmap = 0;
2320
2321   clib_memset (sm, 0, sizeof (*sm));
2322
2323   // required
2324   sm->vnet_main = vnet_get_main ();
2325   // convenience
2326   sm->ip4_main = &ip4_main;
2327   sm->api_main = vlibapi_get_main ();
2328   sm->ip4_lookup_main = &ip4_main.lookup_main;
2329
2330   // frame queue indices used for handoff
2331   sm->fq_out2in_index = ~0;
2332   sm->fq_in2out_index = ~0;
2333   sm->fq_in2out_output_index = ~0;
2334
2335   sm->log_level = NAT_LOG_ERROR;
2336
2337   nat44_set_node_indexes (sm, vm);
2338
2339   sm->log_class = vlib_log_register_class ("nat", 0);
2340   nat_ipfix_logging_init (vm);
2341
2342   nat_init_simple_counter (sm->total_sessions, "total-sessions",
2343                            "/nat44-ed/total-sessions");
2344   sm->max_cfg_sessions_gauge = stat_segment_new_entry (
2345     (u8 *) "/nat44-ed/max-cfg-sessions", STAT_DIR_TYPE_SCALAR_INDEX);
2346
2347 #define _(x)                                                                  \
2348   nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x,                \
2349                            "/nat44-ed/in2out/fastpath/" #x);                  \
2350   nat_init_simple_counter (sm->counters.fastpath.out2in.x, #x,                \
2351                            "/nat44-ed/out2in/fastpath/" #x);                  \
2352   nat_init_simple_counter (sm->counters.slowpath.in2out.x, #x,                \
2353                            "/nat44-ed/in2out/slowpath/" #x);                  \
2354   nat_init_simple_counter (sm->counters.slowpath.out2in.x, #x,                \
2355                            "/nat44-ed/out2in/slowpath/" #x);
2356   foreach_nat_counter;
2357 #undef _
2358   nat_init_simple_counter (sm->counters.hairpinning, "hairpinning",
2359                            "/nat44-ed/hairpinning");
2360
2361   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2362   if (p)
2363     {
2364       tr = (vlib_thread_registration_t *) p[0];
2365       if (tr)
2366         {
2367           sm->num_workers = tr->count;
2368           sm->first_worker_index = tr->first_index;
2369         }
2370     }
2371   num_threads = tm->n_vlib_mains - 1;
2372   sm->port_per_thread = 0xffff - 1024;
2373   vec_validate (sm->per_thread_data, num_threads);
2374
2375   /* Use all available workers by default */
2376   if (sm->num_workers > 1)
2377     {
2378       for (i = 0; i < sm->num_workers; i++)
2379         bitmap = clib_bitmap_set (bitmap, i, 1);
2380       snat_set_workers (bitmap);
2381       clib_bitmap_free (bitmap);
2382     }
2383   else
2384     {
2385       sm->per_thread_data[0].snat_thread_index = 0;
2386     }
2387
2388   /* callbacks to call when interface address changes. */
2389   cbi.function = nat44_ed_add_del_interface_address_cb;
2390   vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
2391   cbi.function = nat44_ed_add_del_sm_addr_only_cb;
2392   vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
2393
2394   /* callbacks to call when interface to table biding changes */
2395   cbt.function = nat44_ed_update_outside_fib_cb;
2396   vec_add1 (sm->ip4_main->table_bind_callbacks, cbt);
2397
2398   sm->fib_src_low =
2399     fib_source_allocate ("nat-low", FIB_SOURCE_PRIORITY_LOW,
2400                          FIB_SOURCE_BH_SIMPLE);
2401   sm->fib_src_hi =
2402     fib_source_allocate ("nat-hi", FIB_SOURCE_PRIORITY_HI,
2403                          FIB_SOURCE_BH_SIMPLE);
2404
2405   nat_affinity_init (vm);
2406   test_key_calc_split ();
2407
2408   return nat44_api_hookup (vm);
2409 }
2410
2411 VLIB_INIT_FUNCTION (nat_init);
2412
2413 int
2414 nat44_plugin_enable (nat44_config_t c)
2415 {
2416   snat_main_t *sm = &snat_main;
2417
2418   fail_if_enabled ();
2419
2420   if (c.static_mapping_only && !c.connection_tracking)
2421     {
2422       nat_log_err ("unsupported combination of configuration");
2423       return 1;
2424     }
2425
2426   sm->static_mapping_only = c.static_mapping_only;
2427   sm->static_mapping_connection_tracking = c.connection_tracking;
2428
2429   sm->forwarding_enabled = 0;
2430   sm->mss_clamping = 0;
2431   sm->pat = (!c.static_mapping_only ||
2432              (c.static_mapping_only && c.connection_tracking));
2433
2434   if (!c.sessions)
2435     c.sessions = 63 * 1024;
2436
2437   sm->max_translations_per_thread = c.sessions;
2438   stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
2439                                   sm->max_translations_per_thread);
2440   sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
2441
2442   vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
2443
2444   sm->inside_vrf_id = c.inside_vrf;
2445   sm->inside_fib_index =
2446     fib_table_find_or_create_and_lock
2447     (FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi);
2448
2449   sm->outside_vrf_id = c.outside_vrf;
2450   sm->outside_fib_index = fib_table_find_or_create_and_lock (
2451     FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi);
2452
2453   nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets);
2454
2455   nat_affinity_enable ();
2456
2457   nat_reset_timeouts (&sm->timeouts);
2458
2459   vlib_zero_simple_counter (&sm->total_sessions, 0);
2460
2461   if (!sm->frame_queue_nelts)
2462     {
2463       sm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
2464     }
2465
2466   if (sm->num_workers > 1)
2467     {
2468       if (sm->fq_in2out_index == ~0)
2469         {
2470           sm->fq_in2out_index = vlib_frame_queue_main_init (
2471             sm->in2out_node_index, sm->frame_queue_nelts);
2472         }
2473       if (sm->fq_out2in_index == ~0)
2474         {
2475           sm->fq_out2in_index = vlib_frame_queue_main_init (
2476             sm->out2in_node_index, sm->frame_queue_nelts);
2477         }
2478       if (sm->fq_in2out_output_index == ~0)
2479         {
2480           sm->fq_in2out_output_index = vlib_frame_queue_main_init (
2481             sm->in2out_output_node_index, sm->frame_queue_nelts);
2482         }
2483     }
2484
2485   sm->enabled = 1;
2486   sm->rconfig = c;
2487
2488   return 0;
2489 }
2490
2491 void
2492 nat44_addresses_free (snat_address_t ** addresses)
2493 {
2494   snat_address_t *ap;
2495   vec_foreach (ap, *addresses)
2496     {
2497     #define _(N, i, n, s) \
2498       vec_free (ap->busy_##n##_ports_per_thread);
2499       foreach_nat_protocol
2500     #undef _
2501     }
2502   vec_free (*addresses);
2503   *addresses = 0;
2504 }
2505
2506 int
2507 nat44_plugin_disable ()
2508 {
2509   snat_main_t *sm = &snat_main;
2510   snat_interface_t *i, *pool;
2511   int error = 0;
2512
2513   fail_if_disabled ();
2514
2515   pool = pool_dup (sm->interfaces);
2516   pool_foreach (i, pool)
2517     {
2518       if (nat_interface_is_inside (i))
2519         {
2520           error = nat44_ed_del_interface (i->sw_if_index, 1);
2521         }
2522       if (nat_interface_is_outside (i))
2523         {
2524           error = nat44_ed_del_interface (i->sw_if_index, 0);
2525         }
2526       if (error)
2527         {
2528           nat_log_err ("error occurred while removing interface %u",
2529                        i->sw_if_index);
2530         }
2531     }
2532   pool_free (sm->interfaces);
2533   pool_free (pool);
2534   sm->interfaces = 0;
2535
2536   pool = pool_dup (sm->output_feature_interfaces);
2537   pool_foreach (i, pool)
2538     {
2539       error = nat44_ed_del_output_interface (i->sw_if_index);
2540       if (error)
2541         {
2542           nat_log_err ("error occurred while removing interface %u",
2543                        i->sw_if_index);
2544         }
2545     }
2546   pool_free (sm->output_feature_interfaces);
2547   pool_free (pool);
2548   sm->output_feature_interfaces = 0;
2549
2550   vec_free (sm->max_translations_per_fib);
2551
2552   nat44_ed_db_free ();
2553
2554   nat44_addresses_free (&sm->addresses);
2555   nat44_addresses_free (&sm->twice_nat_addresses);
2556
2557   vec_free (sm->to_resolve);
2558   vec_free (sm->auto_add_sw_if_indices);
2559   vec_free (sm->auto_add_sw_if_indices_twice_nat);
2560
2561   sm->to_resolve = 0;
2562   sm->auto_add_sw_if_indices = 0;
2563   sm->auto_add_sw_if_indices_twice_nat = 0;
2564
2565   sm->forwarding_enabled = 0;
2566
2567   sm->enabled = 0;
2568   clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig));
2569
2570   return 0;
2571 }
2572
2573 void
2574 nat44_ed_forwarding_enable_disable (u8 is_enable)
2575 {
2576   snat_main_per_thread_data_t *tsm;
2577   snat_main_t *sm = &snat_main;
2578   snat_session_t *s;
2579
2580   u32 *ses_to_be_removed = 0, *ses_index;
2581
2582   sm->forwarding_enabled = is_enable != 0;
2583
2584   if (!sm->enabled || is_enable)
2585     {
2586       return;
2587     }
2588
2589   vec_foreach (tsm, sm->per_thread_data)
2590     {
2591       pool_foreach (s, tsm->sessions)
2592         {
2593           if (is_fwd_bypass_session (s))
2594             {
2595               vec_add1 (ses_to_be_removed, s - tsm->sessions);
2596             }
2597         }
2598       vec_foreach (ses_index, ses_to_be_removed)
2599         {
2600           s = pool_elt_at_index (tsm->sessions, ses_index[0]);
2601           nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
2602           nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
2603         }
2604
2605       vec_free (ses_to_be_removed);
2606     }
2607 }
2608
2609 void
2610 snat_free_outside_address_and_port (snat_address_t *addresses,
2611                                     u32 thread_index, ip4_address_t *addr,
2612                                     u16 port, nat_protocol_t protocol)
2613 {
2614   snat_main_t *sm = &snat_main;
2615   snat_address_t *a;
2616   u32 address_index;
2617   u16 port_host_byte_order = clib_net_to_host_u16 (port);
2618
2619   for (address_index = 0; address_index < vec_len (addresses);
2620        address_index++)
2621     {
2622       if (addresses[address_index].addr.as_u32 == addr->as_u32)
2623         break;
2624     }
2625
2626   ASSERT (address_index < vec_len (addresses));
2627
2628   a = addresses + address_index;
2629
2630   switch (protocol)
2631     {
2632 #define _(N, i, n, s) \
2633     case NAT_PROTOCOL_##N: \
2634       ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2635       --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2636       a->busy_##n##_ports--; \
2637       a->busy_##n##_ports_per_thread[thread_index]--; \
2638       break;
2639       foreach_nat_protocol
2640 #undef _
2641         default : nat_elog_info (sm, "unknown protocol");
2642       return;
2643     }
2644 }
2645
2646 int
2647 snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm,
2648                            ip4_address_t match_addr, u16 match_port,
2649                            u32 match_fib_index, nat_protocol_t match_protocol,
2650                            ip4_address_t *mapping_addr, u16 *mapping_port,
2651                            u32 *mapping_fib_index, u8 by_external,
2652                            u8 *is_addr_only, twice_nat_type_t *twice_nat,
2653                            lb_nat_type_t *lb, ip4_address_t *ext_host_addr,
2654                            u8 *is_identity_nat, snat_static_mapping_t **out)
2655 {
2656   clib_bihash_kv_8_8_t kv, value;
2657   clib_bihash_8_8_t *mapping_hash;
2658   snat_static_mapping_t *m;
2659   u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2660   nat44_lb_addr_port_t *local;
2661   u8 backend_index;
2662
2663   if (!by_external)
2664     {
2665       mapping_hash = &sm->static_mapping_by_local;
2666       init_nat_k (&kv, match_addr, match_port, match_fib_index,
2667                   match_protocol);
2668       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2669         {
2670           /* Try address only mapping */
2671           init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
2672           if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2673             return 1;
2674         }
2675     }
2676   else
2677     {
2678       mapping_hash = &sm->static_mapping_by_external;
2679       init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
2680       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2681         {
2682           /* Try address only mapping */
2683           init_nat_k (&kv, match_addr, 0, 0, 0);
2684           if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2685             return 1;
2686         }
2687     }
2688
2689   m = pool_elt_at_index (sm->static_mappings, value.value);
2690
2691   if (by_external)
2692     {
2693       if (is_sm_lb (m->flags))
2694         {
2695           if (PREDICT_FALSE (lb != 0))
2696             *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2697           if (m->affinity && !nat_affinity_find_and_lock (
2698                                vm, ext_host_addr[0], match_addr,
2699                                match_protocol, match_port, &backend_index))
2700             {
2701               local = pool_elt_at_index (m->locals, backend_index);
2702               *mapping_addr = local->addr;
2703               *mapping_port = local->port;
2704               *mapping_fib_index = local->fib_index;
2705               goto end;
2706             }
2707           // pick locals matching this worker
2708           if (PREDICT_FALSE (sm->num_workers > 1))
2709             {
2710               u32 thread_index = vlib_get_thread_index ();
2711               pool_foreach_index (i, m->locals)
2712                {
2713                 local = pool_elt_at_index (m->locals, i);
2714
2715                 ip4_header_t ip = {
2716                   .src_address = local->addr,
2717                 };
2718
2719                 if (nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index,
2720                                                       0) == thread_index)
2721                   {
2722                     vec_add1 (tmp, i);
2723                   }
2724                }
2725               ASSERT (vec_len (tmp) != 0);
2726             }
2727           else
2728             {
2729               pool_foreach_index (i, m->locals)
2730                {
2731                 vec_add1 (tmp, i);
2732               }
2733             }
2734           hi = vec_len (tmp) - 1;
2735           local = pool_elt_at_index (m->locals, tmp[hi]);
2736           rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2737           while (lo < hi)
2738             {
2739               mid = ((hi - lo) >> 1) + lo;
2740               local = pool_elt_at_index (m->locals, tmp[mid]);
2741               (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2742             }
2743           local = pool_elt_at_index (m->locals, tmp[lo]);
2744           if (!(local->prefix >= rand))
2745             return 1;
2746           *mapping_addr = local->addr;
2747           *mapping_port = local->port;
2748           *mapping_fib_index = local->fib_index;
2749           if (m->affinity)
2750             {
2751               if (nat_affinity_create_and_lock (ext_host_addr[0], match_addr,
2752                                                 match_protocol, match_port,
2753                                                 tmp[lo], m->affinity,
2754                                                 m->affinity_per_service_list_head_index))
2755                 nat_elog_info (sm, "create affinity record failed");
2756             }
2757           vec_free (tmp);
2758         }
2759       else
2760         {
2761           if (PREDICT_FALSE (lb != 0))
2762             *lb = NO_LB_NAT;
2763           *mapping_fib_index = m->fib_index;
2764           *mapping_addr = m->local_addr;
2765           /* Address only mapping doesn't change port */
2766           *mapping_port =
2767             is_sm_addr_only (m->flags) ? match_port : m->local_port;
2768         }
2769     }
2770   else
2771     {
2772       *mapping_addr = m->external_addr;
2773       /* Address only mapping doesn't change port */
2774       *mapping_port =
2775         is_sm_addr_only (m->flags) ? match_port : m->external_port;
2776       *mapping_fib_index = sm->outside_fib_index;
2777     }
2778
2779 end:
2780   if (PREDICT_FALSE (is_addr_only != 0))
2781     *is_addr_only = is_sm_addr_only (m->flags);
2782
2783   if (PREDICT_FALSE (twice_nat != 0))
2784     {
2785       *twice_nat = TWICE_NAT_DISABLED;
2786
2787       if (is_sm_twice_nat (m->flags))
2788         {
2789           *twice_nat = TWICE_NAT;
2790         }
2791       else if (is_sm_self_twice_nat (m->flags))
2792         {
2793           *twice_nat = TWICE_NAT_SELF;
2794         }
2795     }
2796
2797   if (PREDICT_FALSE (is_identity_nat != 0))
2798     *is_identity_nat = is_sm_identity_nat (m->flags);
2799
2800   if (out != 0)
2801     *out = m;
2802
2803   return 0;
2804 }
2805
2806 u32
2807 nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
2808                                   u32 rx_fib_index, u8 is_output)
2809 {
2810   snat_main_t *sm = &snat_main;
2811   u32 next_worker_index = sm->first_worker_index;
2812   u32 hash;
2813
2814   clib_bihash_kv_16_8_t kv16, value16;
2815
2816   u32 fib_index = rx_fib_index;
2817   if (b)
2818     {
2819       if (PREDICT_FALSE (is_output))
2820         {
2821           fib_index = sm->outside_fib_index;
2822           nat_outside_fib_t *outside_fib;
2823           fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
2824           fib_prefix_t pfx = {
2825                   .fp_proto = FIB_PROTOCOL_IP4,
2826                   .fp_len = 32,
2827                   .fp_addr = {
2828                           .ip4.as_u32 = ip->dst_address.as_u32,
2829                   } ,
2830           };
2831
2832           switch (vec_len (sm->outside_fibs))
2833             {
2834             case 0:
2835               fib_index = sm->outside_fib_index;
2836               break;
2837             case 1:
2838               fib_index = sm->outside_fibs[0].fib_index;
2839               break;
2840             default:
2841               vec_foreach (outside_fib, sm->outside_fibs)
2842                 {
2843                   fei = fib_table_lookup (outside_fib->fib_index, &pfx);
2844                   if (FIB_NODE_INDEX_INVALID != fei)
2845                     {
2846                       if (fib_entry_get_resolving_interface (fei) != ~0)
2847                         {
2848                           fib_index = outside_fib->fib_index;
2849                           break;
2850                         }
2851                     }
2852                 }
2853               break;
2854             }
2855         }
2856
2857       init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2858                  ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2859                  fib_index, ip->protocol);
2860
2861       if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))
2862         {
2863           next_worker_index = ed_value_get_thread_index (&value16);
2864           vnet_buffer2 (b)->nat.cached_session_index =
2865             ed_value_get_session_index (&value16);
2866           goto out;
2867         }
2868
2869       // dst NAT
2870       init_ed_k (&kv16, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2871                  ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2872                  rx_fib_index, ip->protocol);
2873       if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))
2874         {
2875           next_worker_index = ed_value_get_thread_index (&value16);
2876           vnet_buffer2 (b)->nat.cached_dst_nat_session_index =
2877             ed_value_get_session_index (&value16);
2878           goto out;
2879         }
2880     }
2881
2882   hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2883     (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
2884
2885   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2886     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2887   else
2888     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2889
2890 out:
2891   if (PREDICT_TRUE (!is_output))
2892     {
2893       nat_elog_debug_handoff (sm, "HANDOFF IN2OUT", next_worker_index,
2894                               rx_fib_index,
2895                               clib_net_to_host_u32 (ip->src_address.as_u32),
2896                               clib_net_to_host_u32 (ip->dst_address.as_u32));
2897     }
2898   else
2899     {
2900       nat_elog_debug_handoff (sm, "HANDOFF IN2OUT-OUTPUT-FEATURE",
2901                               next_worker_index, rx_fib_index,
2902                               clib_net_to_host_u32 (ip->src_address.as_u32),
2903                               clib_net_to_host_u32 (ip->dst_address.as_u32));
2904     }
2905
2906   return next_worker_index;
2907 }
2908
2909 u32
2910 nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
2911                                   u32 rx_fib_index, u8 is_output)
2912 {
2913   snat_main_t *sm = &snat_main;
2914   clib_bihash_kv_8_8_t kv, value;
2915   clib_bihash_kv_16_8_t kv16, value16;
2916
2917   u32 proto, next_worker_index = 0;
2918   u16 port;
2919   snat_static_mapping_t *m;
2920   u32 hash;
2921
2922   proto = ip_proto_to_nat_proto (ip->protocol);
2923
2924   if (PREDICT_FALSE (proto == NAT_PROTOCOL_ICMP))
2925     {
2926       ip4_address_t lookup_saddr, lookup_daddr;
2927       u16 lookup_sport, lookup_dport;
2928       u8 lookup_protocol;
2929       if (!nat_get_icmp_session_lookup_values (
2930             b, ip, &lookup_saddr, &lookup_sport, &lookup_daddr, &lookup_dport,
2931             &lookup_protocol))
2932         {
2933           init_ed_k (&kv16, lookup_saddr, lookup_sport, lookup_daddr,
2934                      lookup_dport, rx_fib_index, lookup_protocol);
2935           if (PREDICT_TRUE (
2936                 !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)))
2937             {
2938               next_worker_index = ed_value_get_thread_index (&value16);
2939               nat_elog_debug_handoff (
2940                 sm, "HANDOFF OUT2IN (session)", next_worker_index,
2941                 rx_fib_index, clib_net_to_host_u32 (ip->src_address.as_u32),
2942                 clib_net_to_host_u32 (ip->dst_address.as_u32));
2943               return next_worker_index;
2944             }
2945         }
2946     }
2947
2948   init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2949              ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2950              rx_fib_index, ip->protocol);
2951
2952   if (PREDICT_TRUE (
2953         !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)))
2954     {
2955       vnet_buffer2 (b)->nat.cached_session_index =
2956         ed_value_get_session_index (&value16);
2957       next_worker_index = ed_value_get_thread_index (&value16);
2958       nat_elog_debug_handoff (sm, "HANDOFF OUT2IN (session)",
2959                               next_worker_index, rx_fib_index,
2960                               clib_net_to_host_u32 (ip->src_address.as_u32),
2961                               clib_net_to_host_u32 (ip->dst_address.as_u32));
2962       return next_worker_index;
2963     }
2964
2965   /* first try static mappings without port */
2966   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2967     {
2968       init_nat_k (&kv, ip->dst_address, 0, 0, 0);
2969       if (!clib_bihash_search_8_8
2970           (&sm->static_mapping_by_external, &kv, &value))
2971         {
2972           m = pool_elt_at_index (sm->static_mappings, value.value);
2973           next_worker_index = m->workers[0];
2974           goto done;
2975         }
2976     }
2977
2978   /* unknown protocol */
2979   if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
2980     {
2981       /* use current thread */
2982       next_worker_index = vlib_get_thread_index ();
2983       goto done;
2984     }
2985
2986   port = vnet_buffer (b)->ip.reass.l4_dst_port;
2987
2988   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2989     {
2990       udp_header_t *udp = ip4_next_header (ip);
2991       icmp46_header_t *icmp = (icmp46_header_t *) udp;
2992       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
2993       if (!icmp_type_is_error_message
2994           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
2995         port = vnet_buffer (b)->ip.reass.l4_src_port;
2996       else
2997         {
2998           /* if error message, then it's not fragmented and we can access it */
2999           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3000           proto = ip_proto_to_nat_proto (inner_ip->protocol);
3001           void *l4_header = ip4_next_header (inner_ip);
3002           switch (proto)
3003             {
3004             case NAT_PROTOCOL_ICMP:
3005               icmp = (icmp46_header_t *) l4_header;
3006               echo = (icmp_echo_header_t *) (icmp + 1);
3007               port = echo->identifier;
3008               break;
3009             case NAT_PROTOCOL_UDP:
3010             case NAT_PROTOCOL_TCP:
3011               port = ((tcp_udp_header_t *) l4_header)->src_port;
3012               break;
3013             default:
3014               next_worker_index = vlib_get_thread_index ();
3015               goto done;
3016             }
3017         }
3018     }
3019
3020   /* try static mappings with port */
3021   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3022     {
3023       init_nat_k (&kv, ip->dst_address, port, 0, proto);
3024       if (!clib_bihash_search_8_8
3025           (&sm->static_mapping_by_external, &kv, &value))
3026         {
3027           m = pool_elt_at_index (sm->static_mappings, value.value);
3028           if (!is_sm_lb (m->flags))
3029             {
3030               next_worker_index = m->workers[0];
3031               goto done;
3032             }
3033
3034           hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3035             (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3036
3037           if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3038             next_worker_index =
3039               m->workers[hash & (_vec_len (m->workers) - 1)];
3040           else
3041             next_worker_index = m->workers[hash % _vec_len (m->workers)];
3042           goto done;
3043         }
3044     }
3045
3046   /* worker by outside port */
3047   next_worker_index = sm->first_worker_index;
3048   next_worker_index +=
3049     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3050
3051 done:
3052   nat_elog_debug_handoff (sm, "HANDOFF OUT2IN", next_worker_index,
3053                           rx_fib_index,
3054                           clib_net_to_host_u32 (ip->src_address.as_u32),
3055                           clib_net_to_host_u32 (ip->dst_address.as_u32));
3056   return next_worker_index;
3057 }
3058
3059 u32
3060 nat44_get_max_session_limit ()
3061 {
3062   snat_main_t *sm = &snat_main;
3063   u32 max_limit = 0, len = 0;
3064
3065   for (; len < vec_len (sm->max_translations_per_fib); len++)
3066     {
3067       if (max_limit < sm->max_translations_per_fib[len])
3068         max_limit = sm->max_translations_per_fib[len];
3069     }
3070   return max_limit;
3071 }
3072
3073 int
3074 nat44_set_session_limit (u32 session_limit, u32 vrf_id)
3075 {
3076   snat_main_t *sm = &snat_main;
3077   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3078   u32 len = vec_len (sm->max_translations_per_fib);
3079
3080   if (len <= fib_index)
3081     {
3082       vec_validate (sm->max_translations_per_fib, fib_index + 1);
3083
3084       for (; len < vec_len (sm->max_translations_per_fib); len++)
3085         sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
3086     }
3087
3088   sm->max_translations_per_fib[fib_index] = session_limit;
3089   return 0;
3090 }
3091
3092 int
3093 nat44_update_session_limit (u32 session_limit, u32 vrf_id)
3094 {
3095   snat_main_t *sm = &snat_main;
3096
3097   if (nat44_set_session_limit (session_limit, vrf_id))
3098     return 1;
3099   sm->max_translations_per_thread = nat44_get_max_session_limit ();
3100
3101   stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
3102                                   sm->max_translations_per_thread);
3103
3104   sm->translation_buckets =
3105     nat_calc_bihash_buckets (sm->max_translations_per_thread);
3106
3107   nat44_ed_sessions_clear ();
3108   return 0;
3109 }
3110
3111 static void
3112 nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
3113                          u32 translation_buckets)
3114 {
3115   dlist_elt_t *head;
3116
3117   pool_alloc (tsm->sessions, translations);
3118   pool_alloc (tsm->lru_pool, translations);
3119
3120   pool_get (tsm->lru_pool, head);
3121   tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
3122   clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
3123
3124   pool_get (tsm->lru_pool, head);
3125   tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
3126   clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
3127
3128   pool_get (tsm->lru_pool, head);
3129   tsm->udp_lru_head_index = head - tsm->lru_pool;
3130   clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
3131
3132   pool_get (tsm->lru_pool, head);
3133   tsm->icmp_lru_head_index = head - tsm->lru_pool;
3134   clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
3135
3136   pool_get (tsm->lru_pool, head);
3137   tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
3138   clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
3139 }
3140
3141 static void
3142 reinit_ed_flow_hash ()
3143 {
3144   snat_main_t *sm = &snat_main;
3145   // we expect 2 flows per session, so multiply translation_buckets by 2
3146   clib_bihash_init_16_8 (
3147     &sm->flow_hash, "ed-flow-hash",
3148     clib_max (1, sm->num_workers) * 2 * sm->translation_buckets, 0);
3149   clib_bihash_set_kvp_format_fn_16_8 (&sm->flow_hash, format_ed_session_kvp);
3150 }
3151
3152 static void
3153 nat44_ed_db_init (u32 translations, u32 translation_buckets)
3154 {
3155   snat_main_t *sm = &snat_main;
3156   snat_main_per_thread_data_t *tsm;
3157   u32 static_mapping_buckets = 1024;
3158   u32 static_mapping_memory_size = 64 << 20;
3159
3160   reinit_ed_flow_hash ();
3161
3162   clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3163                         "static_mapping_by_local", static_mapping_buckets,
3164                         static_mapping_memory_size);
3165   clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
3166                                      format_static_mapping_kvp);
3167
3168   clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3169                         "static_mapping_by_external", static_mapping_buckets,
3170                         static_mapping_memory_size);
3171   clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
3172                                      format_static_mapping_kvp);
3173
3174   if (sm->pat)
3175     {
3176       vec_foreach (tsm, sm->per_thread_data)
3177         {
3178           nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
3179                                    sm->translation_buckets);
3180         }
3181     }
3182 }
3183
3184 static void
3185 nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm)
3186 {
3187   pool_free (tsm->lru_pool);
3188   pool_free (tsm->sessions);
3189   vec_free (tsm->per_vrf_sessions_vec);
3190 }
3191
3192 static void
3193 nat44_ed_db_free ()
3194 {
3195   snat_main_t *sm = &snat_main;
3196   snat_main_per_thread_data_t *tsm;
3197
3198   pool_free (sm->static_mappings);
3199   clib_bihash_free_16_8 (&sm->flow_hash);
3200   clib_bihash_free_8_8 (&sm->static_mapping_by_local);
3201   clib_bihash_free_8_8 (&sm->static_mapping_by_external);
3202
3203   if (sm->pat)
3204     {
3205       vec_foreach (tsm, sm->per_thread_data)
3206         {
3207           nat44_ed_worker_db_free (tsm);
3208         }
3209     }
3210 }
3211
3212 void
3213 nat44_ed_sessions_clear ()
3214 {
3215   snat_main_t *sm = &snat_main;
3216   snat_main_per_thread_data_t *tsm;
3217
3218   reinit_ed_flow_hash ();
3219
3220   if (sm->pat)
3221     {
3222       vec_foreach (tsm, sm->per_thread_data)
3223         {
3224
3225           nat44_ed_worker_db_free (tsm);
3226           nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
3227                                    sm->translation_buckets);
3228         }
3229     }
3230   vlib_zero_simple_counter (&sm->total_sessions, 0);
3231 }
3232
3233 static void
3234 nat44_ed_add_del_sm_addr_only_cb (ip4_main_t *im, uword opaque,
3235                                   u32 sw_if_index, ip4_address_t *address,
3236                                   u32 address_length, u32 if_address_index,
3237                                   u32 is_delete)
3238 {
3239   clib_bihash_kv_8_8_t kv, value;
3240   snat_static_map_resolve_t *rp;
3241   snat_main_t *sm = &snat_main;
3242   snat_static_mapping_t *m;
3243   ip4_address_t l_addr;
3244   int i, rv = 0;
3245
3246   if (!sm->enabled)
3247     return;
3248
3249   for (i = 0; i < vec_len (sm->to_resolve); i++)
3250     {
3251       rp = sm->to_resolve + i;
3252       if (rp->addr_only && rp->sw_if_index == sw_if_index)
3253         {
3254           goto match;
3255         }
3256     }
3257   return;
3258
3259 match:
3260   init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
3261               sm->outside_fib_index, rp->addr_only ? 0 : rp->proto);
3262
3263   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3264     {
3265       m = 0;
3266     }
3267   else
3268     {
3269       m = pool_elt_at_index (sm->static_mappings, value.value);
3270     }
3271
3272   // Indetity mapping
3273   if (rp->l_addr.as_u32 == 0)
3274     {
3275       l_addr.as_u32 = address[0].as_u32;
3276     }
3277   else
3278     {
3279       l_addr.as_u32 = rp->l_addr.as_u32;
3280     }
3281
3282   if (is_delete)
3283     {
3284       if (m)
3285         {
3286           rv = nat44_ed_del_static_mapping (l_addr, address[0], rp->l_port,
3287                                             rp->e_port, rp->proto, rp->vrf_id,
3288                                             ~0, rp->flags);
3289         }
3290     }
3291   else
3292     {
3293       if (!m)
3294         {
3295           rv = nat44_ed_add_static_mapping (
3296             l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id,
3297             ~0, rp->flags, rp->pool_addr, rp->tag);
3298         }
3299       // else don't trip over lease renewal, static config
3300     }
3301   if (rv)
3302     {
3303       nat_elog_notice_X1 (sm, "nat44_ed_del_static_mapping returned %d", "i4",
3304                           rv);
3305     }
3306 }
3307
3308 static void
3309 nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
3310                                        u32 sw_if_index, ip4_address_t *address,
3311                                        u32 address_length,
3312                                        u32 if_address_index, u32 is_delete)
3313 {
3314   snat_main_t *sm = &snat_main;
3315   snat_static_map_resolve_t *rp;
3316   ip4_address_t l_addr;
3317   int i, j;
3318   int rv;
3319   u8 twice_nat = 0;
3320   snat_address_t *addresses = sm->addresses;
3321
3322   if (!sm->enabled)
3323     {
3324       return;
3325     }
3326
3327   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
3328     {
3329       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3330         goto match;
3331     }
3332
3333   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
3334     {
3335       twice_nat = 1;
3336       addresses = sm->twice_nat_addresses;
3337       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3338         goto match;
3339     }
3340
3341   return;
3342
3343 match:
3344   if (!is_delete)
3345     {
3346       /* Don't trip over lease renewal, static config */
3347       for (j = 0; j < vec_len (addresses); j++)
3348         if (addresses[j].addr.as_u32 == address->as_u32)
3349           return;
3350
3351       (void) nat44_ed_add_address (address, ~0, twice_nat);
3352       /* Scan static map resolution vector */
3353       for (j = 0; j < vec_len (sm->to_resolve); j++)
3354         {
3355           rp = sm->to_resolve + j;
3356           if (rp->addr_only)
3357             continue;
3358           /* On this interface? */
3359           if (rp->sw_if_index == sw_if_index)
3360             {
3361               // TODO: remove if not needed (handled by function)
3362               /* Indetity mapping? */
3363               if (rp->l_addr.as_u32 == 0)
3364                 l_addr.as_u32 = address[0].as_u32;
3365               else
3366                 l_addr.as_u32 = rp->l_addr.as_u32;
3367
3368               /* Add the static mapping */
3369               rv = nat44_ed_add_static_mapping (
3370                 l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
3371                 rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag);
3372               if (rv)
3373                 {
3374                   nat_elog_notice_X1 (sm, "add_static_mapping returned %d",
3375                                       "i4", rv);
3376                 }
3377             }
3378         }
3379       return;
3380     }
3381   else
3382     {
3383       // remove all static mapping records
3384       (void) nat44_ed_del_address (address[0], 1, twice_nat);
3385     }
3386 }
3387
3388 int
3389 nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat)
3390 {
3391   snat_main_t *sm = &snat_main;
3392   ip4_main_t *ip4_main = sm->ip4_main;
3393   ip4_address_t *first_int_addr;
3394   u32 *auto_add_sw_if_indices = twice_nat ?
3395                                   sm->auto_add_sw_if_indices_twice_nat :
3396                                   sm->auto_add_sw_if_indices;
3397   int i;
3398
3399   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
3400     {
3401       if (auto_add_sw_if_indices[i] == sw_if_index)
3402         {
3403           return VNET_API_ERROR_VALUE_EXIST;
3404         }
3405     }
3406
3407   // add to the auto-address list
3408   if (twice_nat)
3409     {
3410       vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3411     }
3412   else
3413     {
3414       vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
3415     }
3416
3417   // if the address is already bound - or static - add it now
3418   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
3419   if (first_int_addr)
3420     {
3421       (void) nat44_ed_add_address (first_int_addr, ~0, twice_nat);
3422     }
3423
3424   return 0;
3425 }
3426
3427 int
3428 nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat)
3429 {
3430   snat_main_t *sm = &snat_main;
3431   ip4_main_t *ip4_main = sm->ip4_main;
3432   ip4_address_t *first_int_addr;
3433   snat_static_map_resolve_t *rp;
3434   u32 *indices_to_delete = 0;
3435   int i, j;
3436   u32 *auto_add_sw_if_indices;
3437
3438   if (!sm->enabled)
3439     {
3440       return VNET_API_ERROR_UNSUPPORTED;
3441     }
3442
3443   auto_add_sw_if_indices = twice_nat ? sm->auto_add_sw_if_indices_twice_nat :
3444                                        sm->auto_add_sw_if_indices;
3445
3446   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
3447     {
3448       if (auto_add_sw_if_indices[i] == sw_if_index)
3449         {
3450           first_int_addr =
3451             ip4_interface_first_address (ip4_main, sw_if_index, 0);
3452           if (first_int_addr)
3453             {
3454               // remove all static mapping records
3455               (void) nat44_ed_del_address (first_int_addr[0], 1, twice_nat);
3456             }
3457           else
3458             {
3459               for (j = 0; j < vec_len (sm->to_resolve); j++)
3460                 {
3461                   rp = sm->to_resolve + j;
3462                   if (rp->sw_if_index == sw_if_index)
3463                     {
3464                       vec_add1 (indices_to_delete, j);
3465                     }
3466                 }
3467               if (vec_len (indices_to_delete))
3468                 {
3469                   for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3470                     {
3471                       vec_del1 (sm->to_resolve, j);
3472                     }
3473                   vec_free (indices_to_delete);
3474                 }
3475             }
3476
3477           if (twice_nat)
3478             {
3479               vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3480             }
3481           else
3482             {
3483               vec_del1 (sm->auto_add_sw_if_indices, i);
3484             }
3485           return 0;
3486         }
3487     }
3488   return VNET_API_ERROR_NO_SUCH_ENTRY;
3489 }
3490
3491 int
3492 nat44_ed_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3493                       ip4_address_t *eh_addr, u16 eh_port, u8 proto,
3494                       u32 vrf_id, int is_in)
3495 {
3496   ip4_header_t ip;
3497   clib_bihash_kv_16_8_t kv, value;
3498   u32 fib_index;
3499   snat_session_t *s;
3500   snat_main_per_thread_data_t *tsm;
3501
3502   if (!sm->enabled)
3503     {
3504       return VNET_API_ERROR_UNSUPPORTED;
3505     }
3506
3507   fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3508   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3509   if (sm->num_workers > 1)
3510     tsm = vec_elt_at_index (
3511       sm->per_thread_data,
3512       nat44_ed_get_in2out_worker_index (0, &ip, fib_index, 0));
3513   else
3514     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3515
3516   init_ed_k (&kv, *addr, port, *eh_addr, eh_port, fib_index, proto);
3517   if (clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
3518     {
3519       return VNET_API_ERROR_NO_SUCH_ENTRY;
3520     }
3521
3522   if (pool_is_free_index (tsm->sessions, ed_value_get_session_index (&value)))
3523     return VNET_API_ERROR_UNSPECIFIED;
3524   s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
3525   nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
3526   nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
3527   return 0;
3528 }
3529
3530 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
3531                                  vlib_node_runtime_t * node,
3532                                  vlib_frame_t * frame)
3533 {
3534   return 0;
3535 }
3536
3537 VLIB_REGISTER_NODE (nat_default_node) = {
3538   .name = "nat-default",
3539   .vector_size = sizeof (u32),
3540   .format_trace = 0,
3541   .type = VLIB_NODE_TYPE_INTERNAL,
3542   .n_errors = 0,
3543   .n_next_nodes = NAT_N_NEXT,
3544   .next_nodes = {
3545     [NAT_NEXT_DROP] = "error-drop",
3546     [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3547     [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
3548     [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
3549     [NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH] = "nat44-ed-in2out-output",
3550     [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
3551     [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
3552     [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
3553     [NAT_NEXT_IN2OUT_CLASSIFY] = "nat44-in2out-worker-handoff",
3554     [NAT_NEXT_OUT2IN_CLASSIFY] = "nat44-out2in-worker-handoff",
3555   },
3556 };
3557
3558 void
3559 nat_6t_l3_l4_csum_calc (nat_6t_flow_t *f)
3560 {
3561   f->l3_csum_delta = 0;
3562   f->l4_csum_delta = 0;
3563   if (f->ops & NAT_FLOW_OP_SADDR_REWRITE &&
3564       f->rewrite.saddr.as_u32 != f->match.saddr.as_u32)
3565     {
3566       f->l3_csum_delta =
3567         ip_csum_add_even (f->l3_csum_delta, f->rewrite.saddr.as_u32);
3568       f->l3_csum_delta =
3569         ip_csum_sub_even (f->l3_csum_delta, f->match.saddr.as_u32);
3570     }
3571   else
3572     {
3573       f->rewrite.saddr.as_u32 = f->match.saddr.as_u32;
3574     }
3575   if (f->ops & NAT_FLOW_OP_DADDR_REWRITE &&
3576       f->rewrite.daddr.as_u32 != f->match.daddr.as_u32)
3577     {
3578       f->l3_csum_delta =
3579         ip_csum_add_even (f->l3_csum_delta, f->rewrite.daddr.as_u32);
3580       f->l3_csum_delta =
3581         ip_csum_sub_even (f->l3_csum_delta, f->match.daddr.as_u32);
3582     }
3583   else
3584     {
3585       f->rewrite.daddr.as_u32 = f->match.daddr.as_u32;
3586     }
3587   if (f->ops & NAT_FLOW_OP_SPORT_REWRITE && f->rewrite.sport != f->match.sport)
3588     {
3589       f->l4_csum_delta = ip_csum_add_even (f->l4_csum_delta, f->rewrite.sport);
3590       f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.sport);
3591     }
3592   else
3593     {
3594       f->rewrite.sport = f->match.sport;
3595     }
3596   if (f->ops & NAT_FLOW_OP_DPORT_REWRITE && f->rewrite.dport != f->match.dport)
3597     {
3598       f->l4_csum_delta = ip_csum_add_even (f->l4_csum_delta, f->rewrite.dport);
3599       f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.dport);
3600     }
3601   else
3602     {
3603       f->rewrite.dport = f->match.dport;
3604     }
3605   if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE &&
3606       f->rewrite.icmp_id != f->match.sport)
3607     {
3608       f->l4_csum_delta =
3609         ip_csum_add_even (f->l4_csum_delta, f->rewrite.icmp_id);
3610       f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.sport);
3611     }
3612   else
3613     {
3614       f->rewrite.icmp_id = f->match.sport;
3615     }
3616   if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
3617     {
3618     }
3619   else
3620     {
3621       f->rewrite.fib_index = f->match.fib_index;
3622     }
3623 }
3624
3625 static_always_inline int
3626 nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3627                             ip4_header_t *ip, nat_6t_flow_t *f);
3628
3629 static_always_inline void
3630 nat_6t_flow_ip4_translate (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
3631                            nat_6t_flow_t *f, nat_protocol_t proto,
3632                            int is_icmp_inner_ip4, int skip_saddr_rewrite)
3633 {
3634   udp_header_t *udp = ip4_next_header (ip);
3635   tcp_header_t *tcp = (tcp_header_t *) udp;
3636
3637   if ((NAT_PROTOCOL_TCP == proto || NAT_PROTOCOL_UDP == proto) &&
3638       !vnet_buffer (b)->ip.reass.is_non_first_fragment)
3639     {
3640       if (!is_icmp_inner_ip4)
3641         { // regular case
3642           ip->src_address = f->rewrite.saddr;
3643           ip->dst_address = f->rewrite.daddr;
3644           udp->src_port = f->rewrite.sport;
3645           udp->dst_port = f->rewrite.dport;
3646         }
3647       else
3648         { // icmp inner ip4 - reversed saddr/daddr
3649           ip->src_address = f->rewrite.daddr;
3650           ip->dst_address = f->rewrite.saddr;
3651           udp->src_port = f->rewrite.dport;
3652           udp->dst_port = f->rewrite.sport;
3653         }
3654
3655       if (NAT_PROTOCOL_TCP == proto)
3656         {
3657           ip_csum_t tcp_sum = tcp->checksum;
3658           tcp_sum = ip_csum_sub_even (tcp_sum, f->l3_csum_delta);
3659           tcp_sum = ip_csum_sub_even (tcp_sum, f->l4_csum_delta);
3660           mss_clamping (sm->mss_clamping, tcp, &tcp_sum);
3661           tcp->checksum = ip_csum_fold (tcp_sum);
3662         }
3663       else if (proto == NAT_PROTOCOL_UDP && udp->checksum)
3664         {
3665           ip_csum_t udp_sum = udp->checksum;
3666           udp_sum = ip_csum_sub_even (udp_sum, f->l3_csum_delta);
3667           udp_sum = ip_csum_sub_even (udp_sum, f->l4_csum_delta);
3668           udp->checksum = ip_csum_fold (udp_sum);
3669         }
3670     }
3671   else
3672     {
3673       if (!is_icmp_inner_ip4)
3674         { // regular case
3675           if (!skip_saddr_rewrite)
3676             {
3677               ip->src_address = f->rewrite.saddr;
3678             }
3679           ip->dst_address = f->rewrite.daddr;
3680         }
3681       else
3682         { // icmp inner ip4 - reversed saddr/daddr
3683           ip->src_address = f->rewrite.daddr;
3684           ip->dst_address = f->rewrite.saddr;
3685         }
3686     }
3687
3688   if (skip_saddr_rewrite)
3689     {
3690       ip->checksum = ip4_header_checksum (ip);
3691     }
3692   else
3693     {
3694       ip_csum_t ip_sum = ip->checksum;
3695       ip_sum = ip_csum_sub_even (ip_sum, f->l3_csum_delta);
3696       ip->checksum = ip_csum_fold (ip_sum);
3697     }
3698   if (0xffff == ip->checksum)
3699     ip->checksum = 0;
3700   ASSERT (ip4_header_checksum_is_valid (ip));
3701 }
3702
3703 static_always_inline int
3704 it_fits (vlib_main_t *vm, vlib_buffer_t *b, void *object, size_t size)
3705 {
3706   int result = ((u8 *) object + size <=
3707                 (u8 *) vlib_buffer_get_current (b) + b->current_length) &&
3708                vlib_object_within_buffer_data (vm, b, object, size);
3709   return result;
3710 }
3711
3712 static_always_inline int
3713 nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3714                             ip4_header_t *ip, nat_6t_flow_t *f)
3715 {
3716   if (IP_PROTOCOL_ICMP != ip->protocol)
3717     return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED;
3718
3719   icmp46_header_t *icmp = ip4_next_header (ip);
3720   icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3721
3722   if ((!vnet_buffer (b)->ip.reass.is_non_first_fragment))
3723     {
3724       if (!it_fits (vm, b, icmp, sizeof (*icmp)))
3725         {
3726           return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3727         }
3728
3729       if (!icmp_type_is_error_message (icmp->type))
3730         {
3731           if ((f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) &&
3732               (f->rewrite.icmp_id != echo->identifier))
3733             {
3734               ip_csum_t sum = icmp->checksum;
3735               sum = ip_csum_update (sum, echo->identifier, f->rewrite.icmp_id,
3736                                     icmp_echo_header_t,
3737                                     identifier /* changed member */);
3738               echo->identifier = f->rewrite.icmp_id;
3739               icmp->checksum = ip_csum_fold (sum);
3740             }
3741         }
3742       else
3743         {
3744           ip_csum_t sum = ip_incremental_checksum (
3745             0, icmp,
3746             clib_net_to_host_u16 (ip->length) - ip4_header_bytes (ip));
3747           sum = (u16) ~ip_csum_fold (sum);
3748           if (sum != 0)
3749             {
3750               return NAT_ED_TRNSL_ERR_INVALID_CSUM;
3751             }
3752
3753           // errors are not fragmented
3754           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3755
3756           if (!ip4_header_checksum_is_valid (inner_ip))
3757             {
3758               return NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT;
3759             }
3760
3761           nat_protocol_t inner_proto =
3762             ip_proto_to_nat_proto (inner_ip->protocol);
3763
3764           ip_csum_t old_icmp_sum = icmp->checksum;
3765           ip_csum_t old_inner_ip_sum = inner_ip->checksum;
3766           ip_csum_t old_udp_sum;
3767           ip_csum_t old_tcp_sum;
3768           ip_csum_t new_icmp_sum;
3769           udp_header_t *udp;
3770           tcp_header_t *tcp;
3771
3772           switch (inner_proto)
3773             {
3774             case NAT_PROTOCOL_UDP:
3775               udp = (udp_header_t *) (inner_ip + 1);
3776               if (!it_fits (vm, b, udp, sizeof (*udp)))
3777                 {
3778                   return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3779                 }
3780               old_udp_sum = udp->checksum;
3781               nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto,
3782                                          1 /* is_icmp_inner_ip4 */,
3783                                          0 /* skip_saddr_rewrite */);
3784               new_icmp_sum = ip_csum_sub_even (old_icmp_sum, f->l3_csum_delta);
3785               new_icmp_sum = ip_csum_sub_even (new_icmp_sum, f->l4_csum_delta);
3786               new_icmp_sum =
3787                 ip_csum_update (new_icmp_sum, old_inner_ip_sum,
3788                                 inner_ip->checksum, ip4_header_t, checksum);
3789               new_icmp_sum =
3790                 ip_csum_update (new_icmp_sum, old_udp_sum, udp->checksum,
3791                                 udp_header_t, checksum);
3792               new_icmp_sum = ip_csum_fold (new_icmp_sum);
3793               icmp->checksum = new_icmp_sum;
3794               break;
3795             case NAT_PROTOCOL_TCP:
3796               tcp = (tcp_header_t *) (inner_ip + 1);
3797               if (!it_fits (vm, b, tcp, sizeof (*tcp)))
3798                 {
3799                   return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3800                 }
3801               old_tcp_sum = tcp->checksum;
3802               nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto,
3803                                          1 /* is_icmp_inner_ip4 */,
3804                                          0 /* skip_saddr_rewrite */);
3805               new_icmp_sum = ip_csum_sub_even (old_icmp_sum, f->l3_csum_delta);
3806               new_icmp_sum = ip_csum_sub_even (new_icmp_sum, f->l4_csum_delta);
3807               new_icmp_sum =
3808                 ip_csum_update (new_icmp_sum, old_inner_ip_sum,
3809                                 inner_ip->checksum, ip4_header_t, checksum);
3810               new_icmp_sum =
3811                 ip_csum_update (new_icmp_sum, old_tcp_sum, tcp->checksum,
3812                                 tcp_header_t, checksum);
3813               new_icmp_sum = ip_csum_fold (new_icmp_sum);
3814               icmp->checksum = new_icmp_sum;
3815               break;
3816             case NAT_PROTOCOL_ICMP:
3817               if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE)
3818                 {
3819                   icmp46_header_t *inner_icmp = ip4_next_header (inner_ip);
3820                   if (!it_fits (vm, b, inner_icmp, sizeof (*inner_icmp)))
3821                     {
3822                       return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3823                     }
3824                   icmp_echo_header_t *inner_echo =
3825                     (icmp_echo_header_t *) (inner_icmp + 1);
3826                   if (f->rewrite.icmp_id != inner_echo->identifier)
3827                     {
3828                       ip_csum_t sum = icmp->checksum;
3829                       sum = ip_csum_update (
3830                         sum, inner_echo->identifier, f->rewrite.icmp_id,
3831                         icmp_echo_header_t, identifier /* changed member */);
3832                       icmp->checksum = ip_csum_fold (sum);
3833                       ip_csum_t inner_sum = inner_icmp->checksum;
3834                       inner_sum = ip_csum_update (
3835                         sum, inner_echo->identifier, f->rewrite.icmp_id,
3836                         icmp_echo_header_t, identifier /* changed member */);
3837                       inner_icmp->checksum = ip_csum_fold (inner_sum);
3838                       inner_echo->identifier = f->rewrite.icmp_id;
3839                     }
3840                 }
3841               break;
3842             default:
3843               clib_warning ("unexpected NAT protocol value `%d'", inner_proto);
3844               return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED;
3845             }
3846         }
3847     }
3848
3849   return NAT_ED_TRNSL_ERR_SUCCESS;
3850 }
3851
3852 static_always_inline nat_translation_error_e
3853 nat_6t_flow_buf_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3854                            ip4_header_t *ip, nat_6t_flow_t *f,
3855                            nat_protocol_t proto, int is_output_feature,
3856                            int is_i2o)
3857 {
3858   if (!is_output_feature && f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
3859     {
3860       vnet_buffer (b)->sw_if_index[VLIB_TX] = f->rewrite.fib_index;
3861     }
3862
3863   if (NAT_PROTOCOL_ICMP == proto)
3864     {
3865       if (ip->src_address.as_u32 != f->rewrite.saddr.as_u32)
3866         {
3867           // packet is returned from a router, not from destination
3868           // skip source address rewrite if in o2i path
3869           nat_6t_flow_ip4_translate (sm, b, ip, f, proto,
3870                                      0 /* is_icmp_inner_ip4 */,
3871                                      !is_i2o /* skip_saddr_rewrite */);
3872         }
3873       else
3874         {
3875           nat_6t_flow_ip4_translate (sm, b, ip, f, proto,
3876                                      0 /* is_icmp_inner_ip4 */,
3877                                      0 /* skip_saddr_rewrite */);
3878         }
3879       return nat_6t_flow_icmp_translate (vm, sm, b, ip, f);
3880     }
3881
3882   nat_6t_flow_ip4_translate (sm, b, ip, f, proto, 0 /* is_icmp_inner_ip4 */,
3883                              0 /* skip_saddr_rewrite */);
3884
3885   return NAT_ED_TRNSL_ERR_SUCCESS;
3886 }
3887
3888 nat_translation_error_e
3889 nat_6t_flow_buf_translate_i2o (vlib_main_t *vm, snat_main_t *sm,
3890                                vlib_buffer_t *b, ip4_header_t *ip,
3891                                nat_6t_flow_t *f, nat_protocol_t proto,
3892                                int is_output_feature)
3893 {
3894   return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature,
3895                                     1 /* is_i2o */);
3896 }
3897
3898 nat_translation_error_e
3899 nat_6t_flow_buf_translate_o2i (vlib_main_t *vm, snat_main_t *sm,
3900                                vlib_buffer_t *b, ip4_header_t *ip,
3901                                nat_6t_flow_t *f, nat_protocol_t proto,
3902                                int is_output_feature)
3903 {
3904   return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature,
3905                                     0 /* is_i2o */);
3906 }
3907
3908 u8 *
3909 format_nat_6t (u8 *s, va_list *args)
3910 {
3911   nat_6t_t *t = va_arg (*args, nat_6t_t *);
3912
3913   s = format (s, "saddr %U sport %u daddr %U dport %u proto %U fib_idx %u",
3914               format_ip4_address, t->saddr.as_u8,
3915               clib_net_to_host_u16 (t->sport), format_ip4_address,
3916               t->daddr.as_u8, clib_net_to_host_u16 (t->dport),
3917               format_ip_protocol, t->proto, t->fib_index);
3918   return s;
3919 }
3920
3921 u8 *
3922 format_nat_ed_translation_error (u8 *s, va_list *args)
3923 {
3924   nat_translation_error_e e = va_arg (*args, nat_translation_error_e);
3925
3926   switch (e)
3927     {
3928     case NAT_ED_TRNSL_ERR_SUCCESS:
3929       s = format (s, "success");
3930       break;
3931     case NAT_ED_TRNSL_ERR_TRANSLATION_FAILED:
3932       s = format (s, "translation-failed");
3933       break;
3934     case NAT_ED_TRNSL_ERR_FLOW_MISMATCH:
3935       s = format (s, "flow-mismatch");
3936       break;
3937     case NAT_ED_TRNSL_ERR_PACKET_TRUNCATED:
3938       s = format (s, "packet-truncated");
3939       break;
3940     case NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT:
3941       s = format (s, "inner-ip-corrupted");
3942       break;
3943     case NAT_ED_TRNSL_ERR_INVALID_CSUM:
3944       s = format (s, "invalid-checksum");
3945       break;
3946     }
3947   return s;
3948 }
3949
3950 u8 *
3951 format_nat_6t_flow (u8 *s, va_list *args)
3952 {
3953   nat_6t_flow_t *f = va_arg (*args, nat_6t_flow_t *);
3954
3955   s = format (s, "match: %U ", format_nat_6t, &f->match);
3956   int r = 0;
3957   if (f->ops & NAT_FLOW_OP_SADDR_REWRITE)
3958     {
3959       s = format (s, "rewrite: saddr %U ", format_ip4_address,
3960                   f->rewrite.saddr.as_u8);
3961       r = 1;
3962     }
3963   if (f->ops & NAT_FLOW_OP_SPORT_REWRITE)
3964     {
3965       if (!r)
3966         {
3967           s = format (s, "rewrite: ");
3968           r = 1;
3969         }
3970       s = format (s, "sport %u ", clib_net_to_host_u16 (f->rewrite.sport));
3971     }
3972   if (f->ops & NAT_FLOW_OP_DADDR_REWRITE)
3973     {
3974       if (!r)
3975         {
3976           s = format (s, "rewrite: ");
3977           r = 1;
3978         }
3979       s = format (s, "daddr %U ", format_ip4_address, f->rewrite.daddr.as_u8);
3980     }
3981   if (f->ops & NAT_FLOW_OP_DPORT_REWRITE)
3982     {
3983       if (!r)
3984         {
3985           s = format (s, "rewrite: ");
3986           r = 1;
3987         }
3988       s = format (s, "dport %u ", clib_net_to_host_u16 (f->rewrite.dport));
3989     }
3990   if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE)
3991     {
3992       if (!r)
3993         {
3994           s = format (s, "rewrite: ");
3995           r = 1;
3996         }
3997       s = format (s, "icmp-id %u ", clib_net_to_host_u16 (f->rewrite.icmp_id));
3998     }
3999   if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
4000     {
4001       if (!r)
4002         {
4003           s = format (s, "rewrite: ");
4004           r = 1;
4005         }
4006       s = format (s, "txfib %u ", f->rewrite.fib_index);
4007     }
4008   return s;
4009 }
4010
4011 /*
4012  * fd.io coding-style-patch-verification: ON
4013  *
4014  * Local Variables:
4015  * eval: (c-set-style "gnu")
4016  * End:
4017  */