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