FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
cnat_snat.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 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 <vnet/ip/ip.h>
17 #include <cnat/cnat_snat.h>
18 
19 static void
21  table, ip_address_family_t af)
22 {
23  int i;
25  /* Note: bitmap reversed so this is in fact a longest prefix match */
26  /* *INDENT-OFF* */
28  ({
29  int dst_address_length = 128 - i;
30  vec_add1 (table->meta[af].prefix_lengths_in_search_order, dst_address_length);
31  }));
32  /* *INDENT-ON* */
33 }
34 
35 int
37 {
38  /* All packets destined to this prefix won't be source-NAT-ed */
41  ip6_address_t *mask;
42  u64 af = ip_prefix_version (pfx);;
43 
44  mask = &table->ip_masks[pfx->len];
45  if (AF_IP4 == af)
46  {
47  kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
48  kv.key[1] = 0;
49  }
50  else
51  {
52  kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
53  kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
54  }
55  kv.key[2] = ((u64) af << 32) | pfx->len;
56  clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 1 /* is_add */ );
57 
58  table->meta[af].dst_address_length_refcounts[pfx->len]++;
61  128 - pfx->len, 1);
63  return 0;
64 }
65 
66 int
68 {
70  clib_bihash_kv_24_8_t kv, val;
71  ip6_address_t *mask;
72  u64 af = ip_prefix_version (pfx);;
73 
74  mask = &table->ip_masks[pfx->len];
75  if (AF_IP4 == af)
76  {
77  kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
78  kv.key[1] = 0;
79  }
80  else
81  {
82  kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
83  kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
84  }
85  kv.key[2] = ((u64) af << 32) | pfx->len;
86 
87  if (clib_bihash_search_24_8 (&table->ip_hash, &kv, &val))
88  {
89  return 1;
90  }
91  clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 0 /* is_add */ );
92  /* refcount accounting */
93  ASSERT (table->meta[af].dst_address_length_refcounts[pfx->len] > 0);
94  if (--table->meta[af].dst_address_length_refcounts[pfx->len] == 0)
95  {
98  128 - pfx->len, 0);
100  }
101  return 0;
102 }
103 
104 u8 *
105 format_cnat_snat_prefix (u8 * s, va_list * args)
106 {
107  clib_bihash_kv_24_8_t *kv = va_arg (*args, clib_bihash_kv_24_8_t *);
108  CLIB_UNUSED (int verbose) = va_arg (*args, int);
109  u32 af = kv->key[2] >> 32;
110  u32 len = kv->key[2] & 0xffffffff;
111  if (AF_IP4 == af)
112  s = format (s, "%U/%d", format_ip4_address, &kv->key[0], len);
113  else
114  s = format (s, "%U/%d", format_ip6_address, &kv->key[0], len);
115  return (s);
116 }
117 
118 static clib_error_t *
120  unformat_input_t * input, vlib_cli_command_t * cmd)
121 {
122  unformat_input_t _line_input, *line_input = &_line_input;
123  clib_error_t *e = 0;
125 
126  /* Get a line of input. */
127  if (!unformat_user (input, unformat_line_input, line_input))
128  return 0;
129 
130  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
131  {
132  if (unformat (line_input, "%U", unformat_ip_address, &addr))
133  {
134  if (ip_addr_version (&addr) == AF_IP4)
136  sizeof (ip4_address_t));
137  else
139  sizeof (ip6_address_t));
140  }
141  else
142  {
143  e = clib_error_return (0, "unknown input '%U'",
144  format_unformat_error, input);
145  goto done;
146  }
147  }
148 
149 done:
150  unformat_free (line_input);
151 
152  return (e);
153 }
154 
155 /* *INDENT-OFF* */
156 VLIB_CLI_COMMAND (cnat_set_snat_command, static) =
157 {
158  .path = "cnat snat with",
159  .short_help = "cnat snat with [<ip4-address>][<ip6-address>]",
160  .function = cnat_set_snat,
161 };
162 /* *INDENT-ON* */
163 
164 static clib_error_t *
166  unformat_input_t * input, vlib_cli_command_t * cmd)
167 {
168  ip_prefix_t pfx;
169  u8 is_add = 1;
170  int rv;
171 
173  {
174  if (unformat (input, "%U", unformat_ip_prefix, &pfx))
175  ;
176  else if (unformat (input, "del"))
177  is_add = 0;
178  else
179  return (clib_error_return (0, "unknown input '%U'",
180  format_unformat_error, input));
181  }
182 
183  if (is_add)
184  rv = cnat_add_snat_prefix (&pfx);
185  else
186  rv = cnat_del_snat_prefix (&pfx);
187 
188  if (rv)
189  {
190  return (clib_error_return (0, "error %d", rv, input));
191  }
192 
193  return (NULL);
194 }
195 
196 /* *INDENT-OFF* */
197 VLIB_CLI_COMMAND (cnat_snat_exclude_command, static) =
198 {
199  .path = "cnat snat exclude",
200  .short_help = "cnat snat exclude [ip]",
201  .function = cnat_snat_exclude,
202 };
203 /* *INDENT-ON* */
204 
205 static clib_error_t *
207  unformat_input_t * input, vlib_cli_command_t * cmd)
208 {
210  vlib_cli_output (vm, "Source NAT\nip4: %U\nip6: %U\n",
213  vlib_cli_output (vm, "Prefixes:\n%U\n",
214  format_bihash_24_8, &table->ip_hash, 1);
215  return (NULL);
216 }
217 
218 /* *INDENT-OFF* */
219 VLIB_CLI_COMMAND (cnat_show_snat_command, static) =
220 {
221  .path = "show cnat snat",
222  .short_help = "show cnat snat",
223  .function = cnat_show_snat,
224 };
225 /* *INDENT-ON* */
226 
227 static clib_error_t *
229 {
232  int i;
233  for (i = 0; i < ARRAY_LEN (table->ip_masks); i++)
234  {
235  u32 j, i0, i1;
236 
237  i0 = i / 32;
238  i1 = i % 32;
239 
240  for (j = 0; j < i0; j++)
241  table->ip_masks[i].as_u32[j] = ~0;
242 
243  if (i1)
244  table->ip_masks[i].as_u32[i0] =
245  clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
246  }
247  clib_bihash_init_24_8 (&table->ip_hash, "snat prefixes",
249  clib_bihash_set_kvp_format_fn_24_8 (&table->ip_hash,
251 
252  return (NULL);
253 }
254 
256 
257 
258 /*
259  * fd.io coding-style-patch-verification: ON
260  *
261  * Local Variables:
262  * eval: (c-set-style "gnu")
263  * End:
264  */
#define ip_addr_v6(_a)
Definition: ip_types.h:59
#define CLIB_UNUSED(x)
Definition: clib.h:87
static void cnat_compute_prefix_lengths_in_search_order(cnat_snat_pfx_table_t *table, ip_address_family_t af)
Definition: cnat_snat.c:20
unsigned long u64
Definition: types.h:89
u8 len
Definition: ip_types.h:83
static clib_error_t * cnat_show_snat(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cnat_snat.c:206
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define ip_prefix_v6(_a)
Definition: ip_types.h:91
int cnat_add_snat_prefix(ip_prefix_t *pfx)
Definition: cnat_snat.c:36
u16 mask
Definition: flow_types.api:52
#define ip_prefix_v4(_a)
Definition: ip_types.h:90
#define ip_addr_version(_a)
Definition: ip_types.h:60
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
static clib_error_t * cnat_set_snat(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cnat_snat.c:119
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define clib_memcpy(d, s, n)
Definition: string.h:180
int cnat_del_snat_prefix(ip_prefix_t *pfx)
Definition: cnat_snat.c:67
format_function_t format_ip4_address
Definition: format.h:73
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static uword pow2_mask(uword x)
Definition: clib.h:237
clib_bihash_24_8_t ip_hash
Definition: cnat_types.h:76
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
unformat_function_t unformat_line_input
Definition: format.h:283
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
static clib_error_t * cnat_snat_exclude(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cnat_snat.c:165
struct _unformat_input_t unformat_input_t
u32 dst_address_length_refcounts[129]
Definition: cnat_types.h:68
uword unformat_ip_address(unformat_input_t *input, va_list *args)
Definition: ip_types.c:41
u8 len
Definition: ip_types.api:92
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
format_function_t format_ip6_address
Definition: format.h:91
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define ARRAY_LEN(x)
Definition: clib.h:67
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
#define ip_addr_v4(_a)
Definition: ip_types.h:58
cnat_snat_pfx_table_t snat_pfx_table
Definition: cnat_types.h:129
ip4_address_t snat_ip4
Definition: cnat_types.h:123
enum ip_address_family_t_ ip_address_family_t
ip6_address_t ip_masks[129]
Definition: cnat_types.h:80
uword * non_empty_dst_address_length_bitmap
Definition: cnat_types.h:70
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
u8 * format_cnat_snat_prefix(u8 *s, va_list *args)
Definition: cnat_snat.c:105
cnat_main_t cnat_main
Definition: cnat_types.c:18
#define ip_prefix_version(_a)
Definition: ip_types.h:88
static clib_error_t * cnat_snat_init(vlib_main_t *vm)
Definition: cnat_snat.c:228
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip6_address_t snat_ip6
Definition: cnat_types.h:126
cnat_snat_pfx_table_meta_t meta[2]
Definition: cnat_types.h:78
uword unformat_ip_prefix(unformat_input_t *input, va_list *args)
Definition: ip_types.c:64
u32 snat_hash_buckets
Definition: cnat_types.h:101
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
uword snat_hash_memory
Definition: cnat_types.h:98
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171