FD.io VPP  v21.06
Vector Packet Processing
pnat_cli.c
Go to the documentation of this file.
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 u8 *format_pnat_match_tuple(u8 *s, va_list *args) {
30  pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
31  s = format(s, "{");
32  if (t->mask & PNAT_SA)
33  s = format(s, "%U", format_ip4_address, &t->src);
34  else
35  s = format(s, "*");
36  if (t->mask & PNAT_SPORT)
37  s = format(s, ":%u,", t->sport);
38  else
39  s = format(s, ":*,");
40  if (t->proto > 0)
41  s = format(s, "%U,", format_ip_protocol, t->proto);
42  else
43  s = format(s, "*,");
44  if (t->mask & PNAT_DA)
45  s = format(s, "%U", format_ip4_address, &t->dst);
46  else
47  s = format(s, "*");
48  if (t->mask & PNAT_DPORT)
49  s = format(s, ":%u", t->dport);
50  else
51  s = format(s, ":*");
52  s = format(s, "}");
53  return s;
54 }
55 u8 *format_pnat_rewrite_tuple(u8 *s, va_list *args) {
56  pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
57  s = format(s, "{");
58  if (t->mask & PNAT_SA)
59  s = format(s, "%U", format_ip4_address, &t->src);
60  else
61  s = format(s, "*");
62  if (t->mask & PNAT_SPORT)
63  s = format(s, ":%u,", t->sport);
64  else
65  s = format(s, ":*,");
66  if (t->mask & PNAT_DA)
67  s = format(s, "%U", format_ip4_address, &t->dst);
68  else
69  s = format(s, "*");
70  if (t->mask & PNAT_DPORT)
71  s = format(s, ":%u", t->dport);
72  else
73  s = format(s, ":*");
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);
78  s = format(s, "}");
79  return s;
80 }
81 
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,
87  return s;
88 }
89 
90 static u8 *format_pnat_mask(u8 *s, va_list *args) {
91  pnat_mask_t t = va_arg(*args, pnat_mask_t);
92  if (t & PNAT_SA)
93  s = format(s, "SA ");
94  if (t & PNAT_SPORT)
95  s = format(s, "SP ");
96  if (t & PNAT_DA)
97  s = format(s, "DA ");
98  if (t & PNAT_DPORT)
99  s = format(s, "DP");
100  return s;
101 }
102 
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]);
109  }
110  if (interface->enabled[PNAT_IP4_OUTPUT]) {
111  s = format(s, " output mask: %U", format_pnat_mask,
112  interface->lookup_mask[PNAT_IP4_OUTPUT]);
113  }
114  return s;
115 }
116 
118  pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
119  u32 dport, sport;
120  while (1) {
121  if (unformat(input, "src %U", unformat_ip4_address, &t->src))
122  t->mask |= PNAT_SA;
123  else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
124  t->mask |= PNAT_DA;
125  else if (unformat(input, "sport %d", &sport)) {
126  if (sport == 0 || sport > 65535)
127  return 0;
128  t->mask |= PNAT_SPORT;
129  t->sport = sport;
130  } else if (unformat(input, "dport %d", &dport)) {
131  if (dport == 0 || dport > 65535)
132  return 0;
133  t->mask |= PNAT_DPORT;
134  t->dport = dport;
135  } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
136  ;
137  else
138  break;
139  }
140  return 1;
141 }
142 
144  pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
145  u32 dport, sport;
147 
148  while (1) {
149  if (unformat(input, "src %U", unformat_ip4_address, &t->src))
150  t->mask |= PNAT_SA;
151  else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
152  t->mask |= PNAT_DA;
153  else if (unformat(input, "sport %d", &sport)) {
154  if (sport == 0 || sport > 65535)
155  return 0;
156  t->mask |= PNAT_SPORT;
157  t->sport = sport;
158  } else if (unformat(input, "dport %d", &dport)) {
159  if (dport == 0 || dport > 65535)
160  return 0;
161  t->mask |= PNAT_DPORT;
162  t->dport = dport;
163  } else if (unformat(input, "copy-byte-at-offset %d %d", &from_offset,
164  &to_offset)) {
165  if (from_offset == to_offset || to_offset > 255 ||
166  from_offset > 255)
167  return 0;
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)
173  return 0;
174  t->mask |= PNAT_CLEAR_BYTE;
175  t->clear_offset = clear_offset;
176  } else
177  break;
178  }
179  return 1;
180 }
181 
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;
189  bool add = true;
190  u32 sw_if_index = ~0;
191  pnat_match_tuple_t match = {0};
193 
194  /* Get a line of input. */
195  if (!unformat_user(input, unformat_line_input, line_input))
196  return 0;
197 
198  while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
199  if (unformat(line_input, "match %U", unformat_pnat_match_tuple, &match))
200  match_set = true;
201  else if (unformat(line_input, "rewrite %U", unformat_pnat_rewrite_tuple,
202  &rewrite))
203  rewrite_set = true;
204  else if (unformat(line_input, "interface %U",
206  &sw_if_index))
207  ;
208  else if (unformat(line_input, "in")) {
209  in = true;
210  } else if (unformat(line_input, "out")) {
211  out = true;
212  } else if (unformat(line_input, "del")) {
213  add = false;
214  } else {
215  error = clib_error_return(0, "unknown input `%U'",
216  format_unformat_error, line_input);
217  goto done;
218  }
219  }
220  if (sw_if_index == ~0) {
221  error = clib_error_return(0, "interface is required `%U'",
222  format_unformat_error, line_input);
223  goto done;
224  }
225  if ((in && out) || (!in && !out)) {
226  error = clib_error_return(0, "in or out is required `%U'",
227  format_unformat_error, line_input);
228  goto done;
229  }
230  if (!match_set) {
231  error = clib_error_return(0, "missing parameter: match `%U'",
232  format_unformat_error, line_input);
233  goto done;
234  }
235  if (!rewrite_set) {
236  error = clib_error_return(0, "missing parameter: rewrite `%U'",
237  format_unformat_error, line_input);
238  goto done;
239  }
240 
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);
245  goto done;
246  }
248 
249  if (add) {
250  u32 binding_index;
251  int rv = pnat_binding_add(&match, &rewrite, &binding_index);
252  if (rv) {
253  error = clib_error_return(0, "Adding binding failed %d", rv);
254  goto done;
255  }
256  rv = pnat_binding_attach(sw_if_index, attachment, binding_index);
257  if (rv) {
258  pnat_binding_del(binding_index);
259  error = clib_error_return(
260  0, "Attaching binding to interface failed %d", rv);
261  goto done;
262  }
263  } else {
264  /* Lookup binding and lookup interface if both exists proceed with
265  * delete */
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");
269  goto done;
270  }
271  pnat_attachment_point_t attachment =
273  int rv = pnat_binding_detach(sw_if_index, attachment, binding_index);
274  if (rv) {
275  error = clib_error_return(0, "Detaching binding failed %d %d",
276  binding_index, rv);
277  goto done;
278  }
279  rv = pnat_binding_del(binding_index);
280  if (rv) {
281  error = clib_error_return(0, "Deleting translation failed %d %d",
282  binding_index, rv);
283  goto done;
284  }
285  }
286 
287 done:
288  unformat_free(line_input);
289 
290  return error;
291 }
292 
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]",
298 };
299 
300 static clib_error_t *
302  vlib_cli_command_t *cmd) {
303  pnat_main_t *pm = &pnat_main;
305  clib_error_t *error = 0;
306 
307  /* Get a line of input. */
308  pool_foreach(s, pm->translations) {
310  s);
311  }
312  return error;
313 }
314 
315 VLIB_CLI_COMMAND(show_pnat_translations_command, static) = {
316  .path = "show pnat translations",
317  .short_help = "show pnat translations",
319 };
320 
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;
327 
328  /* Get a line of input. */
329  pool_foreach(interface, pm->interfaces) {
330  vlib_cli_output(vm, "%U", format_pnat_interface, interface);
331  }
332  return error;
333 }
334 
335 VLIB_CLI_COMMAND(show_pnat_interfaces_command, static) = {
336  .path = "show pnat interfaces",
337  .short_help = "show pnat interfaces",
339 };
u32 pnat_flow_lookup(u32 sw_if_index, pnat_attachment_point_t attachment, pnat_match_tuple_t *match)
Definition: pnat.c:310
format_function_t format_ip_protocol
Definition: format.h:45
unformat_function_t unformat_ip_protocol
Definition: format.h:46
u8 from_offset
Definition: pnat.api:55
u8 * format_pnat_match_tuple(u8 *s, va_list *args)
Definition: pnat_cli.c:29
u32 sw_if_index
Definition: pnat.h:71
static clib_error_t * show_pnat_interfaces_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: pnat_cli.c:321
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
pnat_rewrite_tuple_t rewrite
Definition: pnat.h:66
u8 clear_offset
Definition: pnat.api:57
Fixed length block allocator.
static u8 * format_pnat_interface(u8 *s, va_list *args)
Definition: pnat_cli.c:103
uword unformat_pnat_rewrite_tuple(unformat_input_t *input, va_list *args)
Definition: pnat_cli.c:143
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
unformat_function_t unformat_vnet_sw_interface
static u8 * format_pnat_mask(u8 *s, va_list *args)
Definition: pnat_cli.c:90
unsigned char u8
Definition: types.h:56
unsigned int u32
Definition: types.h:88
int pnat_binding_detach(u32 sw_if_index, pnat_attachment_point_t attachment, u32 binding_index)
Definition: pnat.c:364
format_function_t format_ip4_address
Definition: format.h:73
unformat_function_t unformat_ip4_address
Definition: format.h:68
description fragment has unexpected format
Definition: map.api:433
#define clib_error_return(e, args...)
Definition: error.h:99
vnet_main_t * vnet_get_main(void)
vl_api_pnat_attachment_point_t pnat_attachment_point_t
Definition: pnat.h:30
int __clib_unused rv
Definition: application.c:491
Definition: pnat.api:23
vl_api_pnat_mask_t pnat_mask_t
Definition: pnat.h:29
unformat_function_t unformat_line_input
Definition: format.h:275
static clib_error_t * set_pnat_translation_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: pnat_cli.c:182
Definition: cJSON.c:88
pnat_translation_t * translations
Definition: pnat.h:92
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
struct _unformat_input_t unformat_input_t
u16 sport
Definition: pnat.api:43
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
static clib_error_t * show_pnat_translations_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: pnat_cli.c:301
vl_api_pnat_rewrite_tuple_t pnat_rewrite_tuple_t
Definition: pnat.h:28
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
u32 index
Definition: flow_types.api:221
uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args)
Definition: pnat_cli.c:117
pnat_match_tuple_t match
Definition: pnat.h:65
u16 dport
Definition: pnat.api:44
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
vl_api_pnat_match_tuple_t pnat_match_tuple_t
Definition: pnat.h:27
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
int pnat_binding_del(u32 index)
Definition: pnat.c:392
int pnat_binding_add(pnat_match_tuple_t *match, pnat_rewrite_tuple_t *rewrite, u32 *index)
Definition: pnat.c:271
u8 * format_pnat_translation(u8 *s, va_list *args)
Definition: pnat_cli.c:82
Definition: pnat.api:24
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
pnat_interface_t * interfaces
Definition: pnat.h:88
u8 * format_pnat_rewrite_tuple(u8 *s, va_list *args)
Definition: pnat_cli.c:55
u8 to_offset
Definition: pnat.api:56
pnat_main_t pnat_main
Definition: pnat.c:32
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
rewrite
Definition: pnat.api:158
int pnat_binding_attach(u32 sw_if_index, pnat_attachment_point_t attachment, u32 binding_index)
Definition: pnat.c:329