cnat: Prepare extended snat policies
[vpp.git] / src / plugins / cnat / cnat_api.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stddef.h>
17
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <cnat/cnat_translation.h>
21 #include <cnat/cnat_session.h>
22 #include <cnat/cnat_client.h>
23 #include <cnat/cnat_snat_policy.h>
24
25 #include <vnet/ip/ip_types_api.h>
26
27 #include <vpp/app/version.h>
28
29 #include <vlibapi/api.h>
30 #include <vlibmemory/api.h>
31
32 /* define message IDs */
33 #include <vnet/format_fns.h>
34 #include <cnat/cnat.api_enum.h>
35 #include <cnat/cnat.api_types.h>
36
37 /**
38  * Base message ID fot the plugin
39  */
40 static u32 cnat_base_msg_id;
41
42 #define REPLY_MSG_ID_BASE cnat_base_msg_id
43
44 #include <vlibapi/api_helper_macros.h>
45
46 static int
47 cnat_endpoint_decode (const vl_api_cnat_endpoint_t * in,
48                       cnat_endpoint_t * out)
49 {
50   int rv = 0;
51   out->ce_port = clib_net_to_host_u16 (in->port);
52   out->ce_sw_if_index = clib_net_to_host_u32 (in->sw_if_index);
53   out->ce_flags = 0;
54   if (out->ce_sw_if_index == INDEX_INVALID)
55     ip_address_decode2 (&in->addr, &out->ce_ip);
56   else
57     rv = ip_address_family_decode (in->if_af, &out->ce_ip.version);
58   return rv;
59 }
60
61 static int
62 cnat_endpoint_tuple_decode (const vl_api_cnat_endpoint_tuple_t * in,
63                             cnat_endpoint_tuple_t * out)
64 {
65   int rv = 0;
66   rv = cnat_endpoint_decode (&in->src_ep, &out->src_ep);
67   if (rv)
68     return rv;
69   rv = cnat_endpoint_decode (&in->dst_ep, &out->dst_ep);
70   out->ep_flags = in->flags;
71   return rv;
72 }
73
74 static void
75 cnat_endpoint_encode (const cnat_endpoint_t * in,
76                       vl_api_cnat_endpoint_t * out)
77 {
78   out->port = clib_net_to_host_u16 (in->ce_port);
79   out->sw_if_index = clib_net_to_host_u32 (in->ce_sw_if_index);
80   out->if_af = ip_address_family_encode (in->ce_ip.version);
81   if (in->ce_flags & CNAT_EP_FLAG_RESOLVED)
82     ip_address_encode2 (&in->ce_ip, &out->addr);
83   else
84     clib_memset ((void *) &in->ce_ip, 0, sizeof (in->ce_ip));
85 }
86
87 static void
88 vl_api_cnat_translation_update_t_handler (vl_api_cnat_translation_update_t
89                                           * mp)
90 {
91   vl_api_cnat_translation_update_reply_t *rmp;
92   cnat_endpoint_t vip;
93   cnat_endpoint_tuple_t *paths = NULL, *path;
94   ip_protocol_t ip_proto;
95   u32 id = ~0;
96   u8 flags;
97   int rv = 0;
98   u32 pi, n_paths;
99   cnat_lb_type_t lb_type;
100
101   rv = ip_proto_decode (mp->translation.ip_proto, &ip_proto);
102
103   if (rv)
104     goto done;
105
106   n_paths = clib_net_to_host_u32 (mp->translation.n_paths);
107   vec_validate (paths, n_paths - 1);
108
109   for (pi = 0; pi < n_paths; pi++)
110     {
111       path = &paths[pi];
112       rv = cnat_endpoint_tuple_decode (&mp->translation.paths[pi], path);
113       if (rv)
114         goto done;
115     }
116
117   rv = cnat_endpoint_decode (&mp->translation.vip, &vip);
118   if (rv)
119     goto done;
120
121   flags = mp->translation.flags;
122   if (!mp->translation.is_real_ip)
123     flags |= CNAT_FLAG_EXCLUSIVE;
124
125   lb_type = (cnat_lb_type_t) mp->translation.lb_type;
126   id = cnat_translation_update (&vip, ip_proto, paths, flags, lb_type);
127
128   vec_free (paths);
129
130 done:
131   REPLY_MACRO2 (VL_API_CNAT_TRANSLATION_UPDATE_REPLY,
132   ({
133     rmp->id = htonl (id);
134   }));
135 }
136
137 static void
138 vl_api_cnat_translation_del_t_handler (vl_api_cnat_translation_del_t * mp)
139 {
140   vl_api_cnat_translation_del_reply_t *rmp;
141   int rv;
142
143   rv = cnat_translation_delete (ntohl (mp->id));
144
145   REPLY_MACRO (VL_API_CNAT_TRANSLATION_DEL_REPLY);
146 }
147
148 typedef struct cnat_dump_walk_ctx_t_
149 {
150   vl_api_registration_t *rp;
151   u32 context;
152 } cnat_dump_walk_ctx_t;
153
154 static walk_rc_t
155 cnat_translation_send_details (u32 cti, void *args)
156 {
157   vl_api_cnat_translation_details_t *mp;
158   cnat_dump_walk_ctx_t *ctx;
159   cnat_ep_trk_t *trk;
160   vl_api_cnat_endpoint_tuple_t *path;
161   size_t msg_size;
162   cnat_translation_t *ct;
163   u32 n_paths;
164
165   ctx = args;
166   ct = cnat_translation_get (cti);
167   n_paths = vec_len (ct->ct_paths);
168   msg_size = sizeof (*mp) + sizeof (mp->translation.paths[0]) * n_paths;
169
170   mp = vl_msg_api_alloc_zero (msg_size);
171   mp->_vl_msg_id = ntohs (VL_API_CNAT_TRANSLATION_DETAILS + cnat_base_msg_id);
172
173   /* fill in the message */
174   mp->context = ctx->context;
175   mp->translation.n_paths = clib_host_to_net_u32 (n_paths);
176   mp->translation.id = clib_host_to_net_u32 (cti);
177   cnat_endpoint_encode (&ct->ct_vip, &mp->translation.vip);
178   mp->translation.ip_proto = ip_proto_encode (ct->ct_proto);
179   mp->translation.lb_type = (vl_api_cnat_lb_type_t) ct->lb_type;
180
181   path = mp->translation.paths;
182   vec_foreach (trk, ct->ct_paths)
183   {
184     cnat_endpoint_encode (&trk->ct_ep[VLIB_TX], &path->dst_ep);
185     cnat_endpoint_encode (&trk->ct_ep[VLIB_RX], &path->src_ep);
186     path->flags = trk->ct_flags;
187     path++;
188   }
189
190   vl_api_send_msg (ctx->rp, (u8 *) mp);
191
192   return (WALK_CONTINUE);
193 }
194
195 static void
196 vl_api_cnat_translation_dump_t_handler (vl_api_cnat_translation_dump_t * mp)
197 {
198   vl_api_registration_t *rp;
199
200   rp = vl_api_client_index_to_registration (mp->client_index);
201   if (rp == 0)
202     return;
203
204   cnat_dump_walk_ctx_t ctx = {
205     .rp = rp,
206     .context = mp->context,
207   };
208
209   cnat_translation_walk (cnat_translation_send_details, &ctx);
210 }
211
212 static void
213 ip_address2_from_46 (const ip46_address_t * nh,
214                      ip_address_family_t af, ip_address_t * ip)
215 {
216   ip_addr_46 (ip) = *nh;
217   ip_addr_version (ip) = af;
218 }
219
220 static walk_rc_t
221 cnat_session_send_details (const cnat_session_t * session, void *args)
222 {
223   vl_api_cnat_session_details_t *mp;
224   cnat_dump_walk_ctx_t *ctx;
225   cnat_endpoint_t ep;
226
227   ctx = args;
228
229   mp = vl_msg_api_alloc_zero (sizeof (*mp));
230   mp->_vl_msg_id = ntohs (VL_API_CNAT_SESSION_DETAILS + cnat_base_msg_id);
231
232   /* fill in the message */
233   mp->context = ctx->context;
234
235   ep.ce_sw_if_index = INDEX_INVALID;
236   ep.ce_flags = CNAT_EP_FLAG_RESOLVED;
237   ip_address2_from_46 (&session->value.cs_ip[VLIB_TX], session->key.cs_af,
238                        &ep.ce_ip);
239   ep.ce_port = clib_host_to_net_u16 (session->value.cs_port[VLIB_TX]);
240   cnat_endpoint_encode (&ep, &mp->session.new);
241
242   ip_address2_from_46 (&session->key.cs_ip[VLIB_RX], session->key.cs_af,
243                        &ep.ce_ip);
244   ep.ce_port = clib_host_to_net_u16 (session->key.cs_port[VLIB_RX]);
245   cnat_endpoint_encode (&ep, &mp->session.src);
246
247   ip_address2_from_46 (&session->key.cs_ip[VLIB_TX], session->key.cs_af,
248                        &ep.ce_ip);
249   ep.ce_port = clib_host_to_net_u16 (session->key.cs_port[VLIB_TX]);
250   cnat_endpoint_encode (&ep, &mp->session.dst);
251
252   mp->session.ip_proto = ip_proto_encode (session->key.cs_proto);
253   mp->session.location = session->key.cs_loc;
254
255   vl_api_send_msg (ctx->rp, (u8 *) mp);
256
257   return (WALK_CONTINUE);
258 }
259
260 static void
261 vl_api_cnat_session_dump_t_handler (vl_api_cnat_session_dump_t * mp)
262 {
263   vl_api_registration_t *rp;
264
265   rp = vl_api_client_index_to_registration (mp->client_index);
266   if (rp == 0)
267     return;
268
269   cnat_dump_walk_ctx_t ctx = {
270     .rp = rp,
271     .context = mp->context,
272   };
273
274   cnat_session_walk (cnat_session_send_details, &ctx);
275 }
276
277 static void
278 vl_api_cnat_session_purge_t_handler (vl_api_cnat_session_purge_t * mp)
279 {
280   vl_api_cnat_session_purge_reply_t *rmp;
281   int rv;
282
283   cnat_client_throttle_pool_process ();
284   rv = cnat_session_purge ();
285   rv |= cnat_translation_purge ();
286
287   REPLY_MACRO (VL_API_CNAT_SESSION_PURGE_REPLY);
288 }
289
290 static void
291 vl_api_cnat_get_snat_addresses_t_handler (vl_api_cnat_get_snat_addresses_t
292                                           * mp)
293 {
294   vl_api_cnat_get_snat_addresses_reply_t *rmp;
295   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
296   int rv = 0;
297
298   REPLY_MACRO2 (
299     VL_API_CNAT_GET_SNAT_ADDRESSES_REPLY, ({
300       ip6_address_encode (&ip_addr_v6 (&cpm->snat_ip6.ce_ip), rmp->snat_ip6);
301       ip4_address_encode (&ip_addr_v4 (&cpm->snat_ip4.ce_ip), rmp->snat_ip4);
302       rmp->sw_if_index = clib_host_to_net_u32 (cpm->snat_ip6.ce_sw_if_index);
303     }));
304 }
305
306 static void
307 vl_api_cnat_set_snat_addresses_t_handler (vl_api_cnat_set_snat_addresses_t
308                                           * mp)
309 {
310   vl_api_cnat_set_snat_addresses_reply_t *rmp;
311   u32 sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
312   ip4_address_t ip4;
313   ip6_address_t ip6;
314   int rv = 0;
315
316   ip4_address_decode (mp->snat_ip4, &ip4);
317   ip6_address_decode (mp->snat_ip6, &ip6);
318
319   cnat_set_snat (&ip4, &ip6, sw_if_index);
320
321   REPLY_MACRO (VL_API_CNAT_SET_SNAT_ADDRESSES_REPLY);
322 }
323
324 static void
325 vl_api_cnat_set_snat_policy_t_handler (vl_api_cnat_set_snat_policy_t *mp)
326 {
327   vl_api_cnat_set_snat_policy_reply_t *rmp;
328   int rv = 0;
329   cnat_snat_policy_type_t policy = (cnat_snat_policy_type_t) mp->policy;
330
331   rv = cnat_set_snat_policy (policy);
332
333   REPLY_MACRO (VL_API_CNAT_SET_SNAT_POLICY_REPLY);
334 }
335
336 static void
337 vl_api_cnat_snat_policy_add_del_exclude_pfx_t_handler (
338   vl_api_cnat_snat_policy_add_del_exclude_pfx_t *mp)
339 {
340   vl_api_cnat_snat_policy_add_del_exclude_pfx_reply_t *rmp;
341   ip_prefix_t pfx;
342   int rv;
343
344   ip_prefix_decode2 (&mp->prefix, &pfx);
345   if (mp->is_add)
346     rv = cnat_snat_policy_add_pfx (&pfx);
347   else
348     rv = cnat_snat_policy_del_pfx (&pfx);
349
350   REPLY_MACRO (VL_API_CNAT_SNAT_POLICY_ADD_DEL_EXCLUDE_PFX_REPLY);
351 }
352
353 static void
354 vl_api_cnat_snat_policy_add_del_if_t_handler (
355   vl_api_cnat_snat_policy_add_del_if_t *mp)
356 {
357   vl_api_cnat_snat_policy_add_del_if_reply_t *rmp;
358   u32 sw_if_index = ntohl (mp->sw_if_index);
359   int rv = 0;
360
361   VALIDATE_SW_IF_INDEX (mp);
362
363   cnat_snat_interface_map_type_t table =
364     (cnat_snat_interface_map_type_t) mp->table;
365
366   rv = cnat_snat_policy_add_del_if (sw_if_index, mp->is_add, table);
367
368   BAD_SW_IF_INDEX_LABEL;
369
370   REPLY_MACRO (VL_API_CNAT_SNAT_POLICY_ADD_DEL_IF_REPLY);
371 }
372
373 #include <cnat/cnat.api.c>
374
375 static clib_error_t *
376 cnat_api_init (vlib_main_t * vm)
377 {
378   /* Ask for a correctly-sized block of API message decode slots */
379   cnat_base_msg_id = setup_message_id_table ();
380
381   return 0;
382 }
383
384 VLIB_INIT_FUNCTION (cnat_api_init);
385
386 VLIB_PLUGIN_REGISTER () = {
387     .version = VPP_BUILD_VER,
388     .description = "CNat Translate",
389 };
390
391 /*
392  * fd.io coding-style-patch-verification: ON
393  *
394  * Local Variables:
395  * eval: (c-set-style "gnu")
396  * End:
397  */