FD.io VPP  v21.10.1-2-g0a485f517
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);
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 
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 
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 
336  .path = "show pnat interfaces",
337  .short_help = "show pnat interfaces",
339 };
vlib.h
PNAT_COPY_BYTE
@ PNAT_COPY_BYTE
Definition: pnat.api:27
show_pnat_translations_command_fn
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
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
pnat_match_tuple_t
vl_api_pnat_match_tuple_t pnat_match_tuple_t
Definition: pnat.h:27
format_ip4_address
format_function_t format_ip4_address
Definition: format.h:73
pnat_binding_attach
int pnat_binding_attach(u32 sw_if_index, pnat_attachment_point_t attachment, u32 binding_index)
Definition: pnat.c:329
pnat_binding_del
int pnat_binding_del(u32 index)
Definition: pnat.c:392
unformat_line_input
unformat_function_t unformat_line_input
Definition: format.h:275
to_offset
u8 to_offset
Definition: pnat.api:56
format_pnat_mask
static u8 * format_pnat_mask(u8 *s, va_list *args)
Definition: pnat_cli.c:90
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
vlib_cli_command_t::path
char * path
Definition: cli.h:96
pnat_translation_t::rewrite
pnat_rewrite_tuple_t rewrite
Definition: pnat.h:66
clear_offset
u8 clear_offset
Definition: pnat.api:57
from_offset
u8 from_offset
Definition: pnat.api:55
unformat_pnat_match_tuple
uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args)
Definition: pnat_cli.c:117
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
pnat_mask_t
vl_api_pnat_mask_t pnat_mask_t
Definition: pnat.h:29
unformat_input_t
struct _unformat_input_t unformat_input_t
set_pnat_translation_command_fn
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
pnat_main_t
Definition: pnat.h:82
error
Definition: cJSON.c:88
pnat_interface_t::sw_if_index
u32 sw_if_index
Definition: pnat.h:71
PNAT_DA
@ PNAT_DA
Definition: pnat.api:24
sport
u16 sport
Definition: pnat.api:43
format_pnat_interface
static u8 * format_pnat_interface(u8 *s, va_list *args)
Definition: pnat_cli.c:103
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
pnat_flow_lookup
u32 pnat_flow_lookup(u32 sw_if_index, pnat_attachment_point_t attachment, pnat_match_tuple_t *match)
Definition: pnat.c:310
pnat_rewrite_tuple_t
vl_api_pnat_rewrite_tuple_t pnat_rewrite_tuple_t
Definition: pnat.h:28
pnat.h
show_pnat_translations_command
static vlib_cli_command_t show_pnat_translations_command
(constructor) VLIB_CLI_COMMAND (show_pnat_translations_command)
Definition: pnat_cli.c:315
unformat_free
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
feature.h
pnat_binding_detach
int pnat_binding_detach(u32 sw_if_index, pnat_attachment_point_t attachment, u32 binding_index)
Definition: pnat.c:364
PNAT_SA
@ PNAT_SA
Definition: pnat.api:23
show_pnat_interfaces_command
static vlib_cli_command_t show_pnat_interfaces_command
(constructor) VLIB_CLI_COMMAND (show_pnat_interfaces_command)
Definition: pnat_cli.c:335
pnat_main
pnat_main_t pnat_main
Definition: pnat.c:32
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
pnat_main_t::translations
pnat_translation_t * translations
Definition: pnat.h:92
set_pnat_translation_command
static vlib_cli_command_t set_pnat_translation_command
(constructor) VLIB_CLI_COMMAND (set_pnat_translation_command)
Definition: pnat_cli.c:293
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
format_pnat_match_tuple
u8 * format_pnat_match_tuple(u8 *s, va_list *args)
Definition: pnat_cli.c:29
format_pnat_translation
u8 * format_pnat_translation(u8 *s, va_list *args)
Definition: pnat_cli.c:82
uword
u64 uword
Definition: types.h:112
format_ip_protocol
format_function_t format_ip_protocol
Definition: format.h:45
pool.h
Fixed length block allocator. Pools are built from clib vectors and bitmaps. Use pools when repeatedl...
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
unformat_pnat_rewrite_tuple
uword unformat_pnat_rewrite_tuple(unformat_input_t *input, va_list *args)
Definition: pnat_cli.c:143
unformat_ip_protocol
unformat_function_t unformat_ip_protocol
Definition: format.h:46
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
ip4_packet.h
index
u32 index
Definition: flow_types.api:221
PNAT_DPORT
@ PNAT_DPORT
Definition: pnat.api:26
pnat_translation_t
Definition: pnat.h:48
unformat_vnet_sw_interface
unformat_function_t unformat_vnet_sw_interface
Definition: interface_funcs.h:462
format
description fragment has unexpected format
Definition: map.api:433
pnat_interface_t
Definition: pnat.h:70
dport
u16 dport
Definition: pnat.api:44
ip.h
u32
unsigned int u32
Definition: types.h:88
format_pnat_rewrite_tuple
u8 * format_pnat_rewrite_tuple(u8 *s, va_list *args)
Definition: pnat_cli.c:55
PNAT_CLEAR_BYTE
@ PNAT_CLEAR_BYTE
Definition: pnat.api:28
ip4.h
PNAT_SPORT
@ PNAT_SPORT
Definition: pnat.api:25
vlib_main_t
Definition: main.h:102
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
pnat_translation_t::match
pnat_match_tuple_t match
Definition: pnat.h:65
clib_error.h
PNAT_IP4_OUTPUT
@ PNAT_IP4_OUTPUT
Definition: pnat.api:34
rv
int __clib_unused rv
Definition: application.c:491
unformat_ip4_address
unformat_function_t unformat_ip4_address
Definition: format.h:68
show_pnat_interfaces_command_fn
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
pnat_main_t::interfaces
pnat_interface_t * interfaces
Definition: pnat.h:88
vlib_cli_command_t
Definition: cli.h:92
PNAT_IP4_INPUT
@ PNAT_IP4_INPUT
Definition: pnat.api:33
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
rewrite
rewrite
Definition: pnat.api:158
pnat_binding_add
int pnat_binding_add(pnat_match_tuple_t *match, pnat_rewrite_tuple_t *rewrite, u32 *index)
Definition: pnat.c:271
pnat_attachment_point_t
vl_api_pnat_attachment_point_t pnat_attachment_point_t
Definition: pnat.h:30
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137