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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <nat/det44/det44.h>
21 #define DET44_EXPECTED_ARGUMENT "expected required argument(s)"
24 det44_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
25 vlib_cli_command_t * cmd)
27 unformat_input_t _line_input, *line_input = &_line_input;
28 ip4_address_t in_addr, out_addr;
29 u32 in_plen, out_plen;
31 clib_error_t *error = 0;
33 if (!unformat_user (input, unformat_line_input, line_input))
34 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
36 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
39 (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
43 (line_input, "out %U/%u", unformat_ip4_address, &out_addr,
46 else if (unformat (line_input, "del"))
50 error = clib_error_return (0, "unknown input '%U'",
51 format_unformat_error, line_input);
56 rv = snat_det_add_map (&in_addr, (u8) in_plen, &out_addr, (u8) out_plen,
61 error = clib_error_return (0, "snat_det_add_map return %d", rv);
66 unformat_free (line_input);
72 det44_show_mappings_command_fn (vlib_main_t * vm,
73 unformat_input_t * input,
74 vlib_cli_command_t * cmd)
76 det44_main_t *dm = &det44_main;
78 vlib_cli_output (vm, "NAT44 deterministic mappings:");
79 pool_foreach (mp, dm->det_maps)
81 vlib_cli_output (vm, " in %U/%d out %U/%d\n",
82 format_ip4_address, &mp->in_addr, mp->in_plen,
83 format_ip4_address, &mp->out_addr, mp->out_plen);
84 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
86 vlib_cli_output (vm, " number of ports per inside host: %d\n",
88 vlib_cli_output (vm, " sessions number: %d\n", mp->ses_num);
94 det44_forward_command_fn (vlib_main_t * vm,
95 unformat_input_t * input, vlib_cli_command_t * cmd)
97 unformat_input_t _line_input, *line_input = &_line_input;
98 ip4_address_t in_addr, out_addr;
101 clib_error_t *error = 0;
103 if (!unformat_user (input, unformat_line_input, line_input))
104 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
106 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
108 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
112 error = clib_error_return (0, "unknown input '%U'",
113 format_unformat_error, line_input);
118 mp = snat_det_map_by_user (&in_addr);
120 vlib_cli_output (vm, "no match");
123 snat_det_forward (mp, &in_addr, &out_addr, &lo_port);
124 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
125 lo_port, lo_port + mp->ports_per_host - 1);
129 unformat_free (line_input);
134 static clib_error_t *
135 det44_reverse_command_fn (vlib_main_t * vm,
136 unformat_input_t * input, vlib_cli_command_t * cmd)
138 unformat_input_t _line_input, *line_input = &_line_input;
139 ip4_address_t in_addr, out_addr;
140 clib_error_t *error = 0;
144 if (!unformat_user (input, unformat_line_input, line_input))
145 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
147 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
150 (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
154 error = clib_error_return (0, "unknown input '%U'",
155 format_unformat_error, line_input);
160 if (out_port < 1024 || out_port > 65535)
162 error = clib_error_return (0, "wrong port, must be <1024-65535>");
166 mp = snat_det_map_by_out (&out_addr);
168 vlib_cli_output (vm, "no match");
171 snat_det_reverse (mp, &out_addr, (u16) out_port, &in_addr);
172 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
176 unformat_free (line_input);
181 static clib_error_t *
182 det44_show_sessions_command_fn (vlib_main_t * vm,
183 unformat_input_t * input,
184 vlib_cli_command_t * cmd)
186 det44_main_t *dm = &det44_main;
187 snat_det_session_t *ses;
189 vlib_cli_output (vm, "NAT44 deterministic sessions:");
190 pool_foreach (mp, dm->det_maps)
193 vec_foreach_index (i, mp->sessions)
195 ses = vec_elt_at_index (mp->sessions, i);
197 vlib_cli_output (vm, " %U", format_det_map_ses, mp, ses, &i);
203 static clib_error_t *
204 det44_close_session_out_fn (vlib_main_t * vm,
205 unformat_input_t * input,
206 vlib_cli_command_t * cmd)
208 unformat_input_t _line_input, *line_input = &_line_input;
209 ip4_address_t out_addr, ext_addr, in_addr;
210 u32 out_port, ext_port;
212 snat_det_session_t *ses;
213 snat_det_out_key_t key;
214 clib_error_t *error = 0;
216 if (!unformat_user (input, unformat_line_input, line_input))
217 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
219 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
221 if (unformat (line_input, "%U:%d %U:%d",
222 unformat_ip4_address, &out_addr, &out_port,
223 unformat_ip4_address, &ext_addr, &ext_port))
227 error = clib_error_return (0, "unknown input '%U'",
228 format_unformat_error, line_input);
233 unformat_free (line_input);
235 mp = snat_det_map_by_out (&out_addr);
237 vlib_cli_output (vm, "no match");
240 snat_det_reverse (mp, &ext_addr, (u16) out_port, &in_addr);
241 key.ext_host_addr = out_addr;
242 key.ext_host_port = ntohs ((u16) ext_port);
243 key.out_port = ntohs ((u16) out_port);
244 ses = snat_det_get_ses_by_out (mp, &out_addr, key.as_u64);
246 vlib_cli_output (vm, "no match");
248 snat_det_ses_close (mp, ses);
252 unformat_free (line_input);
257 static clib_error_t *
258 det44_close_session_in_fn (vlib_main_t * vm,
259 unformat_input_t * input, vlib_cli_command_t * cmd)
261 unformat_input_t _line_input, *line_input = &_line_input;
262 ip4_address_t in_addr, ext_addr;
263 u32 in_port, ext_port;
265 snat_det_session_t *ses;
266 snat_det_out_key_t key;
267 clib_error_t *error = 0;
269 if (!unformat_user (input, unformat_line_input, line_input))
270 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
272 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
274 if (unformat (line_input, "%U:%d %U:%d",
275 unformat_ip4_address, &in_addr, &in_port,
276 unformat_ip4_address, &ext_addr, &ext_port))
280 error = clib_error_return (0, "unknown input '%U'",
281 format_unformat_error, line_input);
286 unformat_free (line_input);
288 mp = snat_det_map_by_user (&in_addr);
290 vlib_cli_output (vm, "no match");
293 key.ext_host_addr = ext_addr;
294 key.ext_host_port = ntohs ((u16) ext_port);
296 snat_det_find_ses_by_in (mp, &in_addr, ntohs ((u16) in_port), key);
298 vlib_cli_output (vm, "no match");
300 snat_det_ses_close (mp, ses);
304 unformat_free (line_input);
309 static clib_error_t *
310 det44_set_timeouts_command_fn (vlib_main_t * vm,
311 unformat_input_t * input,
312 vlib_cli_command_t * cmd)
314 unformat_input_t _line_input, *line_input = &_line_input;
315 nat_timeouts_t timeouts = { 0 };
316 clib_error_t *error = 0;
319 if (!unformat_user (input, unformat_line_input, line_input))
320 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
322 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
324 if (unformat (line_input, "udp %u", &timeouts.udp));
325 else if (unformat (line_input, "tcp established %u",
326 &timeouts.tcp.established));
327 else if (unformat (line_input, "tcp transitory %u",
328 &timeouts.tcp.transitory));
329 else if (unformat (line_input, "icmp %u", &timeouts.icmp));
330 else if (unformat (line_input, "reset"))
334 error = clib_error_return (0, "unknown input '%U'",
335 format_unformat_error, line_input);
342 if (det44_set_timeouts (&timeouts))
344 error = clib_error_return (0, "error configuring timeouts");
348 det44_reset_timeouts ();
350 unformat_free (line_input);
354 static clib_error_t *
355 det44_show_timeouts_command_fn (vlib_main_t * vm,
356 unformat_input_t * input,
357 vlib_cli_command_t * cmd)
359 nat_timeouts_t timeouts;
360 timeouts = det44_get_timeouts ();
361 vlib_cli_output (vm, "udp timeout: %dsec", timeouts.udp);
362 vlib_cli_output (vm, "tcp established timeout: %dsec",
363 timeouts.tcp.established);
364 vlib_cli_output (vm, "tcp transitory timeout: %dsec",
365 timeouts.tcp.transitory);
366 vlib_cli_output (vm, "icmp timeout: %dsec", timeouts.icmp);
370 static clib_error_t *
371 det44_plugin_enable_disable_command_fn (vlib_main_t * vm,
372 unformat_input_t * input,
373 vlib_cli_command_t * cmd)
375 unformat_input_t _line_input, *line_input = &_line_input;
376 u8 enable = 0, is_set = 0;
377 clib_error_t *error = 0;
378 det44_config_t c = { 0 };
380 if (!unformat_user (input, unformat_line_input, line_input))
381 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
383 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
385 if (!is_set && unformat (line_input, "enable"))
387 unformat (line_input, "inside vrf %u", &c.inside_vrf_id);
388 unformat (line_input, "outside vrf %u", &c.outside_vrf_id);
391 else if (!is_set && unformat (line_input, "disable"));
394 error = clib_error_return (0, "unknown input '%U'",
395 format_unformat_error, line_input);
403 if (det44_plugin_enable (c))
404 error = clib_error_return (0, "plugin enable failed");
408 if (det44_plugin_disable ())
409 error = clib_error_return (0, "plugin disable failed");
412 unformat_free (line_input);
422 static clib_error_t *
423 det44_feature_command_fn (vlib_main_t * vm,
424 unformat_input_t * input, vlib_cli_command_t * cmd)
426 unformat_input_t _line_input, *line_input = &_line_input;
427 sw_if_indices_t *sw_if_indices = 0, *p, e;
428 vnet_main_t *vnm = vnet_get_main ();
429 clib_error_t *error = 0;
432 if (!unformat_user (input, unformat_line_input, line_input))
433 return clib_error_return (0, DET44_EXPECTED_ARGUMENT);
435 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
437 if (unformat (line_input, "inside %U", unformat_vnet_sw_interface,
438 vnm, &e.sw_if_index))
441 vec_add1 (sw_if_indices, e);
443 else if (unformat (line_input, "outside %U", unformat_vnet_sw_interface,
444 vnm, &e.sw_if_index))
447 vec_add1 (sw_if_indices, e);
449 else if (unformat (line_input, "del"))
453 error = clib_error_return (0, "unknown input '%U'",
454 format_unformat_error, line_input);
459 vec_foreach (p, sw_if_indices)
461 if (det44_interface_add_del (p->sw_if_index, p->is_inside, is_del))
463 error = clib_error_return (0, "%s %s %U failed",
464 is_del ? "del" : "add",
465 p->is_inside ? "inside" : "outside",
466 format_vnet_sw_if_index_name,
467 vnm, p->sw_if_index);
472 unformat_free (line_input);
473 vec_free (sw_if_indices);
477 static clib_error_t *
478 det44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
479 vlib_cli_command_t * cmd)
481 vnet_main_t *vnm = vnet_get_main ();
482 det44_main_t *dm = &det44_main;
483 det44_interface_t *i;
484 vlib_cli_output (vm, "DET44 interfaces:");
485 pool_foreach (i, dm->interfaces)
487 vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
489 (det44_interface_is_inside(i) &&
490 det44_interface_is_outside(i)) ? "in out" :
491 (det44_interface_is_inside(i) ? "in" : "out"));
498 * @cliexstart{det44 add}
499 * Create bijective mapping of inside address to outside address and port range
500 * pairs, with the purpose of enabling DET44 to reduce logging in CGN
502 * To create mapping between inside network 10.0.0.0/18 and
503 * outside network 1.1.1.0/30 use:
504 * # vpp# det44 add in 10.0.0.0/18 out 1.1.1.0/30
507 VLIB_CLI_COMMAND (det44_map_command, static) = {
509 .short_help = "det44 add in <addr>/<plen> out <addr>/<plen> [del]",
510 .function = det44_map_command_fn,
515 * @cliexpstart{show det44 mappings}
516 * Show DET44 mappings
517 * vpp# show det44 mappings
519 * in 10.0.0.0/24 out 1.1.1.1/32
520 * outside address sharing ratio: 256
521 * number of ports per inside host: 252
525 VLIB_CLI_COMMAND (det44_show_mappings_command, static) = {
526 .path = "show det44 mappings",
527 .short_help = "show det44 mappings",
528 .function = det44_show_mappings_command_fn,
533 * @cliexstart{det44 forward}
534 * Return outside address and port range from inside address for DET44.
535 * To obtain outside address and port of inside host use:
536 * vpp# det44 forward 10.0.0.2
537 * 1.1.1.0:<1054-1068>
540 VLIB_CLI_COMMAND (det44_forward_command, static) = {
541 .path = "det44 forward",
542 .short_help = "det44 forward <addr>",
543 .function = det44_forward_command_fn,
548 * @cliexstart{det44 reverse}
549 * Return inside address from outside address and port for DET44.
550 * To obtain inside host address from outside address and port use:
551 * #vpp det44 reverse 1.1.1.1:1276
555 VLIB_CLI_COMMAND (det44_reverse_command, static) = {
556 .path = "det44 reverse",
557 .short_help = "det44 reverse <addr>:<port>",
558 .function = det44_reverse_command_fn,
563 * @cliexstart{show det44 sessions}
564 * Show DET44 sessions.
565 * vpp# show det44 sessions
567 * in 10.0.0.3:3005 out 1.1.1.2:1146 external host 172.16.1.2:3006 state: udp-active expire: 306
568 * in 10.0.0.3:3000 out 1.1.1.2:1141 external host 172.16.1.2:3001 state: udp-active expire: 306
569 * in 10.0.0.4:3005 out 1.1.1.2:1177 external host 172.16.1.2:3006 state: udp-active expire: 306
572 VLIB_CLI_COMMAND (det44_show_sessions_command, static) = {
573 .path = "show det44 sessions",
574 .short_help = "show det44 sessions",
575 .function = det44_show_sessions_command_fn,
580 * @cliexstart{det44 close session out}
581 * Close session using outside ip address and port
582 * and external ip address and port, use:
583 * vpp# det44 close session out 1.1.1.1:1276 2.2.2.2:2387
586 VLIB_CLI_COMMAND (det44_close_sesion_out_command, static) = {
587 .path = "det44 close session out",
588 .short_help = "det44 close session out "
589 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
590 .function = det44_close_session_out_fn,
595 * @cliexstart{det44 deterministic close session in}
596 * Close session using inside ip address and port
597 * and external ip address and port, use:
598 * vpp# det44 close session in 3.3.3.3:3487 2.2.2.2:2387
601 VLIB_CLI_COMMAND (det44_close_session_in_command, static) = {
602 .path = "det44 close session in",
603 .short_help = "det44 close session in "
604 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
605 .function = det44_close_session_in_fn,
610 * @cliexstart{set det44 timeout}
611 * Set values of timeouts for DET44 sessions (in seconds), use:
612 * vpp# set det44 timeouts udp 120 tcp established 7500 tcp transitory 250 icmp 90
613 * To reset default values use:
614 * vpp# set det44 timeouts reset
617 VLIB_CLI_COMMAND (det44_set_timeouts_command, static) =
619 .path = "set det44 timeouts",
620 .short_help = "set det44 timeouts <[udp <sec>] [tcp established <sec>] "
621 "[tcp transitory <sec>] [icmp <sec>]|reset>",
622 .function = det44_set_timeouts_command_fn,
627 * @cliexstart{show det44 timeouts}
628 * Show values of timeouts for DET44 sessions.
629 * vpp# show det44 timeouts
630 * udp timeout: 300sec
631 * tcp-established timeout: 7440sec
632 * tcp-transitory timeout: 240sec
633 * icmp timeout: 60sec
636 VLIB_CLI_COMMAND (det44_show_timeouts_command, static) =
638 .path = "show det44 timeouts",
639 .short_help = "show det44 timeouts",
640 .function = det44_show_timeouts_command_fn,
645 * @cliexstart{det44 plugin}
646 * Enable/disable DET44 plugin.
649 VLIB_CLI_COMMAND (det44_plugin_enable_disable_command, static) =
651 .path = "det44 plugin",
652 .short_help = "det44 plugin <enable [inside vrf] [outside vrf]|disable>",
653 .function = det44_plugin_enable_disable_command_fn,
658 * @cliexstart{set interface det44}
659 * Enable/disable DET44 feature on the interface.
660 * To enable DET44 feature with local network interface use:
661 * vpp# set interface det44 inside GigabitEthernet0/8/0
662 * To enable DET44 feature with external network interface use:
663 * vpp# set interface det44 outside GigabitEthernet0/a/0
666 VLIB_CLI_COMMAND (det44_feature_command, static) =
668 .path = "set interface det44",
669 .short_help = "set interface det44 inside <intfc> outside <intfc> [del]",
670 .function = det44_feature_command_fn,
675 * @cliexstart{show det44 interfaces}
676 * Show interfaces with DET44 feature.
677 * vpp# show det44 interfaces
679 * GigabitEthernet0/8/0 in
680 * GigabitEthernet0/a/0 out
683 VLIB_CLI_COMMAND (det44_show_interfaces_command, static) =
685 .path = "show det44 interfaces",
686 .short_help = "show det44 interfaces",
687 .function = det44_show_interfaces_command_fn,
691 * fd.io coding-style-patch-verification: ON
694 * eval: (c-set-style "gnu")