Line data Source code
1 : /*
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:
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 <stdbool.h>
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>
24 : #include "pnat.h"
25 :
26 : /*
27 : * This file contains the handlers for the (unsupported) VPP debug CLI.
28 : */
29 11 : u8 *format_pnat_match_tuple(u8 *s, va_list *args) {
30 11 : pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
31 11 : s = format(s, "{");
32 11 : if (t->mask & PNAT_SA)
33 4 : s = format(s, "%U", format_ip4_address, &t->src);
34 : else
35 7 : s = format(s, "*");
36 11 : if (t->mask & PNAT_SPORT)
37 0 : s = format(s, ":%u,", t->sport);
38 : else
39 11 : s = format(s, ":*,");
40 11 : if (t->proto > 0)
41 7 : s = format(s, "%U,", format_ip_protocol, t->proto);
42 : else
43 4 : s = format(s, "*,");
44 11 : if (t->mask & PNAT_DA)
45 7 : s = format(s, "%U", format_ip4_address, &t->dst);
46 : else
47 4 : s = format(s, "*");
48 11 : if (t->mask & PNAT_DPORT)
49 6 : s = format(s, ":%u", t->dport);
50 : else
51 5 : s = format(s, ":*");
52 11 : s = format(s, "}");
53 11 : return s;
54 : }
55 11 : u8 *format_pnat_rewrite_tuple(u8 *s, va_list *args) {
56 11 : pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
57 11 : s = format(s, "{");
58 11 : if (t->mask & PNAT_SA)
59 5 : s = format(s, "%U", format_ip4_address, &t->src);
60 : else
61 6 : s = format(s, "*");
62 11 : if (t->mask & PNAT_SPORT)
63 0 : s = format(s, ":%u,", t->sport);
64 : else
65 11 : s = format(s, ":*,");
66 11 : if (t->mask & PNAT_DA)
67 5 : s = format(s, "%U", format_ip4_address, &t->dst);
68 : else
69 6 : s = format(s, "*");
70 11 : if (t->mask & PNAT_DPORT)
71 2 : s = format(s, ":%u", t->dport);
72 : else
73 9 : s = format(s, ":*");
74 11 : if (t->mask & PNAT_COPY_BYTE)
75 0 : s = format(s, " copy byte@[%d->%d]", t->from_offset, t->to_offset);
76 11 : if (t->mask & PNAT_CLEAR_BYTE)
77 0 : s = format(s, " clear byte@[%d]", t->clear_offset);
78 11 : s = format(s, "}");
79 11 : return s;
80 : }
81 :
82 2 : u8 *format_pnat_translation(u8 *s, va_list *args) {
83 2 : u32 index = va_arg(*args, u32);
84 2 : pnat_translation_t *t = va_arg(*args, pnat_translation_t *);
85 2 : s = format(s, "[%d] match: %U rewrite: %U", index, format_pnat_match_tuple,
86 : &t->match, format_pnat_rewrite_tuple, &t->rewrite);
87 2 : return s;
88 : }
89 :
90 2 : static u8 *format_pnat_mask(u8 *s, va_list *args) {
91 2 : pnat_mask_t t = va_arg(*args, pnat_mask_t);
92 2 : if (t & PNAT_SA)
93 1 : s = format(s, "SA ");
94 2 : if (t & PNAT_SPORT)
95 0 : s = format(s, "SP ");
96 2 : if (t & PNAT_DA)
97 1 : s = format(s, "DA ");
98 2 : if (t & PNAT_DPORT)
99 2 : s = format(s, "DP");
100 2 : return s;
101 : }
102 :
103 2 : static u8 *format_pnat_interface(u8 *s, va_list *args) {
104 2 : pnat_interface_t *interface = va_arg(*args, pnat_interface_t *);
105 2 : s = format(s, "sw_if_index: %d", interface->sw_if_index);
106 2 : if (interface->enabled[PNAT_IP4_INPUT]) {
107 1 : s = format(s, " input mask: %U", format_pnat_mask,
108 1 : interface->lookup_mask[PNAT_IP4_INPUT]);
109 : }
110 2 : if (interface->enabled[PNAT_IP4_OUTPUT]) {
111 1 : s = format(s, " output mask: %U", format_pnat_mask,
112 1 : interface->lookup_mask[PNAT_IP4_OUTPUT]);
113 : }
114 2 : return s;
115 : }
116 :
117 0 : uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) {
118 0 : pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
119 : u32 dport, sport;
120 : while (1) {
121 0 : if (unformat(input, "src %U", unformat_ip4_address, &t->src))
122 0 : t->mask |= PNAT_SA;
123 0 : else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
124 0 : t->mask |= PNAT_DA;
125 0 : else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
126 0 : t->mask |= PNAT_PROTO;
127 0 : else if (unformat(input, "sport %d", &sport)) {
128 0 : if (sport == 0 || sport > 65535)
129 0 : return 0;
130 0 : t->mask |= PNAT_SPORT;
131 0 : t->sport = sport;
132 0 : } else if (unformat(input, "dport %d", &dport)) {
133 0 : if (dport == 0 || dport > 65535)
134 0 : return 0;
135 0 : t->mask |= PNAT_DPORT;
136 0 : t->dport = dport;
137 : } else
138 0 : break;
139 : }
140 0 : return 1;
141 : }
142 :
143 0 : uword unformat_pnat_rewrite_tuple(unformat_input_t *input, va_list *args) {
144 0 : pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
145 : u32 dport, sport;
146 : u32 to_offset, from_offset, clear_offset;
147 :
148 : while (1) {
149 0 : if (unformat(input, "src %U", unformat_ip4_address, &t->src))
150 0 : t->mask |= PNAT_SA;
151 0 : else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
152 0 : t->mask |= PNAT_DA;
153 0 : else if (unformat(input, "sport %d", &sport)) {
154 0 : if (sport == 0 || sport > 65535)
155 0 : return 0;
156 0 : t->mask |= PNAT_SPORT;
157 0 : t->sport = sport;
158 0 : } else if (unformat(input, "dport %d", &dport)) {
159 0 : if (dport == 0 || dport > 65535)
160 0 : return 0;
161 0 : t->mask |= PNAT_DPORT;
162 0 : t->dport = dport;
163 0 : } else if (unformat(input, "copy-byte-at-offset %d %d", &from_offset,
164 : &to_offset)) {
165 0 : if (from_offset == to_offset || to_offset > 255 ||
166 0 : from_offset > 255)
167 0 : return 0;
168 0 : t->mask |= PNAT_COPY_BYTE;
169 0 : t->from_offset = from_offset;
170 0 : t->to_offset = to_offset;
171 0 : } else if (unformat(input, "clear-byte-at-offset %d", &clear_offset)) {
172 0 : if (clear_offset > 255)
173 0 : return 0;
174 0 : t->mask |= PNAT_CLEAR_BYTE;
175 0 : t->clear_offset = clear_offset;
176 : } else
177 0 : break;
178 : }
179 0 : return 1;
180 : }
181 :
182 0 : 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 0 : unformat_input_t _line_input, *line_input = &_line_input;
186 0 : clib_error_t *error = 0;
187 0 : bool in = false, out = false;
188 0 : bool match_set = false, rewrite_set = false;
189 0 : bool add = true;
190 0 : u32 sw_if_index = ~0;
191 0 : pnat_match_tuple_t match = {0};
192 0 : pnat_rewrite_tuple_t rewrite = {0};
193 :
194 : /* Get a line of input. */
195 0 : if (!unformat_user(input, unformat_line_input, line_input))
196 0 : return 0;
197 :
198 0 : while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
199 0 : if (unformat(line_input, "match %U", unformat_pnat_match_tuple, &match))
200 0 : match_set = true;
201 0 : else if (unformat(line_input, "rewrite %U", unformat_pnat_rewrite_tuple,
202 : &rewrite))
203 0 : rewrite_set = true;
204 0 : else if (unformat(line_input, "interface %U",
205 : unformat_vnet_sw_interface, vnet_get_main(),
206 : &sw_if_index))
207 : ;
208 0 : else if (unformat(line_input, "in")) {
209 0 : in = true;
210 0 : } else if (unformat(line_input, "out")) {
211 0 : out = true;
212 0 : } else if (unformat(line_input, "del")) {
213 0 : add = false;
214 : } else {
215 0 : error = clib_error_return(0, "unknown input `%U'",
216 : format_unformat_error, line_input);
217 0 : goto done;
218 : }
219 : }
220 0 : if (sw_if_index == ~0) {
221 0 : error = clib_error_return(0, "interface is required `%U'",
222 : format_unformat_error, line_input);
223 0 : goto done;
224 : }
225 0 : if ((in && out) || (!in && !out)) {
226 0 : error = clib_error_return(0, "in or out is required `%U'",
227 : format_unformat_error, line_input);
228 0 : goto done;
229 : }
230 0 : if (!match_set) {
231 0 : error = clib_error_return(0, "missing parameter: match `%U'",
232 : format_unformat_error, line_input);
233 0 : goto done;
234 : }
235 0 : if (!rewrite_set) {
236 0 : error = clib_error_return(0, "missing parameter: rewrite `%U'",
237 : format_unformat_error, line_input);
238 0 : goto done;
239 : }
240 :
241 0 : if ((match.dport || match.sport) &&
242 0 : (match.proto != 17 && match.proto != 6)) {
243 0 : error = clib_error_return(0, "missing protocol (TCP|UDP): match `%U'",
244 : format_unformat_error, line_input);
245 0 : goto done;
246 : }
247 0 : pnat_attachment_point_t attachment = in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
248 :
249 0 : if (add) {
250 : u32 binding_index;
251 0 : int rv = pnat_binding_add(&match, &rewrite, &binding_index);
252 0 : if (rv) {
253 0 : error = clib_error_return(0, "Adding binding failed %d", rv);
254 0 : goto done;
255 : }
256 0 : rv = pnat_binding_attach(sw_if_index, attachment, binding_index);
257 0 : if (rv) {
258 0 : pnat_binding_del(binding_index);
259 0 : error = clib_error_return(
260 : 0, "Attaching binding to interface failed %d", rv);
261 0 : goto done;
262 : }
263 : } else {
264 : /* Lookup binding and lookup interface if both exists proceed with
265 : * delete */
266 0 : u32 binding_index = pnat_flow_lookup(sw_if_index, attachment, &match);
267 0 : if (binding_index == ~0) {
268 0 : error = clib_error_return(0, "Binding does not exist");
269 0 : goto done;
270 : }
271 0 : pnat_attachment_point_t attachment =
272 0 : in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
273 0 : int rv = pnat_binding_detach(sw_if_index, attachment, binding_index);
274 0 : if (rv) {
275 0 : error = clib_error_return(0, "Detaching binding failed %d %d",
276 : binding_index, rv);
277 0 : goto done;
278 : }
279 0 : rv = pnat_binding_del(binding_index);
280 0 : if (rv) {
281 0 : error = clib_error_return(0, "Deleting translation failed %d %d",
282 : binding_index, rv);
283 0 : goto done;
284 : }
285 : }
286 :
287 0 : done:
288 0 : unformat_free(line_input);
289 :
290 0 : return error;
291 : }
292 :
293 50261 : 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,
298 : };
299 :
300 : static clib_error_t *
301 1 : show_pnat_translations_command_fn(vlib_main_t *vm, unformat_input_t *input,
302 : vlib_cli_command_t *cmd) {
303 1 : pnat_main_t *pm = &pnat_main;
304 : pnat_translation_t *s;
305 1 : clib_error_t *error = 0;
306 :
307 : /* Get a line of input. */
308 3 : pool_foreach(s, pm->translations) {
309 2 : vlib_cli_output(vm, "%U", format_pnat_translation, s - pm->translations,
310 : s);
311 : }
312 1 : return error;
313 : }
314 :
315 50261 : 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,
319 : };
320 :
321 1 : 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 1 : pnat_main_t *pm = &pnat_main;
325 : pnat_interface_t *interface;
326 1 : clib_error_t *error = 0;
327 :
328 : /* Get a line of input. */
329 3 : pool_foreach(interface, pm->interfaces) {
330 2 : vlib_cli_output(vm, "%U", format_pnat_interface, interface);
331 : }
332 1 : return error;
333 : }
334 :
335 50261 : 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,
339 : };
|