-VLIB_CLI_COMMAND (add_address_command, static) = {
- .path = "nat44 add address",
- .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
- "[tenant-vrf <vrf-id>] [twice-nat] [del]",
- .function = add_address_command_fn,
-};
-
-static clib_error_t *
-snat_feature_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- vnet_main_t * vnm = vnet_get_main();
- clib_error_t * error = 0;
- u32 sw_if_index;
- u32 * inside_sw_if_indices = 0;
- u32 * outside_sw_if_indices = 0;
- u8 is_output_feature = 0;
- int is_del = 0;
- int i;
-
- sw_if_index = ~0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
- vnm, &sw_if_index))
- vec_add1 (inside_sw_if_indices, sw_if_index);
- else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
- vnm, &sw_if_index))
- vec_add1 (outside_sw_if_indices, sw_if_index);
- else if (unformat (line_input, "output-feature"))
- is_output_feature = 1;
- else if (unformat (line_input, "del"))
- is_del = 1;
- else
- {
- error = clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (vec_len (inside_sw_if_indices))
- {
- for (i = 0; i < vec_len(inside_sw_if_indices); i++)
- {
- sw_if_index = inside_sw_if_indices[i];
- if (is_output_feature)
- {
- if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
- {
- error = clib_error_return (0, "%s %U failed",
- is_del ? "del" : "add",
- format_vnet_sw_interface_name, vnm,
- vnet_get_sw_interface (vnm,
- sw_if_index));
- goto done;
- }
- }
- else
- {
- if (snat_interface_add_del (sw_if_index, 1, is_del))
- {
- error = clib_error_return (0, "%s %U failed",
- is_del ? "del" : "add",
- format_vnet_sw_interface_name, vnm,
- vnet_get_sw_interface (vnm,
- sw_if_index));
- goto done;
- }
- }
- }
- }
-
- if (vec_len (outside_sw_if_indices))
- {
- for (i = 0; i < vec_len(outside_sw_if_indices); i++)
- {
- sw_if_index = outside_sw_if_indices[i];
- if (is_output_feature)
- {
- if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
- {
- error = clib_error_return (0, "%s %U failed",
- is_del ? "del" : "add",
- format_vnet_sw_interface_name, vnm,
- vnet_get_sw_interface (vnm,
- sw_if_index));
- goto done;
- }
- }
- else
- {
- if (snat_interface_add_del (sw_if_index, 0, is_del))
- {
- error = clib_error_return (0, "%s %U failed",
- is_del ? "del" : "add",
- format_vnet_sw_interface_name, vnm,
- vnet_get_sw_interface (vnm,
- sw_if_index));
- goto done;
- }
- }
- }
- }
-
-done:
- unformat_free (line_input);
- vec_free (inside_sw_if_indices);
- vec_free (outside_sw_if_indices);
-
- return error;
-}
-
-VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
- .path = "set interface nat44",
- .function = snat_feature_command_fn,
- .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
- "[del]",
-};
-
-uword
-unformat_snat_protocol (unformat_input_t * input, va_list * args)
-{
- u32 *r = va_arg (*args, u32 *);
-
- if (0);
-#define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
- foreach_snat_protocol
-#undef _
- else
- return 0;
- return 1;
-}
-
-u8 *
-format_snat_protocol (u8 * s, va_list * args)
-{
- u32 i = va_arg (*args, u32);
- u8 *t = 0;
-
- switch (i)
- {
-#define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
- foreach_snat_protocol
-#undef _
- default:
- s = format (s, "unknown");
- return s;
- }
- s = format (s, "%s", t);
- return s;
-}
-
-static clib_error_t *
-add_static_mapping_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- clib_error_t * error = 0;
- ip4_address_t l_addr, e_addr;
- u32 l_port = 0, e_port = 0, vrf_id = ~0;
- int is_add = 1;
- int addr_only = 1;
- u32 sw_if_index = ~0;
- vnet_main_t * vnm = vnet_get_main();
- int rv;
- snat_protocol_t proto = ~0;
- u8 proto_set = 0;
- u8 twice_nat = 0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
- &l_port))
- addr_only = 0;
- else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
- ;
- else if (unformat (line_input, "external %U %u", unformat_ip4_address,
- &e_addr, &e_port))
- addr_only = 0;
- else if (unformat (line_input, "external %U", unformat_ip4_address,
- &e_addr))
- ;
- else if (unformat (line_input, "external %U %u",
- unformat_vnet_sw_interface, vnm, &sw_if_index,
- &e_port))
- addr_only = 0;
-
- else if (unformat (line_input, "external %U",
- unformat_vnet_sw_interface, vnm, &sw_if_index))
- ;
- else if (unformat (line_input, "vrf %u", &vrf_id))
- ;
- else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
- proto_set = 1;
- else if (unformat (line_input, "twice-nat"))
- twice_nat = 1;
- else if (unformat (line_input, "del"))
- is_add = 0;
- else
- {
- error = clib_error_return (0, "unknown input: '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (twice_nat && addr_only)
- {
- error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
- goto done;
- }
-
- if (!addr_only && !proto_set)
- {
- error = clib_error_return (0, "missing protocol");
- goto done;
- }
-
- rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
- vrf_id, addr_only, sw_if_index, proto, is_add,
- twice_nat);
-
- switch (rv)
- {
- case VNET_API_ERROR_INVALID_VALUE:
- error = clib_error_return (0, "External port already in use.");
- goto done;
- case VNET_API_ERROR_NO_SUCH_ENTRY:
- if (is_add)
- error = clib_error_return (0, "External addres must be allocated.");
- else
- error = clib_error_return (0, "Mapping not exist.");
- goto done;
- case VNET_API_ERROR_NO_SUCH_FIB:
- error = clib_error_return (0, "No such VRF id.");
- goto done;
- case VNET_API_ERROR_VALUE_EXIST:
- error = clib_error_return (0, "Mapping already exist.");
- goto done;
- default:
- break;
- }
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * @cliexpar
- * @cliexstart{snat add static mapping}
- * Static mapping allows hosts on the external network to initiate connection
- * to to the local network host.
- * To create static mapping between local host address 10.0.0.3 port 6303 and
- * external address 4.4.4.4 port 3606 for TCP protocol use:
- * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
- * If not runnig "static mapping only" NAT plugin mode use before:
- * vpp# nat44 add address 4.4.4.4
- * To create static mapping between local and external address use:
- * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
- .path = "nat44 add static mapping",
- .function = add_static_mapping_command_fn,
- .short_help =
- "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
- "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
-};
-
-static clib_error_t *
-add_identity_mapping_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- clib_error_t * error = 0;
- ip4_address_t addr;
- u32 port = 0, vrf_id = ~0;
- int is_add = 1;
- int addr_only = 1;
- u32 sw_if_index = ~0;
- vnet_main_t * vnm = vnet_get_main();
- int rv;
- snat_protocol_t proto;
-
- addr.as_u32 = 0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "%U", unformat_ip4_address, &addr))
- ;
- else if (unformat (line_input, "external %U",
- unformat_vnet_sw_interface, vnm, &sw_if_index))
- ;
- else if (unformat (line_input, "vrf %u", &vrf_id))
- ;
- else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
- &port))
- addr_only = 0;
- else if (unformat (line_input, "del"))
- is_add = 0;
- else
- {
- error = clib_error_return (0, "unknown input: '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
- vrf_id, addr_only, sw_if_index, proto, is_add,
- 0);
-
- switch (rv)
- {
- case VNET_API_ERROR_INVALID_VALUE:
- error = clib_error_return (0, "External port already in use.");
- goto done;
- case VNET_API_ERROR_NO_SUCH_ENTRY:
- if (is_add)
- error = clib_error_return (0, "External addres must be allocated.");
- else
- error = clib_error_return (0, "Mapping not exist.");
- goto done;
- case VNET_API_ERROR_NO_SUCH_FIB:
- error = clib_error_return (0, "No such VRF id.");
- goto done;
- case VNET_API_ERROR_VALUE_EXIST:
- error = clib_error_return (0, "Mapping already exist.");
- goto done;
- default:
- break;
- }
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * @cliexpar
- * @cliexstart{snat add identity mapping}
- * Identity mapping translate an IP address to itself.
- * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
- * use:
- * vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
- * To create identity mapping for address 10.0.0.3 use:
- * vpp# nat44 add identity mapping 10.0.0.3
- * To create identity mapping for DHCP addressed interface use:
- * vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
- .path = "nat44 add identity mapping",
- .function = add_identity_mapping_command_fn,
- .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
- "[<protocol> <port>] [vrf <table-id>] [del]",
-};
-
-static clib_error_t *
-add_lb_static_mapping_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- clib_error_t * error = 0;
- ip4_address_t l_addr, e_addr;
- u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
- int is_add = 1;
- int rv;
- snat_protocol_t proto;
- u8 proto_set = 0;
- nat44_lb_addr_port_t *locals = 0, local;
- u8 twice_nat = 0;
- u8 out2in_only = 0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "local %U:%u probability %u",
- unformat_ip4_address, &l_addr, &l_port, &probability))
- {
- memset (&local, 0, sizeof (local));
- local.addr = l_addr;
- local.port = (u16) l_port;
- local.probability = (u8) probability;
- vec_add1 (locals, local);
- }
- else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
- &e_addr, &e_port))
- ;
- else if (unformat (line_input, "vrf %u", &vrf_id))
- ;
- else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
- &proto))
- proto_set = 1;
- else if (unformat (line_input, "twice-nat"))
- twice_nat = 1;
- else if (unformat (line_input, "out2in-only"))
- out2in_only = 1;
- else if (unformat (line_input, "del"))
- is_add = 0;
- else
- {
- error = clib_error_return (0, "unknown input: '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (vec_len (locals) < 2)
- {
- error = clib_error_return (0, "at least two local must be set");
- goto done;
- }
-
- if (!proto_set)
- {
- error = clib_error_return (0, "missing protocol");
- goto done;
- }
-
- rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
- locals, is_add, twice_nat, out2in_only);
-
- switch (rv)
- {
- case VNET_API_ERROR_INVALID_VALUE:
- error = clib_error_return (0, "External port already in use.");
- goto done;
- case VNET_API_ERROR_NO_SUCH_ENTRY:
- if (is_add)
- error = clib_error_return (0, "External addres must be allocated.");
- else
- error = clib_error_return (0, "Mapping not exist.");
- goto done;
- case VNET_API_ERROR_VALUE_EXIST:
- error = clib_error_return (0, "Mapping already exist.");
- goto done;
- default:
- break;
- }
-
-done:
- unformat_free (line_input);
- vec_free (locals);
-
- return error;
-}
-
-VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
- .path = "nat44 add load-balancing static mapping",
- .function = add_lb_static_mapping_command_fn,
- .short_help =
- "nat44 add load-balancing static mapping protocol tcp|udp "
- "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
- "[vrf <table-id>] [out2in-only] [del]",
-};
-
-static clib_error_t *
-set_workers_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- uword *bitmap = 0;
- int rv = 0;
- clib_error_t *error = 0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
- ;
- else
- {
- error = clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (bitmap == 0)
- {
- error = clib_error_return (0, "List of workers must be specified.");
- goto done;
- }
-
- rv = snat_set_workers(bitmap);
-
- clib_bitmap_free (bitmap);
-
- switch (rv)
- {
- case VNET_API_ERROR_INVALID_WORKER:
- error = clib_error_return (0, "Invalid worker(s).");
- goto done;
- case VNET_API_ERROR_FEATURE_DISABLED:
- error = clib_error_return (0,
- "Supported only if 2 or more workes available.");
- goto done;
- default:
- break;
- }
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * @cliexpar
- * @cliexstart{set snat workers}
- * Set NAT workers if 2 or more workers available, use:
- * vpp# set snat workers 0-2,5
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (set_workers_command, static) = {
- .path = "set nat workers",
- .function = set_workers_command_fn,
- .short_help =
- "set nat workers <workers-list>",
-};
-
-static clib_error_t *
-snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u32 domain_id = 0;
- u32 src_port = 0;
- u8 enable = 1;
- int rv = 0;
- clib_error_t *error = 0;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "domain %d", &domain_id))
- ;
- else if (unformat (line_input, "src-port %d", &src_port))
- ;
- else if (unformat (line_input, "disable"))
- enable = 0;
- else
- {
- error = clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
-
- if (rv)
- {
- error = clib_error_return (0, "ipfix logging enable failed");
- goto done;
- }
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * @cliexpar
- * @cliexstart{snat ipfix logging}
- * To enable NAT IPFIX logging use:
- * vpp# nat ipfix logging
- * To set IPFIX exporter use:
- * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
- .path = "nat ipfix logging",
- .function = snat_ipfix_logging_enable_disable_command_fn,
- .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
-};
-
-static u32
-snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
-{
- snat_main_t *sm = &snat_main;
- u32 next_worker_index = 0;
- u32 hash;
-
- next_worker_index = sm->first_worker_index;
- hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
- (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
-
- if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
- next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
- else
- next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
-
- return next_worker_index;
-}
-
-static u32
-snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)