FD.io VPP  v21.01.1
Vector Packet Processing
cnat_client.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_table.h>
17 #include <vnet/dpo/drop_dpo.h>
18 
19 #include <cnat/cnat_client.h>
20 #include <cnat/cnat_translation.h>
21 
23 
25 
27 
30 {
31  return (FIB_NODE_INDEX_INVALID == cc->cc_fei);
32 }
33 
34 static void
36 {
37  if (ip_addr_version (&cc->cc_ip) == AF_IP4)
38  hash_unset (cnat_client_db.crd_cip4, ip_addr_v4 (&cc->cc_ip).as_u32);
39  else
40  hash_unset_mem_free (&cnat_client_db.crd_cip6, &ip_addr_v6 (&cc->cc_ip));
41 }
42 
43 static void
45 {
47  if (!(cc->flags & CNAT_FLAG_EXCLUSIVE))
48  {
51  }
53  dpo_reset (&cc->cc_parent);
54  pool_put (cnat_client_pool, cc);
55 }
56 
57 void
58 cnat_client_free_by_ip (ip46_address_t * ip, u8 af)
59 {
60  cnat_client_t *cc;
61  cc = (AF_IP4 == af ?
62  cnat_client_ip4_find (&ip->ip4) : cnat_client_ip6_find (&ip->ip6));
63  ASSERT (NULL != cc);
64 
65  if ((0 == cnat_client_uncnt_session (cc))
66  && (cc->flags & CNAT_FLAG_EXPIRES) && (0 == cc->tr_refcnt))
68 }
69 
70 void
72 {
73  /* This processes ips stored in the throttle pool
74  to update session refcounts
75  and should be called before cnat_client_free_by_ip */
77  cnat_client_t *cc;
78  int nthreads;
79  u32 *del_vec = NULL, *ai;
81  nthreads = tm->n_threads + 1;
82  for (int i = 0; i < nthreads; i++)
83  {
84  vec_reset_length (del_vec);
85  clib_spinlock_lock (&cnat_client_db.throttle_pool_lock[i]);
86  /* *INDENT-OFF* */
87  pool_foreach (addr, cnat_client_db.throttle_pool[i]) {
88  cc = (AF_IP4 == addr->version ?
91  /* Client might not already be created */
92  if (NULL != cc)
93  {
95  vec_add1(del_vec, addr - cnat_client_db.throttle_pool[i]);
96  }
97  }
98  /* *INDENT-ON* */
99  vec_foreach (ai, del_vec)
100  {
101  addr = pool_elt_at_index (cnat_client_db.throttle_pool[i], *ai);
102  pool_put (cnat_client_db.throttle_pool[i], addr);
103  }
104  clib_spinlock_unlock (&cnat_client_db.throttle_pool_lock[i]);
105  }
106 }
107 
108 void
110 {
111  cnat_client_t *cc;
112  if (INDEX_INVALID == cci)
113  return;
114 
115  cc = cnat_client_get (cci);
116  ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
117  cc->tr_refcnt++;
118 }
119 
120 void
122 {
123  cnat_client_t *cc;
124  if (INDEX_INVALID == cci)
125  return;
126 
127  cc = cnat_client_get (cci);
128  ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
129  cc->tr_refcnt--;
130 
131  if (0 == cc->tr_refcnt && 0 == cc->session_refcnt)
132  cnat_client_destroy (cc);
133 }
134 
135 static void
137 {
138  index_t cci;
139 
140  cci = cc - cnat_client_pool;
141 
142  if (ip_addr_version (&cc->cc_ip) == AF_IP4)
143  hash_set (cnat_client_db.crd_cip4, ip_addr_v4 (&cc->cc_ip).as_u32, cci);
144  else
145  hash_set_mem_alloc (&cnat_client_db.crd_cip6,
146  &ip_addr_v6 (&cc->cc_ip), cci);
147 }
148 
149 
150 index_t
152 {
153  cnat_client_t *cc;
154  dpo_id_t tmp = DPO_INVALID;
155  fib_node_index_t fei;
156  dpo_proto_t dproto;
157  fib_prefix_t pfx;
158  index_t cci;
159  u32 fib_flags;
160 
161  /* check again if we need this client */
162  cc = (AF_IP4 == ip->version ?
163  cnat_client_ip4_find (&ip->ip.ip4) :
164  cnat_client_ip6_find (&ip->ip.ip6));
165 
166  if (NULL != cc)
167  return (cc - cnat_client_pool);
168 
169 
170  pool_get_aligned (cnat_client_pool, cc, CLIB_CACHE_LINE_BYTES);
171  cc->cc_locks = 1;
172  cci = cc - cnat_client_pool;
173  cc->parent_cci = cci;
174  cc->flags = flags;
175  cc->tr_refcnt = 0;
176  cc->session_refcnt = 0;
177 
178  ip_address_copy (&cc->cc_ip, ip);
179  cnat_client_db_add (cc);
180 
181  ip_address_to_fib_prefix (&cc->cc_ip, &pfx);
182 
183  dproto = fib_proto_to_dpo (pfx.fp_proto);
184  dpo_set (&tmp, cnat_client_dpo, dproto, cci);
185  dpo_stack (cnat_client_dpo, dproto, &cc->cc_parent, drop_dpo_get (dproto));
186 
188  fib_flags |= (flags & CNAT_FLAG_EXCLUSIVE) ?
190 
192  &pfx, cnat_fib_source, fib_flags,
193  &tmp);
194 
195  cc = pool_elt_at_index (cnat_client_pool, cci);
196  cc->cc_fei = fei;
197 
198  return (cci);
199 }
200 
201 void
203 {
204  /* RPC call to add a client from the dataplane */
205  index_t cci;
206  cnat_client_t *cc;
208  cc = pool_elt_at_index (cnat_client_pool, cci);
210  /* Process throttled calls if any */
212 }
213 
214 /**
215  * Interpose a policy DPO
216  */
217 static void
219  const dpo_id_t * parent, dpo_id_t * clone)
220 {
221  cnat_client_t *cc, *cc_clone;
222 
223  pool_get_zero (cnat_client_pool, cc_clone);
224  cc = cnat_client_get (original->dpoi_index);
225 
226  cc_clone->cc_fei = FIB_NODE_INDEX_INVALID;
227  cc_clone->parent_cci = cc->parent_cci;
228  cc_clone->flags = cc->flags;
229  ip_address_copy (&cc_clone->cc_ip, &cc->cc_ip);
230 
231  /* stack the clone on the FIB provided parent */
232  dpo_stack (cnat_client_dpo, original->dpoi_proto, &cc_clone->cc_parent,
233  parent);
234 
235  /* return the clone */
236  dpo_set (clone,
238  original->dpoi_proto, cc_clone - cnat_client_pool);
239 }
240 
241 int
243 {
245  int nthreads;
246  nthreads = tm->n_threads + 1;
247  ASSERT (0 == hash_elts (cnat_client_db.crd_cip6));
248  ASSERT (0 == hash_elts (cnat_client_db.crd_cip4));
249  ASSERT (0 == pool_elts (cnat_client_pool));
250  for (int i = 0; i < nthreads; i++)
251  {
252  ASSERT (0 == pool_elts (cnat_client_db.throttle_pool[i]));
253  }
254  return (0);
255 }
256 
257 u8 *
258 format_cnat_client (u8 * s, va_list * args)
259 {
260  index_t cci = va_arg (*args, index_t);
261  u32 indent = va_arg (*args, u32);
262 
263  cnat_client_t *cc = pool_elt_at_index (cnat_client_pool, cci);
264 
265  s = format (s, "[%d] cnat-client:[%U] tr:%d sess:%d", cci,
266  format_ip_address, &cc->cc_ip,
267  cc->tr_refcnt, cc->session_refcnt);
268  if (cc->flags & CNAT_FLAG_EXPIRES)
269  s = format (s, " expires");
270 
271  if (cc->flags & CNAT_FLAG_EXCLUSIVE)
272  s = format (s, " exclusive");
273 
274  if (cnat_client_is_clone (cc))
275  s = format (s, "\n%Uclone of [%d]\n%U%U",
276  format_white_space, indent + 2, cc->parent_cci,
277  format_white_space, indent + 2,
278  format_dpo_id, &cc->cc_parent, indent + 4);
279 
280  return (s);
281 }
282 
283 
284 static clib_error_t *
286  unformat_input_t * input, vlib_cli_command_t * cmd)
287 {
288  index_t cci;
289 
290  cci = INDEX_INVALID;
291 
293  {
294  if (unformat (input, "%d", &cci))
295  ;
296  else
297  return (clib_error_return (0, "unknown input '%U'",
298  format_unformat_error, input));
299  }
300 
301  if (INDEX_INVALID == cci)
302  {
303  /* *INDENT-OFF* */
304  pool_foreach_index (cci, cnat_client_pool)
305  vlib_cli_output(vm, "%U", format_cnat_client, cci, 0);
306  /* *INDENT-ON* */
307 
308  vlib_cli_output (vm, "%d clients", pool_elts (cnat_client_pool));
309  vlib_cli_output (vm, "%d timestamps", pool_elts (cnat_timestamps));
310  }
311  else
312  {
313  vlib_cli_output (vm, "Invalid policy ID:%d", cci);
314  }
315 
316  return (NULL);
317 }
318 
319 /* *INDENT-OFF* */
320 VLIB_CLI_COMMAND (cnat_client_show_cmd_node, static) = {
321  .path = "show cnat client",
322  .function = cnat_client_show,
323  .short_help = "show cnat client",
324  .is_mp_safe = 1,
325 };
326 /* *INDENT-ON* */
327 
328 const static char *const cnat_client_dpo_ip4_nodes[] = {
329  "ip4-cnat-tx",
330  NULL,
331 };
332 
333 const static char *const cnat_client_dpo_ip6_nodes[] = {
334  "ip6-cnat-tx",
335  NULL,
336 };
337 
338 const static char *const *const cnat_client_dpo_nodes[DPO_PROTO_NUM] = {
341 };
342 
343 static void
345 {
346  cnat_client_t *cc;
347 
348  cc = cnat_client_get (dpo->dpoi_index);
349 
350  cc->cc_locks++;
351 }
352 
353 static void
355 {
356  cnat_client_t *cc;
357 
358  cc = cnat_client_get (dpo->dpoi_index);
359 
360  cc->cc_locks--;
361 
362  if (0 == cc->cc_locks)
363  {
365  pool_put (cnat_client_pool, cc);
366  }
367 }
368 
369 u8 *
370 format_cnat_client_dpo (u8 * s, va_list * ap)
371 {
372  index_t cci = va_arg (*ap, index_t);
373  u32 indent = va_arg (*ap, u32);
374 
375  s = format (s, "%U", format_cnat_client, cci, indent);
376 
377  return (s);
378 }
379 
380 const static dpo_vft_t cnat_client_dpo_vft = {
382  .dv_unlock = cnat_client_dpo_unlock,
383  .dv_format = format_cnat_client_dpo,
384  .dv_mk_interpose = cnat_client_dpo_interpose,
385 };
386 
387 static clib_error_t *
389 {
391  int nthreads = tm->n_threads + 1;
392  int i;
393  cnat_client_dpo = dpo_register_new_type (&cnat_client_dpo_vft,
395 
396  cnat_client_db.crd_cip6 = hash_create_mem (0,
397  sizeof (ip6_address_t),
398  sizeof (uword));
399 
400  vec_validate (cnat_client_db.throttle_pool, nthreads);
401  vec_validate (cnat_client_db.throttle_pool_lock, nthreads);
402  for (i = 0; i < nthreads; i++)
403  clib_spinlock_init (&cnat_client_db.throttle_pool_lock[i]);
404 
405  return (NULL);
406 }
407 
409 
410 /*
411  * fd.io coding-style-patch-verification: ON
412  *
413  * Local Variables:
414  * eval: (c-set-style "gnu")
415  * End:
416  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:211
dpo_type_t cnat_client_dpo
Definition: cnat_client.c:26
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:411
#define ip_addr_v6(_a)
Definition: ip_types.h:92
int cnat_client_purge(void)
Check all the clients were purged by translation & session purge.
Definition: cnat_client.c:242
static void cnat_client_dpo_lock(dpo_id_t *dpo)
Definition: cnat_client.c:344
#define hash_set(h, key, value)
Definition: hash.h:255
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
#define pool_foreach_index(i, v)
Definition: pool.h:569
u32 session_refcnt
Session refcount for cleanup.
Definition: cnat_client.h:67
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
A virtual function table regisitered for a DPO type.
Definition: dpo.h:406
static void cnat_client_db_remove(cnat_client_t *cc)
Definition: cnat_client.c:35
ip_address_t ** throttle_pool
Definition: cnat_client.h:147
#define hash_unset(h, key)
Definition: hash.h:261
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:254
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
Definition: fib_entry.h:123
static clib_error_t * cnat_client_init(vlib_main_t *vm)
Definition: cnat_client.c:388
dpo_proto_t dpoi_proto
the data-path protocol of the type.
Definition: dpo.h:180
ip46_address_t ip
Definition: ip_types.h:81
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
dpo_id_t cc_parent
How to send packets to this client post translation.
Definition: cnat_client.h:47
u8 * format_cnat_client_dpo(u8 *s, va_list *ap)
Definition: cnat_client.c:370
vlib_main_t * vm
Definition: in2out_ed.c:1580
u32 tr_refcnt
Translations refcount for cleanup.
Definition: cnat_client.h:62
index_t parent_cci
Parent cnat_client index if cloned via interpose or own index if vanilla client.
Definition: cnat_client.h:74
static void cnat_client_dpo_unlock(dpo_id_t *dpo)
Definition: cnat_client.c:354
#define ip_addr_version(_a)
Definition: ip_types.h:93
index_t cnat_client_add(const ip_address_t *ip, u8 flags)
Definition: cnat_client.c:151
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
const dpo_id_t * drop_dpo_get(dpo_proto_t proto)
Definition: drop_dpo.c:25
Definition: fib_entry.h:120
#define static_always_inline
Definition: clib.h:109
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static const char *const cnat_client_dpo_ip6_nodes[]
Definition: cnat_client.c:333
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
description fragment has unexpected format
Definition: map.api:433
static_always_inline u32 cnat_client_uncnt_session(cnat_client_t *cc)
Del a session refcnt to this client.
Definition: cnat_client.h:212
Aggregate type for a prefix.
Definition: fib_types.h:202
#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:271
static void cnat_client_db_add(cnat_client_t *cc)
Definition: cnat_client.c:136
unsigned int u32
Definition: types.h:88
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:347
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
static_always_inline u32 cnat_client_cnt_session(cnat_client_t *cc)
Add a session refcnt to this client.
Definition: cnat_client.h:202
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
Definition: fib_entry.h:116
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:546
fib_source_t cnat_fib_source
Definition: cnat_types.c:19
struct _unformat_input_t unformat_input_t
ip_address_t addr
Definition: cnat_client.h:98
cnat_timestamp_t * cnat_timestamps
Definition: cnat_types.c:20
void cnat_client_throttle_pool_process()
Definition: cnat_client.c:71
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
static const char *const *const cnat_client_dpo_nodes[DPO_PROTO_NUM]
Definition: cnat_client.c:338
u8 * format_cnat_client(u8 *s, va_list *args)
Definition: cnat_client.c:258
static_always_inline cnat_client_t * cnat_client_ip4_find(const ip4_address_t *ip)
Find a client from an IP4 address.
Definition: cnat_client.h:157
static const char *const cnat_client_dpo_ip4_nodes[]
Definition: cnat_client.c:328
static_always_inline cnat_client_t * cnat_client_get(index_t i)
Definition: cnat_client.h:91
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P with alignment A.
Definition: pool.h:245
int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source)
fib_node_index_t cc_fei
the FIB entry this client sources
Definition: cnat_client.h:52
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
clib_spinlock_t * throttle_pool_lock
Definition: cnat_client.h:148
void cnat_client_translation_added(index_t cci)
A translation that references this VIP was added.
Definition: cnat_client.c:109
void fib_table_entry_delete_index(fib_node_index_t fib_entry_index, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:919
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
u8 * format_ip_address(u8 *s, va_list *args)
Definition: ip_types.c:21
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
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
u32 cc_locks
number of DPO locks
Definition: cnat_client.h:57
static clib_error_t * cnat_client_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cnat_client.c:285
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:324
static void cnat_client_destroy(cnat_client_t *cc)
Definition: cnat_client.c:44
static uword hash_elts(void *v)
Definition: hash.h:118
#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:91
void cnat_client_learn(const cnat_learn_arg_t *l)
Called in the main thread by RPC from the workers to learn a new client.
Definition: cnat_client.c:202
static void cnat_client_dpo_interpose(const dpo_id_t *original, const dpo_id_t *parent, dpo_id_t *clone)
Interpose a policy DPO.
Definition: cnat_client.c:218
void cnat_client_translation_deleted(index_t cci)
A translation that references this VIP was deleted.
Definition: cnat_client.c:121
ip_address_family_t version
Definition: ip_types.h:82
void cnat_client_free_by_ip(ip46_address_t *ip, u8 af)
Definition: cnat_client.c:58
static void hash_unset_mem_free(uword **h, const void *key)
Definition: hash.h:295
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:343
u8 * format_dpo_id(u8 *s, va_list *args)
Format a DPO_id_t oject.
Definition: dpo.c:148
static_always_inline cnat_client_t * cnat_client_ip6_find(const ip6_address_t *ip)
Find a client from an IP6 address.
Definition: cnat_client.h:186
DB of clients.
Definition: cnat_client.h:140
#define DPO_PROTO_NUM
Definition: dpo.h:70
static_always_inline u8 cnat_client_is_clone(cnat_client_t *cc)
Definition: cnat_client.c:29
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:188
vl_api_address_t ip
Definition: l2.api:501
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
#define CNAT_FIB_TABLE
Definition: cnat_types.h:27
u64 uword
Definition: types.h:112
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:202
cnat_client_db_t cnat_client_db
Definition: cnat_client.c:24
ip_address_t cc_ip
the client&#39;s IP address
Definition: cnat_client.h:42
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void ip_address_copy(ip_address_t *dst, const ip_address_t *src)
Definition: ip_types.c:133
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
cnat_client_t * cnat_client_pool
Definition: cnat_client.c:22
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.
static void hash_set_mem_alloc(uword **h, const void *key, uword v)
Definition: hash.h:279
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u8 flags
Client flags.
Definition: cnat_client.h:79
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:170
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:521
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127