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_match_tuple(u8 *s, va_list *args) {
30 pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_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);
55 u8 *format_pnat_rewrite_tuple(u8 *s, va_list *args) {
56 pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
58 if (t->mask & PNAT_SA)
59 s = format(s, "%U", format_ip4_address, &t->src);
62 if (t->mask & PNAT_SPORT)
63 s = format(s, ":%u,", t->sport);
66 if (t->mask & PNAT_DA)
67 s = format(s, "%U", format_ip4_address, &t->dst);
70 if (t->mask & PNAT_DPORT)
71 s = format(s, ":%u", t->dport);
74 if (t->mask & PNAT_COPY_BYTE)
75 s = format(s, " copy byte@[%d->%d]", t->from_offset, t->to_offset);
76 if (t->mask & PNAT_CLEAR_BYTE)
77 s = format(s, " clear byte@[%d]", t->clear_offset);
82 u8 *format_pnat_translation(u8 *s, va_list *args) {
83 u32 index = va_arg(*args, u32);
84 pnat_translation_t *t = va_arg(*args, pnat_translation_t *);
85 s = format(s, "[%d] match: %U rewrite: %U", index, format_pnat_match_tuple,
86 &t->match, format_pnat_rewrite_tuple, &t->rewrite);
90 static u8 *format_pnat_mask(u8 *s, va_list *args) {
91 pnat_mask_t t = va_arg(*args, pnat_mask_t);
103 static u8 *format_pnat_interface(u8 *s, va_list *args) {
104 pnat_interface_t *interface = va_arg(*args, pnat_interface_t *);
105 s = format(s, "sw_if_index: %d", interface->sw_if_index);
106 if (interface->enabled[PNAT_IP4_INPUT]) {
107 s = format(s, " input mask: %U", format_pnat_mask,
108 interface->lookup_mask[PNAT_IP4_INPUT]);
110 if (interface->enabled[PNAT_IP4_OUTPUT]) {
111 s = format(s, " output mask: %U", format_pnat_mask,
112 interface->lookup_mask[PNAT_IP4_OUTPUT]);
117 uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) {
118 pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
121 if (unformat(input, "src %U", unformat_ip4_address, &t->src))
123 else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
125 else if (unformat(input, "sport %d", &sport)) {
126 if (sport == 0 || sport > 65535)
128 t->mask |= PNAT_SPORT;
130 } else if (unformat(input, "dport %d", &dport)) {
131 if (dport == 0 || dport > 65535)
133 t->mask |= PNAT_DPORT;
135 } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
143 uword unformat_pnat_rewrite_tuple(unformat_input_t *input, va_list *args) {
144 pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
146 u32 to_offset, from_offset, clear_offset;
149 if (unformat(input, "src %U", unformat_ip4_address, &t->src))
151 else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
153 else if (unformat(input, "sport %d", &sport)) {
154 if (sport == 0 || sport > 65535)
156 t->mask |= PNAT_SPORT;
158 } else if (unformat(input, "dport %d", &dport)) {
159 if (dport == 0 || dport > 65535)
161 t->mask |= PNAT_DPORT;
163 } else if (unformat(input, "copy-byte-at-offset %d %d", &from_offset,
165 if (from_offset == to_offset || to_offset > 255 ||
168 t->mask |= PNAT_COPY_BYTE;
169 t->from_offset = from_offset;
170 t->to_offset = to_offset;
171 } else if (unformat(input, "clear-byte-at-offset %d", &clear_offset)) {
172 if (clear_offset > 255)
174 t->mask |= PNAT_CLEAR_BYTE;
175 t->clear_offset = clear_offset;
182 static clib_error_t *set_pnat_translation_command_fn(vlib_main_t *vm,
183 unformat_input_t *input,
184 vlib_cli_command_t *cmd) {
185 unformat_input_t _line_input, *line_input = &_line_input;
186 clib_error_t *error = 0;
187 bool in = false, out = false;
188 bool match_set = false, rewrite_set = false;
190 u32 sw_if_index = ~0;
191 pnat_match_tuple_t match = {0};
192 pnat_rewrite_tuple_t rewrite = {0};
194 /* Get a line of input. */
195 if (!unformat_user(input, unformat_line_input, line_input))
198 while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
199 if (unformat(line_input, "match %U", unformat_pnat_match_tuple, &match))
201 else if (unformat(line_input, "rewrite %U", unformat_pnat_rewrite_tuple,
204 else if (unformat(line_input, "interface %U",
205 unformat_vnet_sw_interface, vnet_get_main(),
208 else if (unformat(line_input, "in")) {
210 } else if (unformat(line_input, "out")) {
212 } else if (unformat(line_input, "del")) {
215 error = clib_error_return(0, "unknown input `%U'",
216 format_unformat_error, line_input);
220 if (sw_if_index == ~0) {
221 error = clib_error_return(0, "interface is required `%U'",
222 format_unformat_error, line_input);
225 if ((in && out) || (!in && !out)) {
226 error = clib_error_return(0, "in or out is required `%U'",
227 format_unformat_error, line_input);
231 error = clib_error_return(0, "missing parameter: match `%U'",
232 format_unformat_error, line_input);
236 error = clib_error_return(0, "missing parameter: rewrite `%U'",
237 format_unformat_error, line_input);
241 if ((match.dport || match.sport) &&
242 (match.proto != 17 && match.proto != 6)) {
243 error = clib_error_return(0, "missing protocol (TCP|UDP): match `%U'",
244 format_unformat_error, line_input);
247 pnat_attachment_point_t attachment = in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
251 int rv = pnat_binding_add(&match, &rewrite, &binding_index);
253 error = clib_error_return(0, "Adding binding failed %d", rv);
256 rv = pnat_binding_attach(sw_if_index, attachment, binding_index);
258 pnat_binding_del(binding_index);
259 error = clib_error_return(
260 0, "Attaching binding to interface failed %d", rv);
264 /* Lookup binding and lookup interface if both exists proceed with
266 u32 binding_index = pnat_flow_lookup(sw_if_index, attachment, &match);
267 if (binding_index == ~0) {
268 error = clib_error_return(0, "Binding does not exist");
271 pnat_attachment_point_t attachment =
272 in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
273 int rv = pnat_binding_detach(sw_if_index, attachment, binding_index);
275 error = clib_error_return(0, "Detaching binding failed %d %d",
279 rv = pnat_binding_del(binding_index);
281 error = clib_error_return(0, "Deleting translation failed %d %d",
288 unformat_free(line_input);
293 VLIB_CLI_COMMAND(set_pnat_translation_command, static) = {
294 .path = "set pnat translation",
295 .short_help = "set pnat translation interface <name> match <5-tuple> "
296 "rewrite <tuple> {in|out} [del]",
297 .function = set_pnat_translation_command_fn,
300 static clib_error_t *
301 show_pnat_translations_command_fn(vlib_main_t *vm, unformat_input_t *input,
302 vlib_cli_command_t *cmd) {
303 pnat_main_t *pm = &pnat_main;
304 pnat_translation_t *s;
305 clib_error_t *error = 0;
307 /* Get a line of input. */
308 pool_foreach(s, pm->translations) {
309 vlib_cli_output(vm, "%U", format_pnat_translation, s - pm->translations,
315 VLIB_CLI_COMMAND(show_pnat_translations_command, static) = {
316 .path = "show pnat translations",
317 .short_help = "show pnat translations",
318 .function = show_pnat_translations_command_fn,
321 static clib_error_t *show_pnat_interfaces_command_fn(vlib_main_t *vm,
322 unformat_input_t *input,
323 vlib_cli_command_t *cmd) {
324 pnat_main_t *pm = &pnat_main;
325 pnat_interface_t *interface;
326 clib_error_t *error = 0;
328 /* Get a line of input. */
329 pool_foreach(interface, pm->interfaces) {
330 vlib_cli_output(vm, "%U", format_pnat_interface, interface);
335 VLIB_CLI_COMMAND(show_pnat_interfaces_command, static) = {
336 .path = "show pnat interfaces",
337 .short_help = "show pnat interfaces",
338 .function = show_pnat_interfaces_command_fn,