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