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