FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
cnat_translation.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/fib/fib_source.h>
17 #include <vnet/fib/fib_table.h>
19 #include <vnet/dpo/load_balance.h>
20 #include <vnet/dpo/drop_dpo.h>
21 
22 #include <cnat/cnat_translation.h>
23 #include <cnat/cnat_session.h>
24 #include <cnat/cnat_client.h>
25 
27 clib_bihash_8_8_t cnat_translation_db;
28 
30 
31 vlib_combined_counter_main_t cnat_translation_counters = {
32  .name = "cnat-translation",
33  .stat_segment_name = "/net/cnat-translation",
34 };
35 
36 static void
38 {
39  fib_entry_untrack (trk->ct_fei, trk->ct_sibling);
40 }
41 
42 static void
45 {
46  fib_prefix_t pfx;
47 
48  ip_address_to_fib_prefix (&path->dst_ep.ce_ip, &pfx);
49 
50  clib_memcpy (&trk->ct_ep[VLIB_TX], &path->dst_ep,
51  sizeof (trk->ct_ep[VLIB_TX]));
52  clib_memcpy (&trk->ct_ep[VLIB_RX], &path->src_ep,
53  sizeof (trk->ct_ep[VLIB_RX]));
54 
56  &pfx,
58  cti, &trk->ct_sibling);
59 
62  (pfx.fp_proto), &trk->ct_dpo);
63 }
64 
65 void
67  index_t cti)
68 {
70  u64 key;
71 
72  key = (proto << 16) | port;
73  key = key << 32 | (u32) cci;
74 
75  bkey.key = key;
76  bkey.value = cti;
77 
78  clib_bihash_add_del_8_8 (&cnat_translation_db, &bkey, 1);
79 }
80 
81 void
83 {
85  u64 key;
86 
87  key = (proto << 16) | port;
88  key = key << 32 | (u32) cci;
89 
90  bkey.key = key;
91 
92  clib_bihash_add_del_8_8 (&cnat_translation_db, &bkey, 0);
93 }
94 
95 static void
97 {
98  fib_protocol_t fproto;
99  cnat_ep_trk_t *trk;
100  dpo_proto_t dproto;
101  index_t lbi;
102 
104  dproto = fib_proto_to_dpo (fproto);
105 
106  lbi = load_balance_create (vec_len (ct->ct_paths),
108 
109  vec_foreach (trk, ct->ct_paths)
110  load_balance_set_bucket (lbi, trk - ct->ct_paths, &trk->ct_dpo);
111 
112  dpo_set (&ct->ct_lb, DPO_LOAD_BALANCE, dproto, lbi);
113  dpo_stack (cnat_client_dpo, dproto, &ct->ct_lb, &ct->ct_lb);
114 }
115 
116 int
118 {
119  cnat_translation_t *ct;
120  cnat_ep_trk_t *trk;
121 
122  if (pool_is_free_index (cnat_translation_pool, id))
123  return (VNET_API_ERROR_NO_SUCH_ENTRY);
124 
125  ct = pool_elt_at_index (cnat_translation_pool, id);
126 
127  dpo_reset (&ct->ct_lb);
128 
129  vec_foreach (trk, ct->ct_paths) cnat_tracker_release (trk);
130 
132  ct->ct_proto);
134  pool_put (cnat_translation_pool, ct);
135 
136  return (0);
137 }
138 
139 u32
143 {
145  const cnat_client_t *cc;
146  cnat_translation_t *ct;
147  cnat_ep_trk_t *trk;
148  index_t cci;
149 
150  /* do we know of this ep's vip */
151  cci = cnat_client_add (&vip->ce_ip, flags);
152  cc = cnat_client_get (cci);
153 
154  ct = cnat_find_translation (cc->parent_cci, vip->ce_port, proto);
155 
156  if (NULL == ct)
157  {
158  pool_get_zero (cnat_translation_pool, ct);
159 
160  clib_memcpy (&ct->ct_vip, vip, sizeof (*vip));
161  ct->ct_proto = proto;
162  ct->ct_cci = cci;
163  ct->index = ct - cnat_translation_pool;
164 
166  ct->index);
168 
169  vlib_validate_combined_counter (&cnat_translation_counters, ct->index);
170  vlib_zero_combined_counter (&cnat_translation_counters, ct->index);
171  }
172  ct->flags = flags;
173 
174  vec_foreach (trk, ct->ct_paths)
175  {
176  cnat_tracker_release (trk);
177  }
178 
180 
181  vec_foreach (path, paths)
182  {
183  vec_add2 (ct->ct_paths, trk, 1);
184 
185  cnat_tracker_track (ct->index, path, trk);
186  }
187 
189 
190  return (ct->index);
191 }
192 
193 void
195 {
196  u32 api;
197 
198  /* *INDENT-OFF* */
199  pool_foreach_index(api, cnat_translation_pool,
200  ({
201  if (!cb(api, ctx))
202  break;
203  }));
204  /* *INDENT-ON* */
205 }
206 
207 static u8 *
208 format_cnat_ep_trk (u8 * s, va_list * args)
209 {
210  cnat_ep_trk_t *ck = va_arg (*args, cnat_ep_trk_t *);
211  u32 indent = va_arg (*args, u32);
212 
213  s = format (s, "%U->%U", format_cnat_endpoint, &ck->ct_ep[VLIB_RX],
215  s = format (s, "\n%Ufib-entry:%d", format_white_space, indent, ck->ct_fei);
216  s = format (s, "\n%U%U",
217  format_white_space, indent, format_dpo_id, &ck->ct_dpo, 6);
218 
219  return (s);
220 }
221 
222 u8 *
223 format_cnat_translation (u8 * s, va_list * args)
224 {
225  cnat_translation_t *ct = va_arg (*args, cnat_translation_t *);
226  cnat_ep_trk_t *ck;
227 
228  s = format (s, "[%d] ", ct->index);
229  s = format (s, "%U %U", format_cnat_endpoint, &ct->ct_vip,
231 
232  vec_foreach (ck, ct->ct_paths)
233  s = format (s, "\n%U", format_cnat_ep_trk, ck, 2);
234 
235  /* If printing a trace, the LB object might be deleted */
237  {
238  s = format (s, "\n via:");
239  s = format (s, "\n%U%U",
240  format_white_space, 2, format_dpo_id, &ct->ct_lb, 2);
241  }
242 
243  return (s);
244 }
245 
246 static clib_error_t *
248  unformat_input_t * input, vlib_cli_command_t * cmd)
249 {
250  index_t cti;
251  cnat_translation_t *ct;
252 
253  cti = INDEX_INVALID;
254 
256  {
257  if (unformat (input, "%d", &cti))
258  ;
259  else
260  return (clib_error_return (0, "unknown input '%U'",
261  format_unformat_error, input));
262  }
263 
264  if (INDEX_INVALID == cti)
265  {
266  /* *INDENT-OFF* */
267  pool_foreach_index(cti, cnat_translation_pool,
268  ({
269  ct = pool_elt_at_index (cnat_translation_pool, cti);
271  }));
272  /* *INDENT-ON* */
273  }
274  else
275  {
276  vlib_cli_output (vm, "Invalid policy ID:%d", cti);
277  }
278 
279  return (NULL);
280 }
281 
282 int
284 {
285  /* purge all the translations */
286  index_t tri, *trp, *trs = NULL;
287 
288  /* *INDENT-OFF* */
289  pool_foreach_index(tri, cnat_translation_pool,
290  ({
291  vec_add1(trs, tri);
292  }));
293  /* *INDENT-ON* */
294 
295  vec_foreach (trp, trs) cnat_translation_delete (*trp);
296 
297  ASSERT (0 == pool_elts (cnat_translation_pool));
298 
299  vec_free (trs);
300 
301  return (0);
302 }
303 
304 /* *INDENT-OFF* */
305 VLIB_CLI_COMMAND (cnat_translation_show_cmd_node, static) = {
306  .path = "show cnat translation",
307  .function = cnat_translation_show,
308  .short_help = "show cnat translation <VIP>",
309  .is_mp_safe = 1,
310 };
311 /* *INDENT-ON* */
312 
313 static fib_node_t *
315 {
317  return (&(ct->ct_node));
318 }
319 
320 static cnat_translation_t *
322 {
323  return ((cnat_translation_t *) (((char *) node) -
325  ct_node)));
326 }
327 
328 static void
330 {
331  /**/}
332 
333 /*
334  * A back walk has reached this ABF policy
335  */
339 {
340  /*
341  * re-stack the fmask on the n-eos of the via
342  */
344 
346 
348 }
349 
350 /*
351  * The translation's graph node virtual function table
352  */
353 static const fib_node_vft_t cnat_translation_vft = {
355  .fnv_last_lock = cnat_translation_last_lock_gone,
356  .fnv_back_walk = cnat_translation_back_walk_notify,
357 };
358 
359 static clib_error_t *
361  unformat_input_t * input,
362  vlib_cli_command_t * cmd)
363 {
364  u32 del_index = INDEX_INVALID;
365  ip_protocol_t proto = IP_PROTOCOL_TCP;
366  cnat_endpoint_t vip;
368  cnat_endpoint_tuple_t tmp, *paths = NULL, *path;
369 
371  {
372  if (unformat (input, "add"))
373  del_index = INDEX_INVALID;
374  else if (unformat (input, "del %d", &del_index))
375  ;
376  else if (unformat (input, "proto %U", unformat_ip_protocol, &proto))
377  ;
378  else if (unformat (input, "vip %U", unformat_cnat_ep, &vip))
379  flags = CNAT_FLAG_EXCLUSIVE;
380  else if (unformat (input, "real %U", unformat_cnat_ep, &vip))
381  flags = 0;
382  else if (unformat (input, "to %U", unformat_cnat_ep_tuple, &tmp))
383  {
384  pool_get (paths, path);
385  clib_memcpy (path, &tmp, sizeof (cnat_endpoint_tuple_t));
386  }
387  else
388  return (clib_error_return (0, "unknown input '%U'",
389  format_unformat_error, input));
390  }
391 
392  if (INDEX_INVALID == del_index)
393  cnat_translation_update (&vip, proto, paths, flags);
394  else
395  cnat_translation_delete (del_index);
396 
397  pool_free (paths);
398  return (NULL);
399 }
400 
401 /* *INDENT-OFF* */
402 VLIB_CLI_COMMAND (cnat_translation_cli_add_del_command, static) =
403 {
404  .path = "cnat translation",
405  .short_help = "cnat translation [add|del] proto [TCP|UDP] [vip|real] [ip] [port] [to [ip] [port]->[ip] [port]]",
406  .function = cnat_translation_cli_add_del,
407 };
408 /* *INDENT-ON* */
409 
410 static clib_error_t *
412 {
415  fib_node_register_new_type (&cnat_translation_vft);
416 
417  clib_bihash_init_8_8 (&cnat_translation_db, "CNat translation DB",
420 
421  return (NULL);
422 }
423 
425 
426 /*
427  * fd.io coding-style-patch-verification: ON
428  *
429  * Local Variables:
430  * eval: (c-set-style "gnu")
431  * End:
432  */
walk_rc_t(* cnat_translation_walk_cb_t)(index_t index, void *ctx)
Callback function invoked during a walk of all translations.
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
dpo_type_t cnat_client_dpo
Definition: cnat_client.c:26
static fib_node_back_walk_rc_t cnat_translation_back_walk_notify(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
format_function_t format_ip_protocol
Definition: format.h:45
unformat_function_t unformat_ip_protocol
Definition: format.h:46
fib_node_index_t fib_entry_track(u32 fib_index, const fib_prefix_t *prefix, fib_node_type_t child_type, index_t child_index, u32 *sibling)
Trackers are used on FIB entries by objects that which to track the changing state of the entry...
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:108
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:103
static_always_inline cnat_translation_t * cnat_translation_get(index_t cti)
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:255
unsigned long u64
Definition: types.h:89
static clib_error_t * cnat_translation_cli_add_del(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
void fib_entry_contribute_forwarding(fib_node_index_t fib_entry_index, fib_forward_chain_type_t fct, dpo_id_t *dpo)
Definition: fib_entry.c:437
static void cnat_tracker_release(cnat_ep_trk_t *trk)
void cnat_remove_translation_from_db(index_t cci, u16 port, ip_protocol_t proto)
Remove a translation from the bihash.
static void cnat_translation_last_lock_gone(fib_node_t *node)
ip_protocol_t ct_proto
The ip protocol for the translation.
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:630
A Translation represents the translation of a VEP to one of a set of real server addresses.
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:70
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
cnat_endpoint_t src_ep
Definition: cnat_types.h:61
index_t parent_cci
Parent cnat_client index if cloned via interpose or own index if vanilla client.
Definition: cnat_client.h:74
vl_api_fib_path_t path
Definition: mfib_types.api:34
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:252
index_t cnat_client_add(const ip_address_t *ip, u8 flags)
Definition: cnat_client.c:150
unsigned char u8
Definition: types.h:56
fib_node_type_t fib_node_register_new_type(const fib_node_vft_t *vft)
Create a new FIB node type and Register the function table for it.
Definition: fib_node.c:80
cnat_translation_t * cnat_translation_pool
enum fib_protocol_t_ fib_protocol_t
Protocol Type.
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define clib_memcpy(d, s, n)
Definition: string.h:180
index_t load_balance_create(u32 n_buckets, dpo_proto_t lb_proto, flow_hash_config_t fhc)
Definition: load_balance.c:263
uword unformat_cnat_ep(unformat_input_t *input, va_list *args)
Definition: cnat_types.c:30
cnat_endpoint_t dst_ep
Definition: cnat_types.h:60
load_balance_t * load_balance_pool
Pool of all DPOs.
Definition: load_balance.c:51
cnat_endpoint_t ct_vip
The Virtual end point.
static_always_inline cnat_translation_t * cnat_find_translation(index_t cti, u16 port, ip_protocol_t proto)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u32 cnat_translation_update(const cnat_endpoint_t *vip, ip_protocol_t proto, const cnat_endpoint_tuple_t *paths, u8 flags)
create or update a translation
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
Aggregate type for a prefix.
Definition: fib_types.h:203
#define clib_error_return(e, args...)
Definition: error.h:99
void ip_address_to_fib_prefix(const ip_address_t *addr, fib_prefix_t *prefix)
convert from a IP address to a FIB prefix
Definition: ip_types.c:268
unsigned int u32
Definition: types.h:88
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
static cnat_translation_t * cnat_translation_get_from_node(fib_node_t *node)
int cnat_translation_purge(void)
Purge all the trahslations.
enum ip_protocol ip_protocol_t
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread counters.
Definition: counter.h:285
index_t ct_cci
The client object this translation belongs on.
int cnat_translation_delete(u32 id)
Delete a translation.
vl_api_ip_proto_t proto
Definition: acl_types.api:50
u64 key
the key
Definition: bihash_8_8.h:41
long ctx[MAX_CONNS]
Definition: main.c:144
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static clib_error_t * cnat_translation_init(vlib_main_t *vm)
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:102
static void cnat_translation_stack(cnat_translation_t *ct)
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:302
dpo_id_t ct_dpo
The forwarding contributed by the entry.
u8 * format_cnat_endpoint(u8 *s, va_list *args)
Definition: cnat_types.c:65
An node in the FIB graph.
Definition: fib_node.h:295
static fib_node_type_t cnat_translation_fib_node_type
cnat_ep_trk_t * ct_paths
The vector of tracked back-ends.
static_always_inline cnat_client_t * cnat_client_get(index_t i)
Definition: cnat_client.h:91
#define pool_free(p)
Free a pool.
Definition: pool.h:427
fib_node_t ct_node
Linkage into the FIB graph.
u64 value
the value
Definition: bihash_8_8.h:42
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
void cnat_client_translation_added(index_t cci)
A translation that references this VIP was added.
Definition: cnat_client.c:113
static void cnat_tracker_track(index_t cti, const cnat_endpoint_tuple_t *path, cnat_ep_trk_t *trk)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
fib_node_get_t fnv_get
Definition: fib_node.h:283
static fib_node_t * cnat_translation_get_node(fib_node_index_t index)
static u8 * format_cnat_ep_trk(u8 *s, va_list *args)
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:299
cnat_endpoint_t ct_ep[VLIB_N_DIR]
The EP being tracked.
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:39
fib_protocol_t ip_address_family_to_fib_proto(ip_address_family_t af)
Definition: ip_types.c:221
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:186
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
Context passed between object during a back walk.
Definition: fib_node.h:208
vl_api_fib_path_t paths[n_paths]
Definition: ip.api:146
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
static clib_error_t * cnat_translation_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define ASSERT(truth)
void fib_entry_untrack(fib_node_index_t fei, u32 sibling)
Stop tracking a FIB entry.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
dpo_id_t ct_lb
The LB used to forward to the backends.
void cnat_client_translation_deleted(index_t cci)
A translation that references this VIP was deleted.
Definition: cnat_client.c:122
u8 * format_cnat_translation(u8 *s, va_list *args)
ip_address_family_t version
Definition: ip_types.h:50
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:324
#define IP_FLOW_HASH_DEFAULT
Default: 5-tuple without the "reverse" bit.
Definition: lookup.h:70
void load_balance_set_bucket(index_t lbi, u32 bucket, const dpo_id_t *next)
Definition: load_balance.c:280
u8 * format_dpo_id(u8 *s, va_list *args)
Format a DPO_id_t oject.
Definition: dpo.c:148
u32 translation_hash_buckets
Definition: cnat_types.h:95
typedef key
Definition: ipsec_types.api:85
void cnat_translation_walk(cnat_translation_walk_cb_t cb, void *ctx)
Walk/visit each of the translations.
Definition: defs.h:47
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:186
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
uword unformat_cnat_ep_tuple(unformat_input_t *input, va_list *args)
Definition: cnat_types.c:49
#define CNAT_FIB_TABLE
Definition: cnat_types.h:25
cnat_main_t cnat_main
Definition: cnat_types.c:18
clib_bihash_8_8_t cnat_translation_db
char * name
The counter collection&#39;s name.
Definition: counter.h:193
u32 index
Definition: flow_types.api:221
fib_node_index_t ct_fei
The FIB entry for the EP.
uword translation_hash_memory
Definition: cnat_types.h:92
A collection of combined counters.
Definition: counter.h:188
u16 port
Definition: lb_types.api:72
A FIB graph nodes virtual function table.
Definition: fib_node.h:282
enum fib_node_type_t_ fib_node_type_t
The types of nodes in a FIB graph.
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void cnat_add_translation_to_db(index_t cci, u16 port, ip_protocol_t proto, index_t cti)
Add a translation to the bihash.
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#define vec_foreach(var, vec)
Vector iterator.
ip_address_t ce_ip
Definition: cnat_types.h:54
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:558
import vnet interface_types api
Definition: sample.api:20
Data used to track an EP in the FIB.
index_t index
Own index (if copied for trace)
u8 flags
Translation flags.
fib_forward_chain_type_t fib_forw_chain_type_from_fib_proto(fib_protocol_t proto)
Convert from a fib-protocol to a chain type.
Definition: fib_types.c:430
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
A client is a representation of an IP address behind the NAT.
Definition: cnat_client.h:35
void dpo_stack(dpo_type_t child_type, dpo_proto_t child_proto, dpo_id_t *dpo, const dpo_id_t *parent)
Stack one DPO object on another, and thus establish a child-parent relationship.
Definition: dpo.c:516
u32 ct_sibling
The sibling on the entry&#39;s child list.
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128