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