2 * Copyright (c) 2021 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.
17 #include <vlib/vlib.h>
18 #include <vnet/feature/feature.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/ip/ip4_packet.h>
22 #include <vppinfra/clib_error.h>
23 #include <vppinfra/pool.h>
27 * This file contains the handlers for the (unsupported) VPP debug CLI.
29 u8 *format_pnat_5tuple(u8 *s, va_list *args) {
30 pnat_5tuple_t *t = va_arg(*args, pnat_5tuple_t *);
32 if (t->mask & PNAT_SA)
33 s = format(s, "%U", format_ip4_address, &t->src);
36 if (t->mask & PNAT_SPORT)
37 s = format(s, ":%u,", t->sport);
41 s = format(s, "%U,", format_ip_protocol, t->proto);
44 if (t->mask & PNAT_DA)
45 s = format(s, "%U", format_ip4_address, &t->dst);
48 if (t->mask & PNAT_DPORT)
49 s = format(s, ":%u", t->dport);
56 u8 *format_pnat_translation(u8 *s, va_list *args) {
57 u32 index = va_arg(*args, u32);
58 pnat_translation_t *t = va_arg(*args, pnat_translation_t *);
59 s = format(s, "[%d] match: %U rewrite: %U", index, format_pnat_5tuple,
60 &t->match, format_pnat_5tuple, &t->rewrite);
64 static u8 *format_pnat_mask(u8 *s, va_list *args) {
65 pnat_mask_t t = va_arg(*args, pnat_mask_t);
77 static u8 *format_pnat_interface(u8 *s, va_list *args) {
78 pnat_interface_t *interface = va_arg(*args, pnat_interface_t *);
79 s = format(s, "sw_if_index: %d", interface->sw_if_index);
80 if (interface->enabled[PNAT_IP4_INPUT]) {
81 s = format(s, " input mask: %U", format_pnat_mask,
82 interface->lookup_mask[PNAT_IP4_INPUT]);
84 if (interface->enabled[PNAT_IP4_OUTPUT]) {
85 s = format(s, " output mask: %U", format_pnat_mask,
86 interface->lookup_mask[PNAT_IP4_OUTPUT]);
91 uword unformat_pnat_5tuple(unformat_input_t *input, va_list *args) {
92 pnat_5tuple_t *t = va_arg(*args, pnat_5tuple_t *);
95 if (unformat(input, "src %U", unformat_ip4_address, &t->src))
97 else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
99 else if (unformat(input, "sport %d", &sport)) {
100 if (sport < 0 || sport > 65535)
102 t->mask |= PNAT_SPORT;
104 } else if (unformat(input, "dport %d", &dport)) {
105 if (dport < 0 || dport > 65535)
107 t->mask |= PNAT_DPORT;
109 } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
117 static clib_error_t *set_pnat_translation_command_fn(vlib_main_t *vm,
118 unformat_input_t *input,
119 vlib_cli_command_t *cmd) {
120 unformat_input_t _line_input, *line_input = &_line_input;
121 clib_error_t *error = 0;
122 bool in = false, out = false;
123 bool match_set = false, rewrite_set = false;
125 u32 sw_if_index = ~0;
126 pnat_5tuple_t match = {0};
127 pnat_5tuple_t rewrite = {0};
129 /* Get a line of input. */
130 if (!unformat_user(input, unformat_line_input, line_input))
133 while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
134 if (unformat(line_input, "match %U", unformat_pnat_5tuple, &match))
136 else if (unformat(line_input, "rewrite %U", unformat_pnat_5tuple,
139 else if (unformat(line_input, "interface %U",
140 unformat_vnet_sw_interface, vnet_get_main(),
143 else if (unformat(line_input, "in")) {
145 } else if (unformat(line_input, "out")) {
147 } else if (unformat(line_input, "del")) {
150 error = clib_error_return(0, "unknown input `%U'",
151 format_unformat_error, line_input);
155 if (sw_if_index == ~0) {
156 error = clib_error_return(0, "interface is required `%U'",
157 format_unformat_error, line_input);
160 if ((in && out) || (!in && !out)) {
161 error = clib_error_return(0, "in or out is required `%U'",
162 format_unformat_error, line_input);
166 error = clib_error_return(0, "missing parameter: match `%U'",
167 format_unformat_error, line_input);
171 error = clib_error_return(0, "missing parameter: rewrite `%U'",
172 format_unformat_error, line_input);
176 if ((match.dport || match.sport) &&
177 (match.proto != 17 && match.proto != 6)) {
178 error = clib_error_return(0, "missing protocol (TCP|UDP): match `%U'",
179 format_unformat_error, line_input);
182 pnat_attachment_point_t attachment = in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
186 int rv = pnat_binding_add(&match, &rewrite, &binding_index);
188 error = clib_error_return(0, "Adding binding failed %d", rv);
191 rv = pnat_binding_attach(sw_if_index, attachment, binding_index);
193 pnat_binding_del(binding_index);
194 error = clib_error_return(
195 0, "Attaching binding to interface failed %d", rv);
199 /* Lookup binding and lookup interface if both exists proceed with
201 u32 binding_index = pnat_flow_lookup(sw_if_index, attachment, &match);
202 if (binding_index == ~0) {
203 error = clib_error_return(0, "Binding does not exist");
206 pnat_attachment_point_t attachment =
207 in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
208 int rv = pnat_binding_detach(sw_if_index, attachment, binding_index);
210 error = clib_error_return(0, "Detaching binding failed %d %d",
214 rv = pnat_binding_del(binding_index);
216 error = clib_error_return(0, "Deleting translation failed %d %d",
223 unformat_free(line_input);
228 VLIB_CLI_COMMAND(set_pnat_translation_command, static) = {
229 .path = "set pnat translation",
230 .short_help = "set pnat translation interface <name> match <5-tuple> "
231 "rewrite <5-tuple> {in|out} [del]",
232 .function = set_pnat_translation_command_fn,
235 static clib_error_t *
236 show_pnat_translations_command_fn(vlib_main_t *vm, unformat_input_t *input,
237 vlib_cli_command_t *cmd) {
238 pnat_main_t *pm = &pnat_main;
239 pnat_translation_t *s;
240 clib_error_t *error = 0;
242 /* Get a line of input. */
243 pool_foreach(s, pm->translations) {
244 vlib_cli_output(vm, "%U", format_pnat_translation, s - pm->translations,
250 VLIB_CLI_COMMAND(show_pnat_translations_command, static) = {
251 .path = "show pnat translations",
252 .short_help = "show pnat translations",
253 .function = show_pnat_translations_command_fn,
256 static clib_error_t *show_pnat_interfaces_command_fn(vlib_main_t *vm,
257 unformat_input_t *input,
258 vlib_cli_command_t *cmd) {
259 pnat_main_t *pm = &pnat_main;
260 pnat_interface_t *interface;
261 clib_error_t *error = 0;
263 /* Get a line of input. */
264 pool_foreach(interface, pm->interfaces) {
265 vlib_cli_output(vm, "%U", format_pnat_interface, interface);
270 VLIB_CLI_COMMAND(show_pnat_interfaces_command, static) = {
271 .path = "show pnat interfaces",
272 .short_help = "show pnat interfaces",
273 .function = show_pnat_interfaces_command_fn,