Line data Source code
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 : #include <vnet/ip/ip.h>
17 : #include <cnat/cnat_snat_policy.h>
18 : #include <cnat/cnat_translation.h>
19 :
20 : cnat_snat_policy_main_t cnat_snat_policy_main;
21 :
22 : uword
23 0 : unformat_cnat_snat_interface_map_type (unformat_input_t *input, va_list *args)
24 : {
25 0 : u8 *a = va_arg (*args, u8 *);
26 0 : if (unformat (input, "include-v4"))
27 0 : *a = CNAT_SNAT_IF_MAP_INCLUDE_V4;
28 0 : else if (unformat (input, "include-v6"))
29 0 : *a = CNAT_SNAT_IF_MAP_INCLUDE_V6;
30 0 : else if (unformat (input, "k8s"))
31 0 : *a = CNAT_SNAT_IF_MAP_INCLUDE_POD;
32 0 : else if (unformat (input, "host"))
33 0 : *a = CNAT_SNAT_IF_MAP_INCLUDE_HOST;
34 : else
35 0 : return 0;
36 0 : return 1;
37 : }
38 :
39 : u8 *
40 0 : format_cnat_snat_interface_map_type (u8 *s, va_list *args)
41 : {
42 0 : cnat_snat_interface_map_type_t mtype = va_arg (*args, int);
43 0 : switch (mtype)
44 : {
45 0 : case CNAT_SNAT_IF_MAP_INCLUDE_V4:
46 0 : s = format (s, "Included v4");
47 0 : break;
48 0 : case CNAT_SNAT_IF_MAP_INCLUDE_V6:
49 0 : s = format (s, "Included v6");
50 0 : break;
51 0 : case CNAT_SNAT_IF_MAP_INCLUDE_POD:
52 0 : s = format (s, "k8s pod");
53 0 : break;
54 0 : case CNAT_SNAT_IF_MAP_INCLUDE_HOST:
55 0 : s = format (s, "k8s host");
56 0 : break;
57 0 : default:
58 0 : s = format (s, "(unknown)");
59 0 : break;
60 : }
61 0 : return (s);
62 : }
63 :
64 : u8 *
65 0 : format_cnat_snat_prefix (u8 *s, va_list *args)
66 : {
67 0 : clib_bihash_kv_24_8_t *kv = va_arg (*args, clib_bihash_kv_24_8_t *);
68 0 : CLIB_UNUSED (int verbose) = va_arg (*args, int);
69 0 : u32 af = kv->key[2] >> 32;
70 0 : u32 len = kv->key[2] & 0xffffffff;
71 0 : if (AF_IP4 == af)
72 0 : s = format (s, "%U/%d", format_ip4_address, &kv->key[0], len);
73 : else
74 0 : s = format (s, "%U/%d", format_ip6_address, &kv->key[0], len);
75 0 : return (s);
76 : }
77 :
78 : static void
79 8 : cnat_compute_prefix_lengths_in_search_order (
80 : cnat_snat_exclude_pfx_table_t *table, ip_address_family_t af)
81 : {
82 : int i;
83 8 : vec_reset_length (table->meta[af].prefix_lengths_in_search_order);
84 : /* Note: bitmap reversed so this is in fact a longest prefix match */
85 12 : clib_bitmap_foreach (i, table->meta[af].non_empty_dst_address_length_bitmap)
86 : {
87 4 : int dst_address_length = 128 - i;
88 4 : vec_add1 (table->meta[af].prefix_lengths_in_search_order,
89 : dst_address_length);
90 : }
91 8 : }
92 :
93 : int
94 24 : cnat_snat_policy_add_del_if (u32 sw_if_index, u8 is_add,
95 : cnat_snat_interface_map_type_t table)
96 : {
97 24 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
98 :
99 24 : if (table >= ARRAY_LEN (cpm->interface_maps))
100 0 : return VNET_API_ERROR_INVALID_VALUE;
101 :
102 24 : clib_bitmap_t **map = &cpm->interface_maps[table];
103 :
104 24 : *map = clib_bitmap_set (*map, sw_if_index, is_add);
105 24 : return 0;
106 : }
107 :
108 : static clib_error_t *
109 0 : cnat_snat_policy_add_del_if_command_fn (vlib_main_t *vm,
110 : unformat_input_t *input,
111 : vlib_cli_command_t *cmd)
112 : {
113 0 : vnet_main_t *vnm = vnet_get_main ();
114 0 : int is_add = 1;
115 0 : u32 sw_if_index = ~0;
116 0 : u32 table = 0;
117 : int rv;
118 :
119 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
120 : {
121 0 : if (unformat (input, "del"))
122 0 : is_add = 0;
123 0 : else if (unformat (input, "table %U",
124 : unformat_cnat_snat_interface_map_type, &table))
125 : ;
126 0 : else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
127 : &sw_if_index))
128 : ;
129 : else
130 0 : return clib_error_return (0, "unknown input '%U'",
131 : format_unformat_error, input);
132 : }
133 :
134 0 : if (sw_if_index == ~0)
135 0 : return clib_error_return (0, "Interface not specified");
136 :
137 0 : rv = cnat_snat_policy_add_del_if (sw_if_index, is_add, table);
138 :
139 0 : if (rv)
140 0 : return clib_error_return (0, "Error %d", rv);
141 :
142 0 : return NULL;
143 : }
144 :
145 257065 : VLIB_CLI_COMMAND (cnat_snat_policy_add_del_if_command, static) = {
146 : .path = "set cnat snat-policy if",
147 : .short_help = "set cnat snat-policy if [del]"
148 : "[table [include-v4 include-v6 k8s]] [interface]",
149 : .function = cnat_snat_policy_add_del_if_command_fn,
150 : };
151 :
152 : int
153 4 : cnat_snat_policy_add_pfx (ip_prefix_t *pfx)
154 : {
155 : /* All packets destined to this prefix won't be source-NAT-ed */
156 4 : cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
157 : clib_bihash_kv_24_8_t kv;
158 : ip6_address_t *mask;
159 4 : u64 af = ip_prefix_version (pfx);
160 : ;
161 :
162 4 : mask = &table->ip_masks[pfx->len];
163 4 : if (AF_IP4 == af)
164 : {
165 2 : kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
166 2 : kv.key[1] = 0;
167 : }
168 : else
169 : {
170 2 : kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
171 2 : kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
172 : }
173 4 : kv.key[2] = ((u64) af << 32) | pfx->len;
174 4 : clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 1 /* is_add */);
175 :
176 4 : table->meta[af].dst_address_length_refcounts[pfx->len]++;
177 8 : table->meta[af].non_empty_dst_address_length_bitmap = clib_bitmap_set (
178 4 : table->meta[af].non_empty_dst_address_length_bitmap, 128 - pfx->len, 1);
179 4 : cnat_compute_prefix_lengths_in_search_order (table, af);
180 4 : return 0;
181 : }
182 :
183 : int
184 4 : cnat_snat_policy_del_pfx (ip_prefix_t *pfx)
185 : {
186 4 : cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
187 : clib_bihash_kv_24_8_t kv, val;
188 : ip6_address_t *mask;
189 4 : u64 af = ip_prefix_version (pfx);
190 : ;
191 :
192 4 : mask = &table->ip_masks[pfx->len];
193 4 : if (AF_IP4 == af)
194 : {
195 2 : kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
196 2 : kv.key[1] = 0;
197 : }
198 : else
199 : {
200 2 : kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
201 2 : kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
202 : }
203 4 : kv.key[2] = ((u64) af << 32) | pfx->len;
204 :
205 4 : if (clib_bihash_search_24_8 (&table->ip_hash, &kv, &val))
206 : {
207 0 : return 1;
208 : }
209 4 : clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 0 /* is_add */);
210 : /* refcount accounting */
211 4 : ASSERT (table->meta[af].dst_address_length_refcounts[pfx->len] > 0);
212 4 : if (--table->meta[af].dst_address_length_refcounts[pfx->len] == 0)
213 : {
214 4 : table->meta[af].non_empty_dst_address_length_bitmap =
215 4 : clib_bitmap_set (table->meta[af].non_empty_dst_address_length_bitmap,
216 4 : 128 - pfx->len, 0);
217 4 : cnat_compute_prefix_lengths_in_search_order (table, af);
218 : }
219 4 : return 0;
220 : }
221 :
222 : int
223 140 : cnat_search_snat_prefix (ip46_address_t *addr, ip_address_family_t af)
224 : {
225 : /* Returns 0 if addr matches any of the listed prefixes */
226 140 : cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
227 : clib_bihash_kv_24_8_t kv, val;
228 : int i, n_p, rv;
229 140 : n_p = vec_len (table->meta[af].prefix_lengths_in_search_order);
230 140 : if (AF_IP4 == af)
231 : {
232 35 : kv.key[0] = addr->ip4.as_u32;
233 35 : kv.key[1] = 0;
234 : }
235 : else
236 : {
237 105 : kv.key[0] = addr->as_u64[0];
238 105 : kv.key[1] = addr->as_u64[1];
239 : }
240 :
241 : /*
242 : * start search from a mask length same length or shorter.
243 : * we don't want matches longer than the mask passed
244 : */
245 140 : i = 0;
246 140 : for (; i < n_p; i++)
247 : {
248 120 : int dst_address_length =
249 120 : table->meta[af].prefix_lengths_in_search_order[i];
250 120 : ip6_address_t *mask = &table->ip_masks[dst_address_length];
251 :
252 120 : ASSERT (dst_address_length >= 0 && dst_address_length <= 128);
253 : /* As lengths are decreasing, masks are increasingly specific. */
254 120 : kv.key[0] &= mask->as_u64[0];
255 120 : kv.key[1] &= mask->as_u64[1];
256 120 : kv.key[2] = ((u64) af << 32) | dst_address_length;
257 120 : rv = clib_bihash_search_inline_2_24_8 (&table->ip_hash, &kv, &val);
258 120 : if (rv == 0)
259 120 : return 0;
260 : }
261 20 : return -1;
262 : }
263 :
264 : static_always_inline int
265 140 : cnat_snat_policy_interface_enabled (u32 sw_if_index, ip_address_family_t af)
266 : {
267 140 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
268 140 : return clib_bitmap_get (cpm->interface_maps[af], sw_if_index);
269 : }
270 :
271 : int
272 0 : cnat_snat_policy_none (vlib_buffer_t *b, cnat_session_t *session)
273 : {
274 : /* srcNAT everything by default */
275 0 : return 1;
276 : }
277 :
278 : int
279 140 : cnat_snat_policy_if_pfx (vlib_buffer_t *b, cnat_session_t *session)
280 : {
281 140 : ip46_address_t *dst_addr = &session->key.cs_ip[VLIB_TX];
282 140 : u32 in_if = vnet_buffer (b)->sw_if_index[VLIB_RX];
283 140 : ip_address_family_t af = session->key.cs_af;
284 :
285 : /* source nat for outgoing connections */
286 140 : if (cnat_snat_policy_interface_enabled (in_if, af))
287 140 : if (cnat_search_snat_prefix (dst_addr, af))
288 : /* Destination is not in the prefixes that don't require snat */
289 20 : return 1;
290 120 : return 0;
291 : }
292 :
293 : int
294 0 : cnat_snat_policy_k8s (vlib_buffer_t *b, cnat_session_t *session)
295 : {
296 0 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
297 0 : ip_address_family_t af = session->key.cs_af;
298 :
299 0 : ip46_address_t *src_addr = &session->key.cs_ip[VLIB_RX];
300 0 : ip46_address_t *dst_addr = &session->key.cs_ip[VLIB_TX];
301 0 : u32 in_if = vnet_buffer (b)->sw_if_index[VLIB_RX];
302 0 : u32 out_if = vnet_buffer (b)->sw_if_index[VLIB_TX];
303 :
304 : /* we should never snat traffic that we punt to the host, pass traffic as it
305 : * is for us */
306 0 : if (clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_HOST],
307 : out_if))
308 : {
309 0 : return 0;
310 : }
311 :
312 : /* source nat for outgoing connections */
313 0 : if (cnat_snat_policy_interface_enabled (in_if, af))
314 0 : if (cnat_search_snat_prefix (dst_addr, af))
315 : /* Destination is not in the prefixes that don't require snat */
316 0 : return 1;
317 :
318 : /* source nat for translations that come from the outside:
319 : src not not a pod interface, dst not a pod interface */
320 0 : if (!clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
321 0 : in_if) &&
322 0 : !clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
323 : out_if))
324 : {
325 0 : if (AF_IP6 == af &&
326 0 : ip6_address_is_equal (&src_addr->ip6,
327 0 : &ip_addr_v6 (&cpm->snat_ip6.ce_ip)))
328 0 : return 0;
329 0 : if (AF_IP4 == af &&
330 0 : ip4_address_is_equal (&src_addr->ip4,
331 0 : &ip_addr_v4 (&cpm->snat_ip4.ce_ip)))
332 0 : return 0;
333 0 : return 1;
334 : }
335 :
336 : /* handle the case where a container is connecting to itself via a service */
337 0 : if (ip46_address_is_equal (src_addr, dst_addr))
338 0 : return 1;
339 :
340 0 : return 0;
341 : }
342 :
343 : void
344 6 : cnat_set_snat (ip4_address_t *ip4, ip6_address_t *ip6, u32 sw_if_index)
345 : {
346 6 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
347 :
348 6 : cnat_lazy_init ();
349 :
350 6 : cnat_translation_unwatch_addr (INDEX_INVALID, CNAT_RESOLV_ADDR_SNAT);
351 :
352 6 : ip_address_set (&cpm->snat_ip4.ce_ip, ip4, AF_IP4);
353 6 : ip_address_set (&cpm->snat_ip6.ce_ip, ip6, AF_IP6);
354 6 : cpm->snat_ip4.ce_sw_if_index = sw_if_index;
355 6 : cpm->snat_ip6.ce_sw_if_index = sw_if_index;
356 :
357 6 : cnat_resolve_ep (&cpm->snat_ip4);
358 6 : cnat_resolve_ep (&cpm->snat_ip6);
359 6 : cnat_translation_watch_addr (INDEX_INVALID, 0, &cpm->snat_ip4,
360 : CNAT_RESOLV_ADDR_SNAT);
361 6 : cnat_translation_watch_addr (INDEX_INVALID, 0, &cpm->snat_ip6,
362 : CNAT_RESOLV_ADDR_SNAT);
363 6 : }
364 :
365 : static clib_error_t *
366 0 : cnat_set_snat_cli (vlib_main_t *vm, unformat_input_t *input,
367 : vlib_cli_command_t *cmd)
368 : {
369 0 : unformat_input_t _line_input, *line_input = &_line_input;
370 0 : vnet_main_t *vnm = vnet_get_main ();
371 0 : ip4_address_t ip4 = { { 0 } };
372 0 : ip6_address_t ip6 = { { 0 } };
373 0 : clib_error_t *e = 0;
374 0 : u32 sw_if_index = INDEX_INVALID;
375 :
376 0 : cnat_lazy_init ();
377 :
378 : /* Get a line of input. */
379 0 : if (!unformat_user (input, unformat_line_input, line_input))
380 0 : return 0;
381 :
382 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
383 : {
384 0 : if (unformat_user (line_input, unformat_ip4_address, &ip4))
385 : ;
386 0 : else if (unformat_user (line_input, unformat_ip6_address, &ip6))
387 : ;
388 0 : else if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
389 : &sw_if_index))
390 : ;
391 : else
392 : {
393 0 : e = clib_error_return (0, "unknown input '%U'",
394 : format_unformat_error, input);
395 0 : goto done;
396 : }
397 : }
398 :
399 0 : cnat_set_snat (&ip4, &ip6, sw_if_index);
400 :
401 0 : done:
402 0 : unformat_free (line_input);
403 :
404 0 : return (e);
405 : }
406 :
407 257065 : VLIB_CLI_COMMAND (cnat_set_snat_command, static) = {
408 : .path = "set cnat snat-policy addr",
409 : .short_help =
410 : "set cnat snat-policy addr [<ip4-address>][<ip6-address>][sw_if_index]",
411 : .function = cnat_set_snat_cli,
412 : };
413 :
414 : static clib_error_t *
415 0 : cnat_snat_policy_add_del_pfx_command_fn (vlib_main_t *vm,
416 : unformat_input_t *input,
417 : vlib_cli_command_t *cmd)
418 : {
419 : ip_prefix_t pfx;
420 0 : u8 is_add = 1;
421 : int rv;
422 :
423 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
424 : {
425 0 : if (unformat (input, "%U", unformat_ip_prefix, &pfx))
426 : ;
427 0 : else if (unformat (input, "del"))
428 0 : is_add = 0;
429 : else
430 0 : return (clib_error_return (0, "unknown input '%U'",
431 : format_unformat_error, input));
432 : }
433 :
434 0 : if (is_add)
435 0 : rv = cnat_snat_policy_add_pfx (&pfx);
436 : else
437 0 : rv = cnat_snat_policy_del_pfx (&pfx);
438 :
439 0 : if (rv)
440 0 : return (clib_error_return (0, "error %d", rv, input));
441 :
442 0 : return (NULL);
443 : }
444 :
445 257065 : VLIB_CLI_COMMAND (cnat_snat_policy_add_del_pfx_command, static) = {
446 : .path = "set cnat snat-policy prefix",
447 : .short_help = "set cnat snat-policy prefix [del] [prefix]",
448 : .function = cnat_snat_policy_add_del_pfx_command_fn,
449 : };
450 :
451 : static clib_error_t *
452 0 : cnat_show_snat (vlib_main_t *vm, unformat_input_t *input,
453 : vlib_cli_command_t *cmd)
454 : {
455 0 : cnat_snat_exclude_pfx_table_t *excluded_pfx =
456 : &cnat_snat_policy_main.excluded_pfx;
457 0 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
458 0 : vnet_main_t *vnm = vnet_get_main ();
459 : u32 sw_if_index;
460 :
461 0 : vlib_cli_output (vm, "Source NAT\n ip4: %U\n ip6: %U\n\n",
462 : format_cnat_endpoint, &cpm->snat_ip4, format_cnat_endpoint,
463 : &cpm->snat_ip6);
464 0 : vlib_cli_output (vm, "Excluded prefixes:\n %U\n", format_bihash_24_8,
465 : &excluded_pfx->ip_hash, 1);
466 :
467 0 : for (int i = 0; i < CNAT_N_SNAT_IF_MAP; i++)
468 : {
469 0 : vlib_cli_output (vm, "\n%U interfaces:\n",
470 : format_cnat_snat_interface_map_type, i);
471 0 : clib_bitmap_foreach (sw_if_index, cpm->interface_maps[i])
472 0 : vlib_cli_output (vm, " %U\n", format_vnet_sw_if_index_name, vnm,
473 : sw_if_index);
474 : }
475 :
476 0 : return (NULL);
477 : }
478 :
479 257065 : VLIB_CLI_COMMAND (cnat_show_snat_command, static) = {
480 : .path = "show cnat snat-policy",
481 : .short_help = "show cnat snat-policy",
482 : .function = cnat_show_snat,
483 : };
484 :
485 : int
486 4 : cnat_set_snat_policy (cnat_snat_policy_type_t policy)
487 : {
488 4 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
489 4 : switch (policy)
490 : {
491 0 : case CNAT_SNAT_POLICY_NONE:
492 0 : cpm->snat_policy = cnat_snat_policy_none;
493 0 : break;
494 4 : case CNAT_SNAT_POLICY_IF_PFX:
495 4 : cpm->snat_policy = cnat_snat_policy_if_pfx;
496 4 : break;
497 0 : case CNAT_SNAT_POLICY_K8S:
498 0 : cpm->snat_policy = cnat_snat_policy_k8s;
499 0 : break;
500 0 : default:
501 0 : return 1;
502 : }
503 4 : return 0;
504 : }
505 :
506 : static clib_error_t *
507 0 : cnat_snat_policy_set_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
508 : vlib_cli_command_t *cmd)
509 : {
510 0 : cnat_snat_policy_type_t policy = CNAT_SNAT_POLICY_NONE;
511 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
512 : {
513 0 : if (unformat (input, "none"))
514 : ;
515 0 : else if (unformat (input, "if-pfx"))
516 0 : policy = CNAT_SNAT_POLICY_IF_PFX;
517 0 : else if (unformat (input, "k8s"))
518 0 : policy = CNAT_SNAT_POLICY_K8S;
519 : else
520 0 : return clib_error_return (0, "unknown input '%U'",
521 : format_unformat_error, input);
522 : }
523 :
524 0 : cnat_set_snat_policy (policy);
525 0 : return NULL;
526 : }
527 :
528 257065 : VLIB_CLI_COMMAND (cnat_snat_policy_set_cmd, static) = {
529 : .path = "set cnat snat-policy",
530 : .short_help = "set cnat snat-policy [none][if-pfx][k8s]",
531 : .function = cnat_snat_policy_set_cmd_fn,
532 : };
533 :
534 : static void
535 8 : cnat_if_addr_add_del_snat_cb (addr_resolution_t *ar, ip_address_t *address,
536 : u8 is_del)
537 : {
538 8 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
539 : cnat_endpoint_t *ep;
540 :
541 8 : ep = AF_IP4 == ar->af ? &cpm->snat_ip4 : &cpm->snat_ip6;
542 :
543 8 : if (!is_del && ep->ce_flags & CNAT_EP_FLAG_RESOLVED)
544 2 : return;
545 :
546 6 : if (is_del)
547 : {
548 4 : ep->ce_flags &= ~CNAT_EP_FLAG_RESOLVED;
549 : /* Are there remaining addresses ? */
550 4 : if (0 == cnat_resolve_addr (ar->sw_if_index, ar->af, address))
551 2 : is_del = 0;
552 : }
553 :
554 6 : if (!is_del)
555 : {
556 4 : ip_address_copy (&ep->ce_ip, address);
557 4 : ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
558 : }
559 : }
560 :
561 : static clib_error_t *
562 575 : cnat_snat_init (vlib_main_t *vm)
563 : {
564 575 : cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
565 575 : cnat_main_t *cm = &cnat_main;
566 575 : cnat_snat_exclude_pfx_table_t *excluded_pfx = &cpm->excluded_pfx;
567 :
568 : int i;
569 74750 : for (i = 0; i < ARRAY_LEN (excluded_pfx->ip_masks); i++)
570 : {
571 : u32 j, i0, i1;
572 :
573 74175 : i0 = i / 32;
574 74175 : i1 = i % 32;
575 :
576 186875 : for (j = 0; j < i0; j++)
577 112700 : excluded_pfx->ip_masks[i].as_u32[j] = ~0;
578 :
579 74175 : if (i1)
580 71300 : excluded_pfx->ip_masks[i].as_u32[i0] =
581 71300 : clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
582 : }
583 575 : clib_bihash_init_24_8 (&excluded_pfx->ip_hash, "snat prefixes",
584 : cm->snat_hash_buckets, cm->snat_hash_memory);
585 575 : clib_bihash_set_kvp_format_fn_24_8 (&excluded_pfx->ip_hash,
586 : format_cnat_snat_prefix);
587 :
588 2875 : for (int i = 0; i < CNAT_N_SNAT_IF_MAP; i++)
589 2300 : clib_bitmap_validate (cpm->interface_maps[i], cm->snat_if_map_length);
590 :
591 575 : cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_SNAT,
592 : cnat_if_addr_add_del_snat_cb);
593 :
594 575 : cpm->snat_policy = cnat_snat_policy_none;
595 :
596 575 : return (NULL);
597 : }
598 :
599 3455 : VLIB_INIT_FUNCTION (cnat_snat_init);
600 :
601 : /*
602 : * fd.io coding-style-patch-verification: ON
603 : *
604 : * Local Variables:
605 : * eval: (c-set-style "gnu")
606 : * End:
607 : */
|