nat: move deterministic nat to det44 sub feature
[vpp.git] / src / plugins / nat / det44 / det44_api.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 /**
17  * @file
18  * @brief Deterministic NAT (CGN) plugin API implementation
19  */
20
21 #include <vnet/ip/ip_types_api.h>
22 #include <nat/det44/det44.h>
23 #include <nat/det44/det44.api_enum.h>
24 #include <nat/det44/det44.api_types.h>
25 #include <vnet/fib/fib_table.h>
26 #include <vnet/ip/ip.h>
27
28 #include <vlibmemory/api.h>
29
30 #define REPLY_MSG_ID_BASE dm->msg_id_base
31 #include <vlibapi/api_helper_macros.h>
32
33 static void
34 vl_api_det44_add_del_map_t_handler (vl_api_det44_add_del_map_t * mp)
35 {
36   det44_main_t *dm = &det44_main;
37   vl_api_det44_add_del_map_reply_t *rmp;
38   int rv = 0;
39   ip4_address_t in_addr, out_addr;
40   clib_memcpy (&in_addr, mp->in_addr, 4);
41   clib_memcpy (&out_addr, mp->out_addr, 4);
42   rv = snat_det_add_map (&in_addr, mp->in_plen, &out_addr,
43                          mp->out_plen, mp->is_add);
44   REPLY_MACRO (VL_API_DET44_ADD_DEL_MAP_REPLY);
45 }
46
47 static void
48 vl_api_det44_forward_t_handler (vl_api_det44_forward_t * mp)
49 {
50   det44_main_t *dm = &det44_main;
51   vl_api_det44_forward_reply_t *rmp;
52   int rv = 0;
53   u16 lo_port = 0, hi_port = 0;
54   snat_det_map_t *m;
55   ip4_address_t in_addr, out_addr;
56
57   out_addr.as_u32 = 0;
58   clib_memcpy (&in_addr, mp->in_addr, 4);
59   m = snat_det_map_by_user (&in_addr);
60   if (!m)
61     {
62       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
63       goto send_reply;
64     }
65
66   snat_det_forward (m, &in_addr, &out_addr, &lo_port);
67   hi_port = lo_port + m->ports_per_host - 1;
68
69 send_reply:
70   /* *INDENT-OFF* */
71   REPLY_MACRO2 (VL_API_DET44_FORWARD_REPLY,
72   ({
73     rmp->out_port_lo = ntohs (lo_port);
74     rmp->out_port_hi = ntohs (hi_port);
75     clib_memcpy (rmp->out_addr, &out_addr, 4);
76   }))
77   /* *INDENT-ON* */
78 }
79
80 static void
81 vl_api_det44_reverse_t_handler (vl_api_det44_reverse_t * mp)
82 {
83   det44_main_t *dm = &det44_main;
84   vl_api_det44_reverse_reply_t *rmp;
85   int rv = 0;
86   ip4_address_t out_addr, in_addr;
87   snat_det_map_t *m;
88
89   in_addr.as_u32 = 0;
90   clib_memcpy (&out_addr, mp->out_addr, 4);
91   m = snat_det_map_by_out (&out_addr);
92   if (!m)
93     {
94       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
95       goto send_reply;
96     }
97
98   snat_det_reverse (m, &out_addr, htons (mp->out_port), &in_addr);
99
100 send_reply:
101   /* *INDENT-OFF* */
102   REPLY_MACRO2 (VL_API_DET44_REVERSE_REPLY,
103   ({
104     clib_memcpy (rmp->in_addr, &in_addr, 4);
105   }))
106   /* *INDENT-ON* */
107 }
108
109 static void
110 sent_det44_map_details (snat_det_map_t * m, vl_api_registration_t * reg,
111                         u32 context)
112 {
113   det44_main_t *dm = &det44_main;
114   vl_api_det44_map_details_t *rmp;
115
116   rmp = vl_msg_api_alloc (sizeof (*rmp));
117   clib_memset (rmp, 0, sizeof (*rmp));
118   rmp->_vl_msg_id = ntohs (VL_API_DET44_MAP_DETAILS + dm->msg_id_base);
119   clib_memcpy (rmp->in_addr, &m->in_addr, 4);
120   rmp->in_plen = m->in_plen;
121   clib_memcpy (rmp->out_addr, &m->out_addr, 4);
122   rmp->out_plen = m->out_plen;
123   rmp->sharing_ratio = htonl (m->sharing_ratio);
124   rmp->ports_per_host = htons (m->ports_per_host);
125   rmp->ses_num = htonl (m->ses_num);
126   rmp->context = context;
127
128   vl_api_send_msg (reg, (u8 *) rmp);
129 }
130
131 static void
132 vl_api_det44_map_dump_t_handler (vl_api_det44_map_dump_t * mp)
133 {
134   det44_main_t *dm = &det44_main;
135   vl_api_registration_t *reg;
136   snat_det_map_t *m;
137
138   reg = vl_api_client_index_to_registration (mp->client_index);
139   if (!reg)
140     return;
141
142   /* *INDENT-OFF* */
143   vec_foreach(m, dm->det_maps)
144     sent_det44_map_details(m, reg, mp->context);
145   /* *INDENT-ON* */
146 }
147
148 static void
149 vl_api_det44_close_session_out_t_handler (vl_api_det44_close_session_out_t
150                                           * mp)
151 {
152   det44_main_t *dm = &det44_main;
153   vl_api_det44_close_session_out_reply_t *rmp;
154   ip4_address_t out_addr, ext_addr, in_addr;
155   snat_det_out_key_t key;
156   snat_det_map_t *m;
157   snat_det_session_t *ses;
158   int rv = 0;
159
160   clib_memcpy (&out_addr, mp->out_addr, 4);
161   clib_memcpy (&ext_addr, mp->ext_addr, 4);
162
163   m = snat_det_map_by_out (&out_addr);
164   if (!m)
165     {
166       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
167       goto send_reply;
168     }
169   snat_det_reverse (m, &ext_addr, ntohs (mp->out_port), &in_addr);
170   key.ext_host_addr = ext_addr;
171   key.ext_host_port = mp->ext_port;
172   key.out_port = mp->out_port;
173   ses = snat_det_get_ses_by_out (m, &in_addr, key.as_u64);
174   if (!ses)
175     {
176       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
177       goto send_reply;
178     }
179   snat_det_ses_close (m, ses);
180
181 send_reply:
182   REPLY_MACRO (VL_API_DET44_CLOSE_SESSION_OUT_REPLY);
183 }
184
185 static void
186 vl_api_det44_close_session_in_t_handler (vl_api_det44_close_session_in_t * mp)
187 {
188   det44_main_t *dm = &det44_main;
189   vl_api_det44_close_session_in_reply_t *rmp;
190   ip4_address_t in_addr, ext_addr;
191   snat_det_out_key_t key;
192   snat_det_map_t *m;
193   snat_det_session_t *ses;
194   int rv = 0;
195
196   clib_memcpy (&in_addr, mp->in_addr, 4);
197   clib_memcpy (&ext_addr, mp->ext_addr, 4);
198
199   m = snat_det_map_by_user (&in_addr);
200   if (!m)
201     {
202       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
203       goto send_reply;
204     }
205   key.ext_host_addr = ext_addr;
206   key.ext_host_port = mp->ext_port;
207   ses = snat_det_find_ses_by_in (m, &in_addr, mp->in_port, key);
208   if (!ses)
209     {
210       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
211       goto send_reply;
212     }
213   snat_det_ses_close (m, ses);
214
215 send_reply:
216   REPLY_MACRO (VL_API_DET44_CLOSE_SESSION_OUT_REPLY);
217 }
218
219 static void
220 send_det44_session_details (snat_det_session_t * s,
221                             vl_api_registration_t * reg, u32 context)
222 {
223   det44_main_t *dm = &det44_main;
224   vl_api_det44_session_details_t *rmp;
225
226   rmp = vl_msg_api_alloc (sizeof (*rmp));
227   clib_memset (rmp, 0, sizeof (*rmp));
228   rmp->_vl_msg_id = ntohs (VL_API_DET44_SESSION_DETAILS + dm->msg_id_base);
229   rmp->in_port = s->in_port;
230   clib_memcpy (rmp->ext_addr, &s->out.ext_host_addr, 4);
231   rmp->ext_port = s->out.ext_host_port;
232   rmp->out_port = s->out.out_port;
233   rmp->state = s->state;
234   rmp->expire = ntohl (s->expire);
235   rmp->context = context;
236
237   vl_api_send_msg (reg, (u8 *) rmp);
238 }
239
240 static void
241 vl_api_det44_session_dump_t_handler (vl_api_det44_session_dump_t * mp)
242 {
243   vl_api_registration_t *reg;
244   ip4_address_t user_addr;
245   snat_det_map_t *m;
246   snat_det_session_t *s, empty_ses;
247   u16 i;
248
249   reg = vl_api_client_index_to_registration (mp->client_index);
250   if (!reg)
251     return;
252
253   clib_memset (&empty_ses, 0, sizeof (empty_ses));
254   clib_memcpy (&user_addr, mp->user_addr, 4);
255   m = snat_det_map_by_user (&user_addr);
256   if (!m)
257     return;
258
259   s = m->sessions + snat_det_user_ses_offset (&user_addr, m->in_plen);
260   for (i = 0; i < DET44_SES_PER_USER; i++)
261     {
262       if (s->out.as_u64)
263         send_det44_session_details (s, reg, mp->context);
264       s++;
265     }
266 }
267
268 static void
269   vl_api_det44_plugin_enable_disable_t_handler
270   (vl_api_det44_plugin_enable_disable_t * mp)
271 {
272   det44_main_t *dm = &det44_main;
273   vl_api_det44_plugin_enable_disable_reply_t *rmp;
274   det44_config_t c = { 0 };
275   int rv = 0;
276   if (mp->enable)
277     {
278       c.outside_vrf_id = ntohl (mp->outside_vrf);
279       c.inside_vrf_id = ntohl (mp->inside_vrf);
280       rv = det44_plugin_enable (c);
281     }
282   else
283     {
284       rv = det44_plugin_disable ();
285     }
286   REPLY_MACRO (VL_API_DET44_PLUGIN_ENABLE_DISABLE_REPLY);
287 }
288
289 static void
290   vl_api_det44_interface_add_del_feature_t_handler
291   (vl_api_det44_interface_add_del_feature_t * mp)
292 {
293   det44_main_t *dm = &det44_main;
294   vl_api_det44_interface_add_del_feature_reply_t *rmp;
295   u32 sw_if_index = ntohl (mp->sw_if_index);
296   int rv = 0;
297   VALIDATE_SW_IF_INDEX (mp);
298   rv = det44_interface_add_del (sw_if_index, mp->is_inside, !mp->is_add);
299   BAD_SW_IF_INDEX_LABEL;
300   REPLY_MACRO (VL_API_DET44_INTERFACE_ADD_DEL_FEATURE_REPLY);
301 }
302
303 static void
304 det44_send_interface_details (det44_interface_t * i,
305                               vl_api_registration_t * reg, u32 context)
306 {
307   det44_main_t *dm = &det44_main;
308   vl_api_det44_interface_details_t *rmp;
309
310   rmp = vl_msg_api_alloc (sizeof (*rmp));
311   clib_memset (rmp, 0, sizeof (*rmp));
312   rmp->_vl_msg_id = ntohs (VL_API_DET44_INTERFACE_DETAILS + dm->msg_id_base);
313   rmp->sw_if_index = ntohl (i->sw_if_index);
314   rmp->is_outside = det44_interface_is_outside (i);
315   rmp->is_inside = det44_interface_is_inside (i);
316   rmp->context = context;
317   vl_api_send_msg (reg, (u8 *) rmp);
318 }
319
320 static void
321 vl_api_det44_interface_dump_t_handler (vl_api_det44_interface_dump_t * mp)
322 {
323   det44_main_t *dm = &det44_main;
324   vl_api_registration_t *reg;
325   det44_interface_t *i;
326
327   reg = vl_api_client_index_to_registration (mp->client_index);
328   if (!reg)
329     return;
330
331   /* *INDENT-OFF* */
332   pool_foreach (i, dm->interfaces,
333   ({
334     det44_send_interface_details(i, reg, mp->context);
335   }));
336   /* *INDENT-ON* */
337 }
338
339 static void
340 vl_api_det44_set_timeouts_t_handler (vl_api_det44_set_timeouts_t * mp)
341 {
342   det44_main_t *dm = &det44_main;
343   vl_api_det44_set_timeouts_reply_t *rmp;
344   nat_timeouts_t timeouts;
345   int rv = 0;
346   timeouts.udp = ntohl (mp->udp);
347   timeouts.tcp.established = ntohl (mp->tcp_established);
348   timeouts.tcp.transitory = ntohl (mp->tcp_transitory);
349   timeouts.icmp = ntohl (mp->icmp);
350   rv = det44_set_timeouts (&timeouts);
351   REPLY_MACRO (VL_API_DET44_SET_TIMEOUTS_REPLY);
352 }
353
354 static void
355 vl_api_det44_get_timeouts_t_handler (vl_api_det44_get_timeouts_t * mp)
356 {
357   det44_main_t *dm = &det44_main;
358   vl_api_det44_get_timeouts_reply_t *rmp;
359   nat_timeouts_t timeouts;
360   int rv = 0;
361   timeouts = det44_get_timeouts ();
362   /* *INDENT-OFF* */
363   REPLY_MACRO2 (VL_API_DET44_GET_TIMEOUTS_REPLY,
364   ({
365     rmp->udp = htonl (timeouts.udp);
366     rmp->tcp_established = htonl (timeouts.tcp.established);
367     rmp->tcp_transitory = htonl (timeouts.tcp.transitory);
368     rmp->icmp = htonl (timeouts.icmp);
369   }))
370   /* *INDENT-ON* */
371 }
372
373 /*
374  * Obsolete deterministic API to be removed
375  */
376
377 static void
378 vl_api_nat_det_add_del_map_t_handler (vl_api_nat_det_add_del_map_t * mp)
379 {
380   det44_main_t *dm = &det44_main;
381   vl_api_nat_det_add_del_map_reply_t *rmp;
382   int rv = 0;
383   ip4_address_t in_addr, out_addr;
384
385   clib_memcpy (&in_addr, mp->in_addr, 4);
386   clib_memcpy (&out_addr, mp->out_addr, 4);
387   rv = snat_det_add_map (&in_addr, mp->in_plen, &out_addr,
388                          mp->out_plen, mp->is_add);
389   REPLY_MACRO (VL_API_NAT_DET_ADD_DEL_MAP_REPLY);
390 }
391
392 static void
393 vl_api_nat_det_forward_t_handler (vl_api_nat_det_forward_t * mp)
394 {
395   det44_main_t *dm = &det44_main;
396   vl_api_nat_det_forward_reply_t *rmp;
397   int rv = 0;
398   u16 lo_port = 0, hi_port = 0;
399   snat_det_map_t *m;
400   ip4_address_t in_addr, out_addr;
401
402   out_addr.as_u32 = 0;
403   clib_memcpy (&in_addr, mp->in_addr, 4);
404   m = snat_det_map_by_user (&in_addr);
405   if (!m)
406     {
407       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
408       goto send_reply;
409     }
410
411   snat_det_forward (m, &in_addr, &out_addr, &lo_port);
412   hi_port = lo_port + m->ports_per_host - 1;
413
414 send_reply:
415   /* *INDENT-OFF* */
416   REPLY_MACRO2 (VL_API_NAT_DET_FORWARD_REPLY,
417   ({
418     rmp->out_port_lo = ntohs (lo_port);
419     rmp->out_port_hi = ntohs (hi_port);
420     clib_memcpy (rmp->out_addr, &out_addr, 4);
421   }))
422   /* *INDENT-ON* */
423 }
424
425 static void
426 vl_api_nat_det_reverse_t_handler (vl_api_nat_det_reverse_t * mp)
427 {
428   det44_main_t *dm = &det44_main;
429   vl_api_nat_det_reverse_reply_t *rmp;
430   int rv = 0;
431   ip4_address_t out_addr, in_addr;
432   snat_det_map_t *m;
433
434   in_addr.as_u32 = 0;
435   clib_memcpy (&out_addr, mp->out_addr, 4);
436   m = snat_det_map_by_out (&out_addr);
437   if (!m)
438     {
439       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
440       goto send_reply;
441     }
442
443   snat_det_reverse (m, &out_addr, htons (mp->out_port), &in_addr);
444
445 send_reply:
446   /* *INDENT-OFF* */
447   REPLY_MACRO2 (VL_API_NAT_DET_REVERSE_REPLY,
448   ({
449     clib_memcpy (rmp->in_addr, &in_addr, 4);
450   }))
451   /* *INDENT-ON* */
452 }
453
454 static void
455 sent_nat_det_map_details (snat_det_map_t * m, vl_api_registration_t * reg,
456                           u32 context)
457 {
458   det44_main_t *dm = &det44_main;
459   vl_api_nat_det_map_details_t *rmp;
460
461   rmp = vl_msg_api_alloc (sizeof (*rmp));
462   clib_memset (rmp, 0, sizeof (*rmp));
463   rmp->_vl_msg_id = ntohs (VL_API_NAT_DET_MAP_DETAILS + dm->msg_id_base);
464   clib_memcpy (rmp->in_addr, &m->in_addr, 4);
465   rmp->in_plen = m->in_plen;
466   clib_memcpy (rmp->out_addr, &m->out_addr, 4);
467   rmp->out_plen = m->out_plen;
468   rmp->sharing_ratio = htonl (m->sharing_ratio);
469   rmp->ports_per_host = htons (m->ports_per_host);
470   rmp->ses_num = htonl (m->ses_num);
471   rmp->context = context;
472
473   vl_api_send_msg (reg, (u8 *) rmp);
474 }
475
476 static void
477 vl_api_nat_det_map_dump_t_handler (vl_api_nat_det_map_dump_t * mp)
478 {
479   det44_main_t *dm = &det44_main;
480   vl_api_registration_t *reg;
481   snat_det_map_t *m;
482
483   reg = vl_api_client_index_to_registration (mp->client_index);
484   if (!reg)
485     return;
486
487   /* *INDENT-OFF* */
488   vec_foreach(m, dm->det_maps)
489     sent_nat_det_map_details(m, reg, mp->context);
490   /* *INDENT-ON* */
491 }
492
493 static void
494 vl_api_nat_det_close_session_out_t_handler (vl_api_nat_det_close_session_out_t
495                                             * mp)
496 {
497   det44_main_t *dm = &det44_main;
498   vl_api_nat_det_close_session_out_reply_t *rmp;
499   ip4_address_t out_addr, ext_addr, in_addr;
500   snat_det_out_key_t key;
501   snat_det_map_t *m;
502   snat_det_session_t *ses;
503   int rv = 0;
504
505   clib_memcpy (&out_addr, mp->out_addr, 4);
506   clib_memcpy (&ext_addr, mp->ext_addr, 4);
507
508   m = snat_det_map_by_out (&out_addr);
509   if (!m)
510     {
511       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
512       goto send_reply;
513     }
514   snat_det_reverse (m, &ext_addr, ntohs (mp->out_port), &in_addr);
515   key.ext_host_addr = ext_addr;
516   key.ext_host_port = mp->ext_port;
517   key.out_port = mp->out_port;
518   ses = snat_det_get_ses_by_out (m, &in_addr, key.as_u64);
519   if (!ses)
520     {
521       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
522       goto send_reply;
523     }
524   snat_det_ses_close (m, ses);
525
526 send_reply:
527   REPLY_MACRO (VL_API_NAT_DET_CLOSE_SESSION_OUT_REPLY);
528 }
529
530 static void
531 vl_api_nat_det_close_session_in_t_handler (vl_api_nat_det_close_session_in_t *
532                                            mp)
533 {
534   det44_main_t *dm = &det44_main;
535   vl_api_nat_det_close_session_in_reply_t *rmp;
536   ip4_address_t in_addr, ext_addr;
537   snat_det_out_key_t key;
538   snat_det_map_t *m;
539   snat_det_session_t *ses;
540   int rv = 0;
541
542   clib_memcpy (&in_addr, mp->in_addr, 4);
543   clib_memcpy (&ext_addr, mp->ext_addr, 4);
544
545   m = snat_det_map_by_user (&in_addr);
546   if (!m)
547     {
548       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
549       goto send_reply;
550     }
551   key.ext_host_addr = ext_addr;
552   key.ext_host_port = mp->ext_port;
553   ses = snat_det_find_ses_by_in (m, &in_addr, mp->in_port, key);
554   if (!ses)
555     {
556       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
557       goto send_reply;
558     }
559   snat_det_ses_close (m, ses);
560
561 send_reply:
562   REPLY_MACRO (VL_API_NAT_DET_CLOSE_SESSION_OUT_REPLY);
563 }
564
565 static void
566 send_nat_det_session_details (snat_det_session_t * s,
567                               vl_api_registration_t * reg, u32 context)
568 {
569   det44_main_t *dm = &det44_main;
570   vl_api_nat_det_session_details_t *rmp;
571
572   rmp = vl_msg_api_alloc (sizeof (*rmp));
573   clib_memset (rmp, 0, sizeof (*rmp));
574   rmp->_vl_msg_id = ntohs (VL_API_NAT_DET_SESSION_DETAILS + dm->msg_id_base);
575   rmp->in_port = s->in_port;
576   clib_memcpy (rmp->ext_addr, &s->out.ext_host_addr, 4);
577   rmp->ext_port = s->out.ext_host_port;
578   rmp->out_port = s->out.out_port;
579   rmp->state = s->state;
580   rmp->expire = ntohl (s->expire);
581   rmp->context = context;
582
583   vl_api_send_msg (reg, (u8 *) rmp);
584 }
585
586 static void
587 vl_api_nat_det_session_dump_t_handler (vl_api_nat_det_session_dump_t * mp)
588 {
589   vl_api_registration_t *reg;
590   ip4_address_t user_addr;
591   snat_det_map_t *m;
592   snat_det_session_t *s, empty_ses;
593   u16 i;
594
595   reg = vl_api_client_index_to_registration (mp->client_index);
596   if (!reg)
597     return;
598
599   clib_memset (&empty_ses, 0, sizeof (empty_ses));
600   clib_memcpy (&user_addr, mp->user_addr, 4);
601   m = snat_det_map_by_user (&user_addr);
602   if (!m)
603     return;
604
605   s = m->sessions + snat_det_user_ses_offset (&user_addr, m->in_plen);
606   for (i = 0; i < DET44_SES_PER_USER; i++)
607     {
608       if (s->out.as_u64)
609         send_nat_det_session_details (s, reg, mp->context);
610       s++;
611     }
612 }
613
614 /* API definitions */
615 #include <vnet/format_fns.h>
616 #include <nat/det44/det44.api.c>
617
618 /* Set up the API message handling tables */
619 clib_error_t *
620 det44_api_hookup (vlib_main_t * vm)
621 {
622   det44_main_t *dm = &det44_main;
623   dm->msg_id_base = setup_message_id_table ();
624   return 0;
625 }
626
627 /*
628  * fd.io coding-style-patch-verification: ON
629  *
630  * Local Variables:
631  * eval: (c-set-style "gnu")
632  * End:
633  */