nat: adding a new api nat44_ed_vrf_tables_v2_dump
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed_api.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /**
17  * @file
18  * @brief NAT44 plugin API implementation
19  */
20
21 #include <vnet/ip/ip_types_api.h>
22 #include <vlibmemory/api.h>
23
24 #include <vnet/fib/fib_table.h>
25
26 #include <nat/lib/nat_inlines.h>
27 #include <nat/lib/ipfix_logging.h>
28
29 #include <nat/nat44-ed/nat44_ed.h>
30
31 #include <nat/nat44-ed/nat44_ed.api_enum.h>
32 #include <nat/nat44-ed/nat44_ed.api_types.h>
33
34 #include <nat/nat44-ed/nat44_ed_inlines.h>
35
36 #define REPLY_MSG_ID_BASE sm->msg_id_base
37 #include <vlibapi/api_helper_macros.h>
38
39 /* New API calls */
40
41 static void
42 vl_api_nat44_ed_plugin_enable_disable_t_handler (
43   vl_api_nat44_ed_plugin_enable_disable_t *mp)
44 {
45   snat_main_t *sm = &snat_main;
46   nat44_config_t c = { 0 };
47   vl_api_nat44_ed_plugin_enable_disable_reply_t *rmp;
48   int rv = 0;
49
50   if (mp->enable)
51     {
52       if ((mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY) ||
53           (mp->flags & NAT44_API_IS_CONNECTION_TRACKING))
54         {
55           rv = VNET_API_ERROR_UNSUPPORTED;
56         }
57       else
58         {
59           c.sessions = ntohl (mp->sessions);
60           c.inside_vrf = ntohl (mp->inside_vrf);
61           c.outside_vrf = ntohl (mp->outside_vrf);
62
63           rv = nat44_plugin_enable (c);
64         }
65     }
66   else
67     {
68       rv = nat44_plugin_disable ();
69     }
70
71   REPLY_MACRO (VL_API_NAT44_ED_PLUGIN_ENABLE_DISABLE_REPLY);
72 }
73
74 static void
75 vl_api_nat44_ed_set_fq_options_t_handler (vl_api_nat44_ed_set_fq_options_t *mp)
76 {
77   snat_main_t *sm = &snat_main;
78   vl_api_nat44_ed_set_fq_options_reply_t *rmp;
79   int rv = 0;
80   u32 frame_queue_nelts = ntohl (mp->frame_queue_nelts);
81   rv = nat44_ed_set_frame_queue_nelts (frame_queue_nelts);
82   REPLY_MACRO (VL_API_NAT44_ED_SET_FQ_OPTIONS_REPLY);
83 }
84
85 static void
86 vl_api_nat44_ed_show_fq_options_t_handler (
87   vl_api_nat44_ed_show_fq_options_t *mp)
88 {
89   snat_main_t *sm = &snat_main;
90   vl_api_nat44_ed_show_fq_options_reply_t *rmp;
91   int rv = 0;
92   /* clang-format off */
93   REPLY_MACRO2_ZERO (VL_API_NAT44_ED_SHOW_FQ_OPTIONS_REPLY,
94   ({
95     rmp->frame_queue_nelts = htonl (sm->frame_queue_nelts);
96   }));
97   /* clang-format on */
98 }
99
100 /* Old API calls hold back because of deprecation
101  * nat44_ed replacement should be used */
102
103 static void
104 vl_api_nat_set_workers_t_handler (vl_api_nat_set_workers_t * mp)
105 {
106   snat_main_t *sm = &snat_main;
107   vl_api_nat_set_workers_reply_t *rmp;
108   int rv = 0;
109   uword *bitmap = 0;
110   u64 mask;
111
112   mask = clib_net_to_host_u64 (mp->worker_mask);
113
114   if (sm->num_workers < 2)
115     {
116       rv = VNET_API_ERROR_FEATURE_DISABLED;
117       goto send_reply;
118     }
119
120   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask));
121   rv = snat_set_workers (bitmap);
122   clib_bitmap_free (bitmap);
123
124 send_reply:
125   REPLY_MACRO (VL_API_NAT_SET_WORKERS_REPLY);
126 }
127
128 static void
129 send_nat_worker_details (u32 worker_index, vl_api_registration_t * reg,
130                          u32 context)
131 {
132   vl_api_nat_worker_details_t *rmp;
133   snat_main_t *sm = &snat_main;
134   vlib_worker_thread_t *w =
135     vlib_worker_threads + worker_index + sm->first_worker_index;
136
137   rmp = vl_msg_api_alloc (sizeof (*rmp));
138   clib_memset (rmp, 0, sizeof (*rmp));
139   rmp->_vl_msg_id = ntohs (VL_API_NAT_WORKER_DETAILS + sm->msg_id_base);
140   rmp->context = context;
141   rmp->worker_index = htonl (worker_index);
142   rmp->lcore_id = htonl (w->cpu_id);
143   strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
144
145   vl_api_send_msg (reg, (u8 *) rmp);
146 }
147
148 static void
149 vl_api_nat_worker_dump_t_handler (vl_api_nat_worker_dump_t * mp)
150 {
151   vl_api_registration_t *reg;
152   snat_main_t *sm = &snat_main;
153   u32 *worker_index;
154
155   reg = vl_api_client_index_to_registration (mp->client_index);
156   if (!reg)
157     return;
158
159   vec_foreach (worker_index, sm->workers)
160     {
161       send_nat_worker_details (*worker_index, reg, mp->context);
162     }
163 }
164
165 static void
166 vl_api_nat44_set_session_limit_t_handler (vl_api_nat44_set_session_limit_t *
167                                           mp)
168 {
169   snat_main_t *sm = &snat_main;
170   vl_api_nat44_set_session_limit_reply_t *rmp;
171   int rv = 0;
172
173   rv = nat44_set_session_limit
174     (ntohl (mp->session_limit), ntohl (mp->vrf_id));
175
176   REPLY_MACRO (VL_API_NAT44_SET_SESSION_LIMIT_REPLY);
177 }
178
179 static void
180 vl_api_nat_ipfix_enable_disable_t_handler (vl_api_nat_ipfix_enable_disable_t *
181                                            mp)
182 {
183   snat_main_t *sm = &snat_main;
184   vl_api_nat_ipfix_enable_disable_reply_t *rmp;
185   int rv = 0;
186
187   rv = nat_ipfix_logging_enable_disable (mp->enable,
188                                          clib_host_to_net_u32
189                                          (mp->domain_id),
190                                          clib_host_to_net_u16 (mp->src_port));
191
192   REPLY_MACRO (VL_API_NAT_IPFIX_ENABLE_DISABLE_REPLY);
193 }
194
195 static void
196 vl_api_nat_set_timeouts_t_handler (vl_api_nat_set_timeouts_t * mp)
197 {
198   snat_main_t *sm = &snat_main;
199   vl_api_nat_set_timeouts_reply_t *rmp;
200   int rv = 0;
201
202   sm->timeouts.udp = ntohl (mp->udp);
203   sm->timeouts.tcp.established = ntohl (mp->tcp_established);
204   sm->timeouts.tcp.transitory = ntohl (mp->tcp_transitory);
205   sm->timeouts.icmp = ntohl (mp->icmp);
206
207   REPLY_MACRO (VL_API_NAT_SET_TIMEOUTS_REPLY);
208 }
209
210 static void
211 vl_api_nat_set_mss_clamping_t_handler (vl_api_nat_set_mss_clamping_t * mp)
212 {
213   snat_main_t *sm = &snat_main;
214   vl_api_nat_set_mss_clamping_reply_t *rmp;
215   int rv = 0;
216
217   if (mp->enable)
218     sm->mss_clamping = ntohs (mp->mss_value);
219   else
220     sm->mss_clamping = 0;
221
222   REPLY_MACRO (VL_API_NAT_SET_MSS_CLAMPING_REPLY);
223 }
224
225 static void
226 vl_api_nat_get_mss_clamping_t_handler (vl_api_nat_get_mss_clamping_t * mp)
227 {
228   snat_main_t *sm = &snat_main;
229   vl_api_nat_get_mss_clamping_reply_t *rmp;
230   int rv = 0;
231
232   REPLY_MACRO2 (VL_API_NAT_GET_MSS_CLAMPING_REPLY,
233   ({
234     rmp->enable = sm->mss_clamping ? 1 : 0;
235     rmp->mss_value = htons (sm->mss_clamping);
236   }))
237 }
238
239 static void
240   vl_api_nat44_add_del_address_range_t_handler
241   (vl_api_nat44_add_del_address_range_t * mp)
242 {
243   snat_main_t *sm = &snat_main;
244   vl_api_nat44_add_del_address_range_reply_t *rmp;
245   ip4_address_t this_addr;
246   u8 is_add, twice_nat;
247   u32 start_host_order, end_host_order;
248   u32 vrf_id;
249   int i, count;
250   int rv = 0;
251   u32 *tmp;
252
253   is_add = mp->is_add;
254   twice_nat = mp->flags & NAT_API_IS_TWICE_NAT;
255
256   tmp = (u32 *) mp->first_ip_address;
257   start_host_order = clib_host_to_net_u32 (tmp[0]);
258   tmp = (u32 *) mp->last_ip_address;
259   end_host_order = clib_host_to_net_u32 (tmp[0]);
260
261   count = (end_host_order - start_host_order) + 1;
262
263   vrf_id = clib_host_to_net_u32 (mp->vrf_id);
264
265   if (count > 1024)
266     nat_log_info ("%U - %U, %d addresses...",
267                   format_ip4_address, mp->first_ip_address,
268                   format_ip4_address, mp->last_ip_address, count);
269
270   memcpy (&this_addr.as_u8, mp->first_ip_address, 4);
271
272   for (i = 0; i < count; i++)
273     {
274       if (is_add)
275         {
276           rv = nat44_ed_add_address (&this_addr, vrf_id, twice_nat);
277         }
278       else
279         {
280           rv = nat44_ed_del_address (this_addr, twice_nat);
281         }
282
283       if (rv)
284         goto send_reply;
285
286       increment_v4_address (&this_addr);
287     }
288
289 send_reply:
290   REPLY_MACRO (VL_API_NAT44_ADD_DEL_ADDRESS_RANGE_REPLY);
291 }
292
293 static void
294 send_nat44_address_details (snat_address_t * a,
295                             vl_api_registration_t * reg, u32 context,
296                             u8 twice_nat)
297 {
298   vl_api_nat44_address_details_t *rmp;
299   snat_main_t *sm = &snat_main;
300
301   rmp = vl_msg_api_alloc (sizeof (*rmp));
302   clib_memset (rmp, 0, sizeof (*rmp));
303   rmp->_vl_msg_id = ntohs (VL_API_NAT44_ADDRESS_DETAILS + sm->msg_id_base);
304   clib_memcpy (rmp->ip_address, &(a->addr), 4);
305   if (a->fib_index != ~0)
306     {
307       fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP4);
308       rmp->vrf_id = ntohl (fib->ft_table_id);
309     }
310   else
311     rmp->vrf_id = ~0;
312   if (twice_nat)
313     rmp->flags |= NAT_API_IS_TWICE_NAT;
314   rmp->context = context;
315
316   vl_api_send_msg (reg, (u8 *) rmp);
317 }
318
319 static void
320 vl_api_nat44_address_dump_t_handler (vl_api_nat44_address_dump_t * mp)
321 {
322   vl_api_registration_t *reg;
323   snat_main_t *sm = &snat_main;
324   snat_address_t *a;
325
326   reg = vl_api_client_index_to_registration (mp->client_index);
327   if (!reg)
328     return;
329
330   vec_foreach (a, sm->addresses)
331     send_nat44_address_details (a, reg, mp->context, 0);
332   vec_foreach (a, sm->twice_nat_addresses)
333     send_nat44_address_details (a, reg, mp->context, 1);
334 }
335
336 static void
337   vl_api_nat44_interface_add_del_feature_t_handler
338   (vl_api_nat44_interface_add_del_feature_t * mp)
339 {
340   vl_api_nat44_interface_add_del_feature_reply_t *rmp;
341   snat_main_t *sm = &snat_main;
342   u32 sw_if_index;
343   u8 is_inside;
344   int rv = 0;
345
346   VALIDATE_SW_IF_INDEX (mp);
347
348   is_inside = mp->flags & NAT_API_IS_INSIDE;
349   sw_if_index = ntohl (mp->sw_if_index);
350
351   if (mp->is_add)
352     {
353       rv = nat44_ed_add_interface (sw_if_index, is_inside);
354     }
355   else
356     {
357       rv = nat44_ed_del_interface (sw_if_index, is_inside);
358     }
359
360   BAD_SW_IF_INDEX_LABEL;
361   REPLY_MACRO (VL_API_NAT44_INTERFACE_ADD_DEL_FEATURE_REPLY);
362 }
363
364 static void
365 send_nat44_interface_details (snat_interface_t * i,
366                               vl_api_registration_t * reg, u32 context)
367 {
368   vl_api_nat44_interface_details_t *rmp;
369   snat_main_t *sm = &snat_main;
370
371   rmp = vl_msg_api_alloc (sizeof (*rmp));
372   clib_memset (rmp, 0, sizeof (*rmp));
373   rmp->_vl_msg_id = ntohs (VL_API_NAT44_INTERFACE_DETAILS + sm->msg_id_base);
374   rmp->sw_if_index = ntohl (i->sw_if_index);
375
376   if (nat44_ed_is_interface_inside (i))
377     rmp->flags |= NAT_API_IS_INSIDE;
378   if (nat44_ed_is_interface_outside (i))
379     rmp->flags |= NAT_API_IS_OUTSIDE;
380
381   rmp->context = context;
382
383   vl_api_send_msg (reg, (u8 *) rmp);
384 }
385
386 static void
387 vl_api_nat44_interface_dump_t_handler (vl_api_nat44_interface_dump_t * mp)
388 {
389   vl_api_registration_t *reg;
390   snat_main_t *sm = &snat_main;
391   snat_interface_t *i;
392
393   reg = vl_api_client_index_to_registration (mp->client_index);
394   if (!reg)
395     return;
396
397   pool_foreach (i, sm->interfaces)
398     {
399       send_nat44_interface_details (i, reg, mp->context);
400     }
401 }
402
403 static void
404 vl_api_nat44_ed_add_del_output_interface_t_handler (
405   vl_api_nat44_ed_add_del_output_interface_t *mp)
406 {
407   vl_api_nat44_ed_add_del_output_interface_reply_t *rmp;
408   snat_main_t *sm = &snat_main;
409   int rv = 0;
410
411   VALIDATE_SW_IF_INDEX_END (mp);
412
413   if (mp->is_add)
414     {
415       rv = nat44_ed_add_output_interface (mp->sw_if_index);
416     }
417   else
418     {
419       rv = nat44_ed_del_output_interface (mp->sw_if_index);
420     }
421
422 bad_sw_if_index:
423   REPLY_MACRO_END (VL_API_NAT44_ED_ADD_DEL_OUTPUT_INTERFACE_REPLY);
424 }
425
426 #define vl_endianfun
427 #include <nat/nat44-ed/nat44_ed.api.h>
428 #undef vl_endianfun
429 static void
430 send_nat44_ed_output_interface_details (u32 index, vl_api_registration_t *rp,
431                                         u32 context)
432 {
433   snat_main_t *sm = &snat_main;
434   vl_api_nat44_ed_output_interface_details_t *rmp;
435   snat_interface_t *i =
436     pool_elt_at_index (sm->output_feature_interfaces, index);
437
438   /* Make sure every field is initiated (or don't skip the clib_memset()) */
439   REPLY_MACRO_DETAILS4 (
440     VL_API_NAT44_ED_OUTPUT_INTERFACE_DETAILS, rp, context, ({
441       rmp->sw_if_index = i->sw_if_index;
442
443       /* Endian hack until apigen registers _details
444        * endian functions */
445       vl_api_nat44_ed_output_interface_details_t_endian (rmp);
446       rmp->_vl_msg_id = htons (rmp->_vl_msg_id);
447       rmp->context = htonl (rmp->context);
448     }));
449 }
450
451 static void
452 vl_api_nat44_ed_output_interface_get_t_handler (
453   vl_api_nat44_ed_output_interface_get_t *mp)
454 {
455   vl_api_nat44_ed_output_interface_get_reply_t *rmp;
456   snat_main_t *sm = &snat_main;
457   i32 rv = 0;
458
459   if (pool_elts (sm->output_feature_interfaces) == 0)
460     {
461       REPLY_MACRO (VL_API_NAT44_ED_OUTPUT_INTERFACE_GET_REPLY);
462       return;
463     }
464
465   REPLY_AND_DETAILS_MACRO (
466     VL_API_NAT44_ED_OUTPUT_INTERFACE_GET_REPLY, sm->output_feature_interfaces,
467     ({ send_nat44_ed_output_interface_details (cursor, rp, mp->context); }));
468 }
469
470 static void
471   vl_api_nat44_add_del_static_mapping_t_handler
472   (vl_api_nat44_add_del_static_mapping_t * mp)
473 {
474   vl_api_nat44_add_del_static_mapping_reply_t *rmp;
475
476   snat_main_t *sm = &snat_main;
477   int rv = 0;
478
479   ip4_address_t l_addr, e_addr, pool_addr = { 0 };
480   u32 sw_if_index, flags = 0, vrf_id;
481   u16 l_port = 0, e_port = 0;
482   ip_protocol_t proto = 0;
483   u8 *tag = 0;
484
485   memcpy (&l_addr.as_u8, mp->local_ip_address, 4);
486
487   if (mp->flags & NAT_API_IS_ADDR_ONLY)
488     {
489       flags |= NAT_SM_FLAG_ADDR_ONLY;
490     }
491   else
492     {
493       l_port = mp->local_port;
494       e_port = mp->external_port;
495       proto = mp->protocol;
496     }
497
498   if (mp->flags & NAT_API_IS_TWICE_NAT)
499     {
500       flags |= NAT_SM_FLAG_TWICE_NAT;
501     }
502
503   if (mp->flags & NAT_API_IS_SELF_TWICE_NAT)
504     {
505       flags |= NAT_SM_FLAG_SELF_TWICE_NAT;
506     }
507
508   if (mp->flags & NAT_API_IS_OUT2IN_ONLY)
509     {
510       flags |= NAT_SM_FLAG_OUT2IN_ONLY;
511     }
512
513   sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
514   if (sw_if_index != ~0)
515     {
516       flags |= NAT_SM_FLAG_SWITCH_ADDRESS;
517     }
518   else
519     {
520       memcpy (&e_addr.as_u8, mp->external_ip_address, 4);
521     }
522
523   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
524
525   if (mp->is_add)
526     {
527       mp->tag[sizeof (mp->tag) - 1] = 0;
528       tag = format (0, "%s", mp->tag);
529       vec_terminate_c_string (tag);
530
531       rv = nat44_ed_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
532                                         vrf_id, sw_if_index, flags, pool_addr,
533                                         tag);
534       vec_free (tag);
535     }
536   else
537     {
538       rv = nat44_ed_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
539                                         vrf_id, sw_if_index, flags);
540     }
541   REPLY_MACRO (VL_API_NAT44_ADD_DEL_STATIC_MAPPING_REPLY);
542 }
543
544 static void
545   vl_api_nat44_add_del_static_mapping_v2_t_handler
546   (vl_api_nat44_add_del_static_mapping_v2_t * mp)
547 {
548   vl_api_nat44_add_del_static_mapping_v2_reply_t *rmp;
549
550   snat_main_t *sm = &snat_main;
551   int rv = 0;
552
553   ip4_address_t l_addr, e_addr, pool_addr;
554   u32 sw_if_index, flags = 0, vrf_id;
555   u16 l_port = 0, e_port = 0;
556   ip_protocol_t proto;
557   u8 *tag = 0;
558
559   memcpy (&l_addr.as_u8, mp->local_ip_address, 4);
560   memcpy (&pool_addr.as_u8, mp->pool_ip_address, 4);
561
562   if (pool_addr.as_u32 != 0)
563     {
564       flags |= NAT_SM_FLAG_EXACT_ADDRESS;
565     }
566
567   if (mp->flags & NAT_API_IS_ADDR_ONLY)
568     {
569       flags |= NAT_SM_FLAG_ADDR_ONLY;
570     }
571   else
572     {
573       l_port = mp->local_port;
574       e_port = mp->external_port;
575     }
576
577   if (mp->flags & NAT_API_IS_TWICE_NAT)
578     {
579       flags |= NAT_SM_FLAG_TWICE_NAT;
580     }
581
582   if (mp->flags & NAT_API_IS_SELF_TWICE_NAT)
583     {
584       flags |= NAT_SM_FLAG_SELF_TWICE_NAT;
585     }
586
587   if (mp->flags & NAT_API_IS_OUT2IN_ONLY)
588     {
589       flags |= NAT_SM_FLAG_OUT2IN_ONLY;
590     }
591
592   sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
593   if (sw_if_index != ~0)
594     {
595       flags |= NAT_SM_FLAG_SWITCH_ADDRESS;
596     }
597   else
598     {
599       memcpy (&e_addr.as_u8, mp->external_ip_address, 4);
600     }
601
602   proto = mp->protocol;
603   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
604
605   if (mp->is_add)
606     {
607       mp->tag[sizeof (mp->tag) - 1] = 0;
608       tag = format (0, "%s", mp->tag);
609       vec_terminate_c_string (tag);
610
611       rv = nat44_ed_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
612                                         vrf_id, sw_if_index, flags, pool_addr,
613                                         tag);
614       vec_free (tag);
615     }
616   else
617     {
618       rv = nat44_ed_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
619                                         vrf_id, sw_if_index, flags);
620     }
621   REPLY_MACRO (VL_API_NAT44_ADD_DEL_STATIC_MAPPING_V2_REPLY);
622 }
623
624 static void
625 send_nat44_static_mapping_details (snat_static_mapping_t * m,
626                                    vl_api_registration_t * reg, u32 context)
627 {
628   vl_api_nat44_static_mapping_details_t *rmp;
629   snat_main_t *sm = &snat_main;
630   u32 len = sizeof (*rmp);
631
632   rmp = vl_msg_api_alloc (len);
633   clib_memset (rmp, 0, len);
634   rmp->_vl_msg_id =
635     ntohs (VL_API_NAT44_STATIC_MAPPING_DETAILS + sm->msg_id_base);
636
637   clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4);
638   clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4);
639   rmp->external_sw_if_index = ~0;
640   rmp->vrf_id = htonl (m->vrf_id);
641   rmp->context = context;
642
643   // convert these in new api
644
645   if (is_sm_self_twice_nat (m->flags))
646     {
647       rmp->flags |= NAT_API_IS_SELF_TWICE_NAT;
648     }
649
650   if (is_sm_out2in_only (m->flags))
651     {
652       rmp->flags |= NAT_API_IS_OUT2IN_ONLY;
653     }
654
655   if (is_sm_twice_nat (m->flags))
656     {
657       rmp->flags |= NAT_API_IS_TWICE_NAT;
658     }
659
660   if (is_sm_addr_only (m->flags))
661     {
662       rmp->flags |= NAT_API_IS_ADDR_ONLY;
663     }
664   else
665     {
666       rmp->protocol = m->proto;
667       rmp->external_port = m->external_port;
668       rmp->local_port = m->local_port;
669     }
670
671   if (m->tag)
672     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
673
674   vl_api_send_msg (reg, (u8 *) rmp);
675 }
676
677 static void
678 send_nat44_static_map_resolve_details (snat_static_mapping_resolve_t *m,
679                                        vl_api_registration_t *reg, u32 context)
680 {
681   vl_api_nat44_static_mapping_details_t *rmp;
682   snat_main_t *sm = &snat_main;
683
684   rmp = vl_msg_api_alloc (sizeof (*rmp));
685   clib_memset (rmp, 0, sizeof (*rmp));
686   rmp->_vl_msg_id =
687     ntohs (VL_API_NAT44_STATIC_MAPPING_DETAILS + sm->msg_id_base);
688   clib_memcpy (rmp->local_ip_address, &(m->l_addr), 4);
689   rmp->external_sw_if_index = htonl (m->sw_if_index);
690   rmp->vrf_id = htonl (m->vrf_id);
691   rmp->context = context;
692
693   if (is_sm_twice_nat (m->flags))
694     {
695       rmp->flags |= NAT_API_IS_TWICE_NAT;
696     }
697
698   if (is_sm_addr_only (m->flags))
699     {
700       rmp->flags |= NAT_API_IS_ADDR_ONLY;
701     }
702   else
703     {
704       rmp->protocol = m->proto;
705       rmp->external_port = m->e_port;
706       rmp->local_port = m->l_port;
707     }
708
709   if (m->tag)
710     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
711
712   vl_api_send_msg (reg, (u8 *) rmp);
713 }
714
715 static void
716 vl_api_nat44_static_mapping_dump_t_handler (vl_api_nat44_static_mapping_dump_t
717                                             * mp)
718 {
719   vl_api_registration_t *reg;
720   snat_main_t *sm = &snat_main;
721   snat_static_mapping_t *m;
722   snat_static_mapping_resolve_t *rp;
723   int j;
724
725   reg = vl_api_client_index_to_registration (mp->client_index);
726   if (!reg)
727     return;
728
729   pool_foreach (m, sm->static_mappings)
730    {
731      if (!is_sm_identity_nat (m->flags) && !is_sm_lb (m->flags))
732        send_nat44_static_mapping_details (m, reg, mp->context);
733   }
734
735   for (j = 0; j < vec_len (sm->sm_to_resolve); j++)
736     {
737       rp = sm->sm_to_resolve + j;
738       if (!is_sm_identity_nat (rp->flags))
739         send_nat44_static_map_resolve_details (rp, reg, mp->context);
740     }
741 }
742
743 static void
744   vl_api_nat44_add_del_identity_mapping_t_handler
745   (vl_api_nat44_add_del_identity_mapping_t * mp)
746 {
747   vl_api_nat44_add_del_identity_mapping_reply_t *rmp;
748
749   snat_main_t *sm = &snat_main;
750   int rv = 0;
751
752   ip4_address_t addr, pool_addr = { 0 };
753   u32 sw_if_index, flags, vrf_id;
754   ip_protocol_t proto = 0;
755   u16 port = 0;
756   u8 *tag = 0;
757
758   flags = NAT_SM_FLAG_IDENTITY_NAT;
759
760   if (mp->flags & NAT_API_IS_ADDR_ONLY)
761     {
762       flags |= NAT_SM_FLAG_ADDR_ONLY;
763     }
764   else
765     {
766       port = mp->port;
767       proto = mp->protocol;
768     }
769
770   sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
771   if (sw_if_index != ~0)
772     {
773       flags |= NAT_SM_FLAG_SWITCH_ADDRESS;
774     }
775   else
776     {
777       memcpy (&addr.as_u8, mp->ip_address, 4);
778     }
779
780   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
781
782   if (mp->is_add)
783     {
784       mp->tag[sizeof (mp->tag) - 1] = 0;
785       tag = format (0, "%s", mp->tag);
786       vec_terminate_c_string (tag);
787
788       rv = nat44_ed_add_static_mapping (addr, addr, port, port, proto, vrf_id,
789                                         sw_if_index, flags, pool_addr, tag);
790       vec_free (tag);
791     }
792   else
793     {
794       rv = nat44_ed_del_static_mapping (addr, addr, port, port, proto, vrf_id,
795                                         sw_if_index, flags);
796     }
797   REPLY_MACRO (VL_API_NAT44_ADD_DEL_IDENTITY_MAPPING_REPLY);
798 }
799
800 static void
801 send_nat44_identity_mapping_details (snat_static_mapping_t * m, int index,
802                                      vl_api_registration_t * reg, u32 context)
803 {
804   vl_api_nat44_identity_mapping_details_t *rmp;
805   snat_main_t *sm = &snat_main;
806   nat44_lb_addr_port_t *local = pool_elt_at_index (m->locals, index);
807
808   rmp = vl_msg_api_alloc (sizeof (*rmp));
809   clib_memset (rmp, 0, sizeof (*rmp));
810   rmp->_vl_msg_id =
811     ntohs (VL_API_NAT44_IDENTITY_MAPPING_DETAILS + sm->msg_id_base);
812
813   if (is_sm_addr_only (m->flags))
814     rmp->flags |= NAT_API_IS_ADDR_ONLY;
815
816   clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
817   rmp->port = m->local_port;
818   rmp->sw_if_index = ~0;
819   rmp->vrf_id = htonl (local->vrf_id);
820   rmp->protocol = m->proto;
821   rmp->context = context;
822   if (m->tag)
823     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
824
825   vl_api_send_msg (reg, (u8 *) rmp);
826 }
827
828 static void
829 send_nat44_identity_map_resolve_details (snat_static_mapping_resolve_t *m,
830                                          vl_api_registration_t *reg,
831                                          u32 context)
832 {
833   vl_api_nat44_identity_mapping_details_t *rmp;
834   snat_main_t *sm = &snat_main;
835
836   rmp = vl_msg_api_alloc (sizeof (*rmp));
837   clib_memset (rmp, 0, sizeof (*rmp));
838   rmp->_vl_msg_id =
839     ntohs (VL_API_NAT44_IDENTITY_MAPPING_DETAILS + sm->msg_id_base);
840
841   if (is_sm_addr_only (m->flags))
842     rmp->flags = (vl_api_nat_config_flags_t) NAT_API_IS_ADDR_ONLY;
843
844   rmp->port = m->l_port;
845   rmp->sw_if_index = htonl (m->sw_if_index);
846   rmp->vrf_id = htonl (m->vrf_id);
847   rmp->protocol = m->proto;
848   rmp->context = context;
849   if (m->tag)
850     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
851
852   vl_api_send_msg (reg, (u8 *) rmp);
853 }
854
855 static void
856   vl_api_nat44_identity_mapping_dump_t_handler
857   (vl_api_nat44_identity_mapping_dump_t * mp)
858 {
859   vl_api_registration_t *reg;
860   snat_main_t *sm = &snat_main;
861   snat_static_mapping_t *m;
862   snat_static_mapping_resolve_t *rp;
863   int j;
864
865   reg = vl_api_client_index_to_registration (mp->client_index);
866   if (!reg)
867     return;
868
869   pool_foreach (m, sm->static_mappings)
870     {
871       if (is_sm_identity_nat (m->flags) && !is_sm_lb (m->flags))
872         {
873           pool_foreach_index (j, m->locals)
874             {
875               send_nat44_identity_mapping_details (m, j, reg, mp->context);
876             }
877         }
878     }
879
880   for (j = 0; j < vec_len (sm->sm_to_resolve); j++)
881     {
882       rp = sm->sm_to_resolve + j;
883       if (is_sm_identity_nat (rp->flags))
884         send_nat44_identity_map_resolve_details (rp, reg, mp->context);
885     }
886 }
887
888 static void
889   vl_api_nat44_add_del_interface_addr_t_handler
890   (vl_api_nat44_add_del_interface_addr_t * mp)
891 {
892   snat_main_t *sm = &snat_main;
893   vl_api_nat44_add_del_interface_addr_reply_t *rmp;
894   u32 sw_if_index = ntohl (mp->sw_if_index);
895   u8 twice_nat;
896   int rv = 0;
897
898   VALIDATE_SW_IF_INDEX (mp);
899
900   twice_nat = mp->flags & NAT_API_IS_TWICE_NAT;
901
902   if (mp->is_add)
903     {
904       rv = nat44_ed_add_interface_address (sw_if_index, twice_nat);
905     }
906   else
907     {
908       rv = nat44_ed_del_interface_address (sw_if_index, twice_nat);
909     }
910
911   BAD_SW_IF_INDEX_LABEL;
912
913   REPLY_MACRO (VL_API_NAT44_ADD_DEL_INTERFACE_ADDR_REPLY);
914 }
915
916 static void
917 send_nat44_interface_addr_details (u32 sw_if_index,
918                                    vl_api_registration_t * reg, u32 context,
919                                    u8 twice_nat)
920 {
921   vl_api_nat44_interface_addr_details_t *rmp;
922   snat_main_t *sm = &snat_main;
923
924   rmp = vl_msg_api_alloc (sizeof (*rmp));
925   clib_memset (rmp, 0, sizeof (*rmp));
926   rmp->_vl_msg_id =
927     ntohs (VL_API_NAT44_INTERFACE_ADDR_DETAILS + sm->msg_id_base);
928   rmp->sw_if_index = ntohl (sw_if_index);
929
930   if (twice_nat)
931     rmp->flags = (vl_api_nat_config_flags_t) NAT_API_IS_TWICE_NAT;
932   rmp->context = context;
933
934   vl_api_send_msg (reg, (u8 *) rmp);
935 }
936
937 static void
938 vl_api_nat44_interface_addr_dump_t_handler (vl_api_nat44_interface_addr_dump_t
939                                             * mp)
940 {
941   snat_main_t *sm = &snat_main;
942   vl_api_registration_t *reg;
943   snat_address_resolve_t *ap;
944
945   reg = vl_api_client_index_to_registration (mp->client_index);
946   if (!reg)
947     return;
948
949   vec_foreach (ap, sm->addr_to_resolve)
950     {
951       send_nat44_interface_addr_details (ap->sw_if_index, reg, mp->context,
952                                          ap->is_twice_nat);
953     }
954 }
955
956 static nat44_lb_addr_port_t *
957 unformat_nat44_lb_addr_port (vl_api_nat44_lb_addr_port_t *addr_port_pairs,
958                              u32 addr_port_pair_num)
959 {
960   u8 i;
961   nat44_lb_addr_port_t *lb_addr_port_pairs = 0, lb_addr_port;
962   vl_api_nat44_lb_addr_port_t *ap;
963
964   for (i = 0; i < addr_port_pair_num; i++)
965     {
966       ap = &addr_port_pairs[i];
967       clib_memset (&lb_addr_port, 0, sizeof (lb_addr_port));
968       clib_memcpy (&lb_addr_port.addr, ap->addr, 4);
969       lb_addr_port.port = ap->port;
970       lb_addr_port.probability = ap->probability;
971       lb_addr_port.vrf_id = clib_net_to_host_u32 (ap->vrf_id);
972       vec_add1 (lb_addr_port_pairs, lb_addr_port);
973     }
974
975   return lb_addr_port_pairs;
976 }
977
978 static void
979 vl_api_nat44_add_del_lb_static_mapping_t_handler (
980   vl_api_nat44_add_del_lb_static_mapping_t *mp)
981 {
982   snat_main_t *sm = &snat_main;
983   vl_api_nat44_add_del_lb_static_mapping_reply_t *rmp;
984   nat44_lb_addr_port_t *locals = 0;
985   ip4_address_t e_addr;
986   ip_protocol_t proto;
987   u32 flags = 0;
988   u8 *tag = 0;
989   int rv = 0;
990
991   locals = unformat_nat44_lb_addr_port (mp->locals,
992                                         clib_net_to_host_u32 (mp->local_num));
993   clib_memcpy (&e_addr, mp->external_addr, 4);
994   proto = mp->protocol;
995
996   if (mp->flags & NAT_API_IS_TWICE_NAT)
997     {
998       flags |= NAT_SM_FLAG_TWICE_NAT;
999     }
1000   else if (mp->flags & NAT_API_IS_SELF_TWICE_NAT)
1001     {
1002       flags |= NAT_SM_FLAG_SELF_TWICE_NAT;
1003     }
1004
1005   if (mp->flags & NAT_API_IS_OUT2IN_ONLY)
1006     {
1007       flags |= NAT_SM_FLAG_OUT2IN_ONLY;
1008     }
1009
1010   if (mp->is_add)
1011     {
1012       mp->tag[sizeof (mp->tag) - 1] = 0;
1013       tag = format (0, "%s", mp->tag);
1014       vec_terminate_c_string (tag);
1015
1016       rv = nat44_ed_add_lb_static_mapping (
1017         e_addr, mp->external_port, proto, locals, flags, tag,
1018         clib_net_to_host_u32 (mp->affinity));
1019     }
1020   else
1021     {
1022       rv = nat44_ed_del_lb_static_mapping (e_addr, mp->external_port, proto,
1023                                            flags);
1024     }
1025
1026   vec_free (locals);
1027   vec_free (tag);
1028   REPLY_MACRO (VL_API_NAT44_ADD_DEL_LB_STATIC_MAPPING_REPLY);
1029 }
1030
1031 static void
1032 vl_api_nat44_lb_static_mapping_add_del_local_t_handler (
1033   vl_api_nat44_lb_static_mapping_add_del_local_t *mp)
1034 {
1035   snat_main_t *sm = &snat_main;
1036   vl_api_nat44_lb_static_mapping_add_del_local_reply_t *rmp;
1037   int rv = 0;
1038   ip4_address_t e_addr, l_addr;
1039   ip_protocol_t proto;
1040
1041   clib_memcpy (&e_addr, mp->external_addr, 4);
1042   clib_memcpy (&l_addr, mp->local.addr, 4);
1043   proto = mp->protocol;
1044
1045   rv = nat44_ed_add_del_lb_static_mapping_local (
1046     e_addr, mp->external_port, l_addr, mp->local.port, proto,
1047     clib_net_to_host_u32 (mp->local.vrf_id), mp->local.probability,
1048     mp->is_add);
1049
1050   REPLY_MACRO (VL_API_NAT44_LB_STATIC_MAPPING_ADD_DEL_LOCAL_REPLY);
1051 }
1052
1053 static void
1054 send_nat44_lb_static_mapping_details (snat_static_mapping_t *m,
1055                                       vl_api_registration_t *reg, u32 context)
1056 {
1057   vl_api_nat44_lb_static_mapping_details_t *rmp;
1058   snat_main_t *sm = &snat_main;
1059   nat44_lb_addr_port_t *ap;
1060   vl_api_nat44_lb_addr_port_t *locals;
1061   u32 local_num = 0;
1062
1063   rmp = vl_msg_api_alloc (
1064     sizeof (*rmp) + (pool_elts (m->locals) * sizeof (nat44_lb_addr_port_t)));
1065
1066   clib_memset (rmp, 0, sizeof (*rmp));
1067   rmp->_vl_msg_id =
1068     ntohs (VL_API_NAT44_LB_STATIC_MAPPING_DETAILS + sm->msg_id_base);
1069
1070   clib_memcpy (rmp->external_addr, &(m->external_addr), 4);
1071   rmp->external_port = m->external_port;
1072   rmp->protocol = m->proto;
1073   rmp->context = context;
1074
1075   if (is_sm_self_twice_nat (m->flags))
1076     {
1077       rmp->flags |= NAT_API_IS_SELF_TWICE_NAT;
1078     }
1079
1080   if (is_sm_out2in_only (m->flags))
1081     {
1082       rmp->flags |= NAT_API_IS_OUT2IN_ONLY;
1083     }
1084
1085   if (is_sm_twice_nat (m->flags))
1086     {
1087       rmp->flags |= NAT_API_IS_TWICE_NAT;
1088     }
1089
1090   if (m->tag)
1091     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
1092
1093   locals = (vl_api_nat44_lb_addr_port_t *) rmp->locals;
1094   pool_foreach (ap, m->locals)
1095     {
1096       clib_memcpy (locals->addr, &(ap->addr), 4);
1097       locals->port = ap->port;
1098       locals->probability = ap->probability;
1099       locals->vrf_id = ntohl (ap->vrf_id);
1100       locals++;
1101       local_num++;
1102     }
1103   rmp->local_num = ntohl (local_num);
1104
1105   vl_api_send_msg (reg, (u8 *) rmp);
1106 }
1107
1108 static void
1109 vl_api_nat44_lb_static_mapping_dump_t_handler (
1110   vl_api_nat44_lb_static_mapping_dump_t *mp)
1111 {
1112   vl_api_registration_t *reg;
1113   snat_main_t *sm = &snat_main;
1114   snat_static_mapping_t *m;
1115
1116   reg = vl_api_client_index_to_registration (mp->client_index);
1117   if (!reg)
1118     return;
1119
1120   pool_foreach (m, sm->static_mappings)
1121     {
1122       if (is_sm_lb (m->flags))
1123         send_nat44_lb_static_mapping_details (m, reg, mp->context);
1124     }
1125 }
1126
1127 static void
1128 vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t *mp)
1129 {
1130   snat_main_t *sm = &snat_main;
1131   vl_api_nat44_del_session_reply_t *rmp;
1132   ip4_address_t addr, eh_addr;
1133   u16 port, eh_port;
1134   u32 vrf_id;
1135   int rv = 0;
1136   u8 is_in;
1137
1138   memcpy (&addr.as_u8, mp->address, 4);
1139   port = mp->port;
1140   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
1141   memcpy (&eh_addr.as_u8, mp->ext_host_address, 4);
1142   eh_port = mp->ext_host_port;
1143
1144   is_in = mp->flags & NAT_API_IS_INSIDE;
1145
1146   rv = nat44_ed_del_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol,
1147                              vrf_id, is_in);
1148
1149   REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY);
1150 }
1151
1152 static void
1153 vl_api_nat44_forwarding_enable_disable_t_handler (
1154   vl_api_nat44_forwarding_enable_disable_t *mp)
1155 {
1156   vl_api_nat44_forwarding_enable_disable_reply_t *rmp;
1157   snat_main_t *sm = &snat_main;
1158   int rv = 0;
1159   nat44_ed_forwarding_enable_disable (mp->enable);
1160   REPLY_MACRO (VL_API_NAT44_FORWARDING_ENABLE_DISABLE_REPLY);
1161 }
1162
1163 static void
1164 vl_api_nat44_show_running_config_t_handler (
1165   vl_api_nat44_show_running_config_t *mp)
1166 {
1167   vl_api_nat44_show_running_config_reply_t *rmp;
1168   snat_main_t *sm = &snat_main;
1169   nat44_config_t *rc = &sm->rconfig;
1170   int rv = 0;
1171
1172   REPLY_MACRO2_ZERO (
1173     VL_API_NAT44_SHOW_RUNNING_CONFIG_REPLY, ({
1174       rmp->inside_vrf = htonl (rc->inside_vrf);
1175       rmp->outside_vrf = htonl (rc->outside_vrf);
1176
1177       rmp->sessions = htonl (rc->sessions);
1178       rmp->translation_buckets = htonl (sm->translation_buckets);
1179
1180       // OBSOLETE
1181       rmp->users = 0;
1182       rmp->user_buckets = 0;
1183       rmp->user_sessions = 0;
1184
1185       rmp->timeouts.udp = htonl (sm->timeouts.udp);
1186       rmp->timeouts.tcp_established = htonl (sm->timeouts.tcp.established);
1187       rmp->timeouts.tcp_transitory = htonl (sm->timeouts.tcp.transitory);
1188       rmp->timeouts.icmp = htonl (sm->timeouts.icmp);
1189
1190       rmp->forwarding_enabled = sm->forwarding_enabled == 1;
1191       // consider how to split functionality between subplugins
1192       rmp->ipfix_logging_enabled = nat_ipfix_logging_enabled ();
1193       rmp->flags |= NAT44_IS_ENDPOINT_DEPENDENT;
1194     }));
1195 }
1196
1197 static void
1198 vl_api_nat44_ed_add_del_vrf_table_t_handler (
1199   vl_api_nat44_ed_add_del_vrf_table_t *mp)
1200 {
1201   snat_main_t *sm = &snat_main;
1202   vl_api_nat44_ed_add_del_vrf_table_reply_t *rmp;
1203   int rv = nat44_ed_add_del_vrf_table (clib_net_to_host_u32 (mp->table_vrf_id),
1204                                        mp->is_add);
1205   REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_TABLE_REPLY);
1206 }
1207
1208 static void
1209 vl_api_nat44_ed_add_del_vrf_route_t_handler (
1210   vl_api_nat44_ed_add_del_vrf_route_t *mp)
1211 {
1212   snat_main_t *sm = &snat_main;
1213   vl_api_nat44_ed_add_del_vrf_route_reply_t *rmp;
1214   int rv =
1215     nat44_ed_add_del_vrf_route (clib_net_to_host_u32 (mp->table_vrf_id),
1216                                 clib_net_to_host_u32 (mp->vrf_id), mp->is_add);
1217   REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_ROUTE_REPLY);
1218 }
1219
1220 static void
1221 nat44_ed_vrf_tables_send_details (vl_api_registration_t *rp, u32 context,
1222                                   vrf_table_t *t)
1223 {
1224   snat_main_t *sm = &snat_main;
1225   vl_api_nat44_ed_vrf_tables_details_t *mp;
1226
1227   u32 *vrf_ids = 0;
1228   vrf_route_t *r;
1229
1230   mp = vl_msg_api_alloc_zero (sizeof (*mp) +
1231                               sizeof (mp->vrf_ids[0]) * vec_len (t->routes));
1232   mp->_vl_msg_id =
1233     ntohs (VL_API_NAT44_ED_VRF_TABLES_DETAILS + sm->msg_id_base);
1234   mp->context = context;
1235   mp->n_vrf_ids = clib_host_to_net_u32 (vec_len (t->routes));
1236
1237   pool_foreach (r, t->routes)
1238     {
1239       vec_add1 (vrf_ids, r->vrf_id);
1240     }
1241
1242   // copy the records
1243   clib_memcpy (mp->vrf_ids, vrf_ids,
1244                sizeof (mp->vrf_ids[0]) * vec_len (t->routes));
1245
1246   vec_free (vrf_ids);
1247
1248   // send the message
1249   vl_api_send_msg (rp, (u8 *) mp);
1250 }
1251
1252 static void
1253 nat44_ed_vrf_tables_send_details_v2 (vl_api_registration_t *rp, u32 context,
1254                                      vrf_table_t *t)
1255 {
1256   snat_main_t *sm = &snat_main;
1257   vl_api_nat44_ed_vrf_tables_v2_details_t *mp;
1258
1259   u32 *vrf_ids = 0;
1260   vrf_route_t *r;
1261
1262   mp = vl_msg_api_alloc_zero (sizeof (*mp) +
1263                               sizeof (mp->vrf_ids[0]) * vec_len (t->routes));
1264   mp->_vl_msg_id = clib_net_to_host_u16 (VL_API_NAT44_ED_VRF_TABLES_DETAILS +
1265                                          sm->msg_id_base);
1266   mp->context = context;
1267   mp->n_vrf_ids = clib_net_to_host_u32 (vec_len (t->routes));
1268   mp->table_vrf_id = clib_net_to_host_u32 (t->table_vrf_id);
1269   pool_foreach (r, t->routes)
1270     {
1271       vec_add1 (vrf_ids, clib_net_to_host_u32 (r->vrf_id));
1272     }
1273
1274   // copy the records
1275   clib_memcpy (mp->vrf_ids, vrf_ids,
1276                sizeof (mp->vrf_ids[0]) * vec_len (t->routes));
1277
1278   vec_free (vrf_ids);
1279
1280   // send the message
1281   vl_api_send_msg (rp, (u8 *) mp);
1282 }
1283
1284 static void
1285 vl_api_nat44_ed_vrf_tables_dump_t_handler (
1286   vl_api_nat44_ed_vrf_tables_dump_t *mp)
1287 {
1288   snat_main_t *sm = &snat_main;
1289   vl_api_registration_t *rp;
1290   vrf_table_t *t;
1291
1292   rp = vl_api_client_index_to_registration (mp->client_index);
1293   if (rp == 0)
1294     return;
1295
1296   pool_foreach (t, sm->vrf_tables)
1297     {
1298       nat44_ed_vrf_tables_send_details (rp, mp->context, t);
1299     }
1300 }
1301
1302 static void
1303 vl_api_nat44_ed_vrf_tables_v2_dump_t_handler (
1304   vl_api_nat44_ed_vrf_tables_v2_dump_t *mp)
1305 {
1306   snat_main_t *sm = &snat_main;
1307   vl_api_registration_t *rp;
1308   vrf_table_t *t;
1309
1310   rp = vl_api_client_index_to_registration (mp->client_index);
1311   if (rp == 0)
1312     return;
1313
1314   pool_foreach (t, sm->vrf_tables)
1315     {
1316       nat44_ed_vrf_tables_send_details_v2 (rp, mp->context, t);
1317     }
1318 }
1319
1320 /* user (internal host) key */
1321 typedef struct
1322 {
1323   union
1324   {
1325     struct
1326     {
1327       ip4_address_t addr;
1328       u32 fib_index;
1329     };
1330     u64 as_u64;
1331   };
1332 } snat_user_key_t;
1333
1334 typedef struct
1335 {
1336   ip4_address_t addr;
1337   u32 fib_index;
1338   u32 nsessions;
1339   u32 nstaticsessions;
1340 } snat_user_t;
1341
1342 typedef struct
1343 {
1344   u32 user_buckets;
1345   snat_user_t *users;
1346   clib_bihash_8_8_t user_hash;
1347 } user_create_helper_t;
1348
1349 static void
1350 send_nat44_user_details (snat_user_t *u, vl_api_registration_t *reg,
1351                          u32 context)
1352 {
1353   vl_api_nat44_user_details_t *rmp;
1354   snat_main_t *sm = &snat_main;
1355   ip4_main_t *im = &ip4_main;
1356
1357   rmp = vl_msg_api_alloc (sizeof (*rmp));
1358   clib_memset (rmp, 0, sizeof (*rmp));
1359   rmp->_vl_msg_id = ntohs (VL_API_NAT44_USER_DETAILS + sm->msg_id_base);
1360
1361   if (!pool_is_free_index (im->fibs, u->fib_index))
1362     {
1363       fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
1364       rmp->vrf_id = ntohl (fib->ft_table_id);
1365     }
1366
1367   clib_memcpy (rmp->ip_address, &(u->addr), 4);
1368   rmp->nsessions = ntohl (u->nsessions);
1369   rmp->nstaticsessions = ntohl (u->nstaticsessions);
1370   rmp->context = context;
1371
1372   vl_api_send_msg (reg, (u8 *) rmp);
1373 }
1374
1375 static void
1376 nat_ed_user_create_helper (user_create_helper_t *uch, snat_session_t *s)
1377 {
1378   snat_user_key_t k;
1379   k.addr = s->in2out.addr;
1380   k.fib_index = s->in2out.fib_index;
1381   clib_bihash_kv_8_8_t key, value;
1382   key.key = k.as_u64;
1383   snat_user_t *u;
1384
1385   if (clib_bihash_search_8_8 (&uch->user_hash, &key, &value))
1386     {
1387       pool_get (uch->users, u);
1388       u->addr = k.addr;
1389       u->fib_index = k.fib_index;
1390       u->nsessions = 0;
1391       u->nstaticsessions = 0;
1392       key.value = u - uch->users;
1393       clib_bihash_add_del_8_8 (&uch->user_hash, &key, 1);
1394     }
1395   else
1396     {
1397       u = pool_elt_at_index (uch->users, value.value);
1398     }
1399   if (nat44_ed_is_session_static (s))
1400     {
1401       ++u->nstaticsessions;
1402     }
1403   else
1404     {
1405       ++u->nsessions;
1406     }
1407 }
1408
1409 u8 *
1410 format_user_kvp (u8 *s, va_list *args)
1411 {
1412   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
1413   snat_user_key_t k;
1414   k.as_u64 = v->key;
1415   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
1416               k.fib_index, v->value);
1417   return s;
1418 }
1419
1420 static void
1421 nat_ed_users_create (snat_main_per_thread_data_t *tsm,
1422                      user_create_helper_t *uch)
1423 {
1424   snat_session_t *s;
1425   clib_bihash_init_8_8 (&uch->user_hash, "users", uch->user_buckets, 0);
1426   clib_bihash_set_kvp_format_fn_8_8 (&uch->user_hash, format_user_kvp);
1427   pool_foreach (s, tsm->sessions)
1428     {
1429       nat_ed_user_create_helper (uch, s);
1430     }
1431 }
1432
1433 static void
1434 nat_ed_users_destroy (user_create_helper_t *uch)
1435 {
1436   pool_free (uch->users);
1437   clib_bihash_free_8_8 (&uch->user_hash);
1438 }
1439
1440 static void
1441 vl_api_nat44_user_dump_t_handler (vl_api_nat44_user_dump_t * mp)
1442 {
1443   user_create_helper_t uch;
1444   vl_api_registration_t *reg;
1445   snat_main_t *sm = &snat_main;
1446   snat_main_per_thread_data_t *tsm;
1447   snat_user_t *u;
1448
1449   clib_memset (&uch, 0, sizeof (uch));
1450
1451   uch.user_buckets = nat_calc_bihash_buckets (1024);
1452
1453   reg = vl_api_client_index_to_registration (mp->client_index);
1454   if (!reg)
1455     return;
1456
1457   vec_foreach (tsm, sm->per_thread_data)
1458     {
1459       nat_ed_users_create (tsm, &uch);
1460       pool_foreach (u, uch.users)
1461         {
1462           send_nat44_user_details (u, reg, mp->context);
1463         }
1464       nat_ed_users_destroy (&uch);
1465     }
1466 }
1467
1468 static void
1469 send_nat44_user_session_details (snat_session_t * s,
1470                                  vl_api_registration_t * reg, u32 context)
1471 {
1472   vl_api_nat44_user_session_details_t *rmp;
1473   snat_main_t *sm = &snat_main;
1474
1475   rmp = vl_msg_api_alloc (sizeof (*rmp));
1476   clib_memset (rmp, 0, sizeof (*rmp));
1477   rmp->_vl_msg_id =
1478     ntohs (VL_API_NAT44_USER_SESSION_DETAILS + sm->msg_id_base);
1479   clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
1480   clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
1481
1482   if (nat44_ed_is_session_static (s))
1483     rmp->flags |= NAT_API_IS_STATIC;
1484
1485   if (nat44_ed_is_twice_nat_session (s))
1486     rmp->flags |= NAT_API_IS_TWICE_NAT;
1487
1488   rmp->flags |= NAT_API_IS_EXT_HOST_VALID;
1489
1490   rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
1491   rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
1492   rmp->total_pkts = ntohl (s->total_pkts);
1493   rmp->context = context;
1494   rmp->outside_port = s->out2in.port;
1495   rmp->inside_port = s->in2out.port;
1496   rmp->protocol = clib_host_to_net_u16 (s->proto);
1497   clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4);
1498   rmp->ext_host_port = s->ext_host_port;
1499   if (nat44_ed_is_twice_nat_session (s))
1500     {
1501       clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4);
1502       rmp->ext_host_nat_port = s->ext_host_nat_port;
1503     }
1504
1505   vl_api_send_msg (reg, (u8 *) rmp);
1506 }
1507
1508 static void
1509 vl_api_nat44_user_session_dump_t_handler (vl_api_nat44_user_session_dump_t *
1510                                           mp)
1511 {
1512   snat_main_per_thread_data_t *tsm;
1513   snat_main_t *sm = &snat_main;
1514   vl_api_registration_t *reg;
1515   snat_user_key_t ukey;
1516   snat_session_t *s;
1517   ip4_header_t ip;
1518
1519   reg = vl_api_client_index_to_registration (mp->client_index);
1520   if (!reg)
1521     return;
1522
1523   clib_memcpy (&ukey.addr, mp->ip_address, 4);
1524   ip.src_address.as_u32 = ukey.addr.as_u32;
1525   ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id));
1526   if (sm->num_workers > 1)
1527     tsm = vec_elt_at_index (
1528       sm->per_thread_data,
1529       nat44_ed_get_in2out_worker_index (0, &ip, ukey.fib_index, 0));
1530   else
1531     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1532
1533       pool_foreach (s, tsm->sessions) {
1534         if (s->in2out.addr.as_u32 == ukey.addr.as_u32)
1535           {
1536             send_nat44_user_session_details (s, reg, mp->context);
1537           }
1538       }
1539 }
1540
1541 static void
1542 send_nat44_user_session_v2_details (snat_session_t *s,
1543                                     vl_api_registration_t *reg, u32 context)
1544 {
1545   vl_api_nat44_user_session_v2_details_t *rmp;
1546   snat_main_t *sm = &snat_main;
1547   vnet_main_t *vnm = vnet_get_main ();
1548   u64 now = vlib_time_now (vnm->vlib_main);
1549   u64 sess_timeout_time = 0;
1550
1551   rmp = vl_msg_api_alloc (sizeof (*rmp));
1552   clib_memset (rmp, 0, sizeof (*rmp));
1553   rmp->_vl_msg_id =
1554     ntohs (VL_API_NAT44_USER_SESSION_V2_DETAILS + sm->msg_id_base);
1555   clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
1556   clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
1557
1558   if (nat44_ed_is_session_static (s))
1559     rmp->flags |= NAT_API_IS_STATIC;
1560
1561   if (nat44_ed_is_twice_nat_session (s))
1562     rmp->flags |= NAT_API_IS_TWICE_NAT;
1563
1564   rmp->flags |= NAT_API_IS_EXT_HOST_VALID;
1565
1566   rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
1567   rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
1568   rmp->total_pkts = ntohl (s->total_pkts);
1569   rmp->context = context;
1570   rmp->outside_port = s->out2in.port;
1571   rmp->inside_port = s->in2out.port;
1572   rmp->protocol = clib_host_to_net_u16 (s->proto);
1573   clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4);
1574   rmp->ext_host_port = s->ext_host_port;
1575   if (nat44_ed_is_twice_nat_session (s))
1576     {
1577       clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4);
1578       rmp->ext_host_nat_port = s->ext_host_nat_port;
1579     }
1580
1581   sess_timeout_time = s->last_heard + nat44_session_get_timeout (sm, s);
1582   rmp->is_timed_out = (now >= sess_timeout_time);
1583
1584   vl_api_send_msg (reg, (u8 *) rmp);
1585 }
1586
1587 static void
1588 send_nat44_user_session_v3_details (snat_session_t *s,
1589                                     vl_api_registration_t *reg, u32 context)
1590 {
1591   vl_api_nat44_user_session_v3_details_t *rmp;
1592   snat_main_t *sm = &snat_main;
1593   u64 now = vlib_time_now (vlib_get_main ());
1594   u64 sess_timeout_time = 0;
1595
1596   rmp = vl_msg_api_alloc (sizeof (*rmp));
1597   clib_memset (rmp, 0, sizeof (*rmp));
1598   rmp->_vl_msg_id =
1599     ntohs (VL_API_NAT44_USER_SESSION_V3_DETAILS + sm->msg_id_base);
1600   clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
1601   clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
1602
1603   if (nat44_ed_is_session_static (s))
1604     rmp->flags |= NAT_API_IS_STATIC;
1605
1606   if (nat44_ed_is_twice_nat_session (s))
1607     rmp->flags |= NAT_API_IS_TWICE_NAT;
1608
1609   rmp->flags |= NAT_API_IS_EXT_HOST_VALID;
1610
1611   rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
1612   rmp->time_since_last_heard =
1613     clib_host_to_net_u64 ((u64) (now - s->last_heard));
1614   rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
1615   rmp->total_pkts = ntohl (s->total_pkts);
1616   rmp->context = context;
1617   rmp->outside_port = s->out2in.port;
1618   rmp->inside_port = s->in2out.port;
1619   rmp->protocol = clib_host_to_net_u16 (s->proto);
1620   clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4);
1621   rmp->ext_host_port = s->ext_host_port;
1622   if (nat44_ed_is_twice_nat_session (s))
1623     {
1624       clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4);
1625       rmp->ext_host_nat_port = s->ext_host_nat_port;
1626     }
1627
1628   sess_timeout_time = s->last_heard + nat44_session_get_timeout (sm, s);
1629   rmp->is_timed_out = (now >= sess_timeout_time);
1630
1631   vl_api_send_msg (reg, (u8 *) rmp);
1632 }
1633
1634 static void
1635 vl_api_nat44_user_session_v2_dump_t_handler (
1636   vl_api_nat44_user_session_v2_dump_t *mp)
1637 {
1638   snat_main_per_thread_data_t *tsm;
1639   snat_main_t *sm = &snat_main;
1640   vl_api_registration_t *reg;
1641   snat_user_key_t ukey;
1642   snat_session_t *s;
1643   ip4_header_t ip;
1644
1645   reg = vl_api_client_index_to_registration (mp->client_index);
1646   if (!reg)
1647     return;
1648
1649   clib_memcpy (&ukey.addr, mp->ip_address, 4);
1650   ip.src_address.as_u32 = ukey.addr.as_u32;
1651   ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id));
1652   if (sm->num_workers > 1)
1653     tsm = vec_elt_at_index (
1654       sm->per_thread_data,
1655       nat44_ed_get_in2out_worker_index (0, &ip, ukey.fib_index, 0));
1656   else
1657     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1658
1659   pool_foreach (s, tsm->sessions)
1660     {
1661       if (s->in2out.addr.as_u32 == ukey.addr.as_u32)
1662         {
1663           send_nat44_user_session_v2_details (s, reg, mp->context);
1664         }
1665     }
1666 }
1667
1668 static void
1669 vl_api_nat44_user_session_v3_dump_t_handler (
1670   vl_api_nat44_user_session_v3_dump_t *mp)
1671 {
1672   snat_main_per_thread_data_t *tsm;
1673   snat_main_t *sm = &snat_main;
1674   vl_api_registration_t *reg;
1675   snat_user_key_t ukey;
1676   snat_session_t *s;
1677   ip4_header_t ip;
1678
1679   reg = vl_api_client_index_to_registration (mp->client_index);
1680   if (!reg)
1681     return;
1682
1683   clib_memcpy (&ukey.addr, mp->ip_address, 4);
1684   ip.src_address.as_u32 = ukey.addr.as_u32;
1685   ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id));
1686   if (sm->num_workers > 1)
1687     tsm = vec_elt_at_index (
1688       sm->per_thread_data,
1689       nat44_ed_get_in2out_worker_index (0, &ip, ukey.fib_index, 0));
1690   else
1691     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1692
1693   pool_foreach (s, tsm->sessions)
1694     {
1695       if (s->in2out.addr.as_u32 == ukey.addr.as_u32)
1696         {
1697           send_nat44_user_session_v3_details (s, reg, mp->context);
1698         }
1699     }
1700 }
1701
1702 /* API definitions */
1703 #include <vnet/format_fns.h>
1704 #include <nat/nat44-ed/nat44_ed.api.c>
1705
1706 /* Set up the API message handling tables */
1707 clib_error_t *
1708 nat44_api_hookup (vlib_main_t * vm)
1709 {
1710   snat_main_t *sm = &snat_main;
1711   sm->msg_id_base = setup_message_id_table ();
1712   return 0;
1713 }
1714
1715 /*
1716  * fd.io coding-style-patch-verification: ON
1717  *
1718  * Local Variables:
1719  * eval: (c-set-style "gnu")
1720  * End:
1721  */