FD.io VPP  v20.09-64-g4f7b92f0a
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  {
52  }
54  dpo_reset (&cc->cc_parent);
55  pool_put (cnat_client_pool, cc);
56 }
57 
58 void
59 cnat_client_free_by_ip (ip46_address_t * ip, u8 af)
60 {
61  cnat_client_t *cc;
62  cc = (AF_IP4 == af ?
63  cnat_client_ip4_find (&ip->ip4) : cnat_client_ip6_find (&ip->ip6));
64  /* This can happen if the translation gets deleted
65  before the session */
66  if (NULL == cc)
67  return;
68  if ((0 == cnat_client_uncnt_session (cc))
69  && (cc->flags & CNAT_FLAG_EXPIRES))
71 }
72 
73 void
75 {
76  /* This processes ips stored in the throttle pool
77  to update session refcounts
78  and should be called before cnat_client_free_by_ip */
80  cnat_client_t *cc;
81  int nthreads;
82  u32 *del_vec = NULL, *ai;
84  nthreads = tm->n_threads + 1;
85  for (int i = 0; i < nthreads; i++)
86  {
87  vec_reset_length (del_vec);
88  clib_spinlock_lock (&cnat_client_db.throttle_pool_lock[i]);
89  /* *INDENT-OFF* */
90  pool_foreach(addr, cnat_client_db.throttle_pool[i], ({
91  cc = (AF_IP4 == addr->version ?
92  cnat_client_ip4_find (&ip_addr_v4(addr)) :
93  cnat_client_ip6_find (&ip_addr_v6(addr)));
94  /* Client might not already be created */
95  if (NULL != cc)
96  {
97  cnat_client_cnt_session (cc);
98  vec_add1(del_vec, addr - cnat_client_db.throttle_pool[i]);
99  }
100  }));
101  /* *INDENT-ON* */
102  vec_foreach (ai, del_vec)
103  {
104  /* Free session */
105  addr = pool_elt_at_index (cnat_client_db.throttle_pool[i], *ai);
106  pool_put (cnat_client_db.throttle_pool[i], addr);
107  }
108  clib_spinlock_unlock (&cnat_client_db.throttle_pool_lock[i]);
109  }
110 }
111 
112 void
114 {
115  cnat_client_t *cc;
116  cc = cnat_client_get (cci);
117  ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
118  cc->tr_refcnt++;
119 }
120 
121 void
123 {
124  cnat_client_t *cc;
125 
126  cc = cnat_client_get (cci);
127  ASSERT (!(cc->flags & CNAT_FLAG_EXPIRES));
128  cc->tr_refcnt--;
129 
130  if (0 == cc->tr_refcnt)
131  cnat_client_destroy (cc);
132 }
133 
134 static void
136 {
137  index_t cci;
138 
139  cci = cc - cnat_client_pool;
140 
141  if (ip_addr_version (&cc->cc_ip) == AF_IP4)
142  hash_set (cnat_client_db.crd_cip4, ip_addr_v4 (&cc->cc_ip).as_u32, cci);
143  else
144  hash_set_mem_alloc (&cnat_client_db.crd_cip6,
145  &ip_addr_v6 (&cc->cc_ip), cci);
146 }
147 
148 
149 index_t
151 {
152  cnat_client_t *cc;
153  dpo_id_t tmp = DPO_INVALID;
154  fib_node_index_t fei;
155  dpo_proto_t dproto;
156  fib_prefix_t pfx;
157  index_t cci;
158  u32 fib_flags;
159 
160  /* check again if we need this client */
161  cc = (AF_IP4 == ip->version ?
162  cnat_client_ip4_find (&ip->ip.ip4) :
163  cnat_client_ip6_find (&ip->ip.ip6));
164 
165  if (NULL != cc)
166  return (cc - cnat_client_pool);
167 
168 
169  pool_get_aligned (cnat_client_pool, cc, CLIB_CACHE_LINE_BYTES);
170  cc->cc_locks = 1;
171  cci = cc - cnat_client_pool;
172  cc->parent_cci = cci;
173  cc->flags = flags;
174 
175  ip_address_copy (&cc->cc_ip, ip);
176  cnat_client_db_add (cc);
177 
178  ip_address_to_fib_prefix (&cc->cc_ip, &pfx);
179 
180  dproto = fib_proto_to_dpo (pfx.fp_proto);
181  dpo_set (&tmp, cnat_client_dpo, dproto, cci);
182  dpo_stack (cnat_client_dpo, dproto, &cc->cc_parent, drop_dpo_get (dproto));
183 
185  fib_flags |= (flags & CNAT_FLAG_EXCLUSIVE) ?
187 
189  &pfx, cnat_fib_source, fib_flags,
190  &tmp);
191 
192  cc = pool_elt_at_index (cnat_client_pool, cci);
193  cc->cc_fei = fei;
194 
195  return (cci);
196 }
197 
198 void
200 {
201  /* RPC call to add a client from the dataplane */
202  index_t cci;
203  cnat_client_t *cc;
205  cc = pool_elt_at_index (cnat_client_pool, cci);
207  /* Process throttled calls if any */
209 }
210 
211 /**
212  * Interpose a policy DPO
213  */
214 static void
216  const dpo_id_t * parent, dpo_id_t * clone)
217 {
218  cnat_client_t *cc, *cc_clone;
219 
220  pool_get_zero (cnat_client_pool, cc_clone);
221  cc = cnat_client_get (original->dpoi_index);
222 
223  cc_clone->cc_fei = FIB_NODE_INDEX_INVALID;
224  cc_clone->parent_cci = cc->parent_cci;
225  cc_clone->flags = cc->flags;
226  ip_address_copy (&cc_clone->cc_ip, &cc->cc_ip);
227 
228  /* stack the clone on the FIB provided parent */
229  dpo_stack (cnat_client_dpo, original->dpoi_proto, &cc_clone->cc_parent,
230  parent);
231 
232  /* return the clone */
233  dpo_set (clone,
235  original->dpoi_proto, cc_clone - cnat_client_pool);
236 }
237 
238 int
240 {
241  ASSERT (0 == hash_elts (cnat_client_db.crd_cip6));
242  ASSERT (0 == hash_elts (cnat_client_db.crd_cip4));
243  ASSERT (0 == pool_elts (cnat_client_pool));
244  return (0);
245 }
246 
247 u8 *
248 format_cnat_client (u8 * s, va_list * args)
249 {
250  index_t cci = va_arg (*args, index_t);
251  u32 indent = va_arg (*args, u32);
252 
253  cnat_client_t *cc = pool_elt_at_index (cnat_client_pool, cci);
254 
255  s = format (s, "[%d] cnat-client:[%U] tr:%d sess:%d", cci,
256  format_ip_address, &cc->cc_ip,
257  cc->tr_refcnt, cc->session_refcnt);
258  if (cc->flags & CNAT_FLAG_EXPIRES)
259  s = format (s, " expires");
260 
261  if (cc->flags & CNAT_FLAG_EXCLUSIVE)
262  s = format (s, " exclusive");
263 
264  if (cnat_client_is_clone (cc))
265  s = format (s, "\n%Uclone of [%d]\n%U%U",
266  format_white_space, indent + 2, cc->parent_cci,
267  format_white_space, indent + 2,
268  format_dpo_id, &cc->cc_parent, indent + 4);
269 
270  return (s);
271 }
272 
273 
274 static clib_error_t *
276  unformat_input_t * input, vlib_cli_command_t * cmd)
277 {
278  index_t cci;
279 
280  cci = INDEX_INVALID;
281 
283  {
284  if (unformat (input, "%d", &cci))
285  ;
286  else
287  return (clib_error_return (0, "unknown input '%U'",
288  format_unformat_error, input));
289  }
290 
291  if (INDEX_INVALID == cci)
292  {
293  /* *INDENT-OFF* */
294  pool_foreach_index(cci, cnat_client_pool, ({
295  vlib_cli_output(vm, "%U", format_cnat_client, cci, 0);
296  }))
297  /* *INDENT-ON* */
298 
299  vlib_cli_output (vm, "%d clients", pool_elts (cnat_client_pool));
300  vlib_cli_output (vm, "%d timestamps", pool_elts (cnat_timestamps));
301  }
302  else
303  {
304  vlib_cli_output (vm, "Invalid policy ID:%d", cci);
305  }
306 
307  return (NULL);
308 }
309 
310 /* *INDENT-OFF* */
311 VLIB_CLI_COMMAND (cnat_client_show_cmd_node, static) = {
312  .path = "show cnat client",
313  .function = cnat_client_show,
314  .short_help = "show cnat client",
315  .is_mp_safe = 1,
316 };
317 /* *INDENT-ON* */
318 
319 const static char *const cnat_client_dpo_ip4_nodes[] = {
320  "ip4-cnat-tx",
321  NULL,
322 };
323 
324 const static char *const cnat_client_dpo_ip6_nodes[] = {
325  "ip6-cnat-tx",
326  NULL,
327 };
328 
329 const static char *const *const cnat_client_dpo_nodes[DPO_PROTO_NUM] = {
332 };
333 
334 static void
336 {
337  cnat_client_t *cc;
338 
339  cc = cnat_client_get (dpo->dpoi_index);
340 
341  cc->cc_locks++;
342 }
343 
344 static void
346 {
347  cnat_client_t *cc;
348 
349  cc = cnat_client_get (dpo->dpoi_index);
350 
351  cc->cc_locks--;
352 
353  if (0 == cc->cc_locks)
354  {
356  pool_put (cnat_client_pool, cc);
357  }
358 }
359 
360 u8 *
361 format_cnat_client_dpo (u8 * s, va_list * ap)
362 {
363  index_t cci = va_arg (*ap, index_t);
364  u32 indent = va_arg (*ap, u32);
365 
366  s = format (s, "%U", format_cnat_client, cci, indent);
367 
368  return (s);
369 }
370 
371 const static dpo_vft_t cnat_client_dpo_vft = {
373  .dv_unlock = cnat_client_dpo_unlock,
374  .dv_format = format_cnat_client_dpo,
375  .dv_mk_interpose = cnat_client_dpo_interpose,
376 };
377 
378 static clib_error_t *
380 {
382  int nthreads = tm->n_threads + 1;
383  int i;
384  cnat_client_dpo = dpo_register_new_type (&cnat_client_dpo_vft,
386 
387  cnat_client_db.crd_cip6 = hash_create_mem (0,
388  sizeof (ip6_address_t),
389  sizeof (uword));
390 
391  vec_validate (cnat_client_db.throttle_pool, nthreads);
392  vec_validate (cnat_client_db.throttle_pool_lock, nthreads);
393  for (i = 0; i < nthreads; i++)
394  clib_spinlock_init (&cnat_client_db.throttle_pool_lock[i]);
395 
396  return (NULL);
397 }
398 
400 
401 /*
402  * fd.io coding-style-patch-verification: ON
403  *
404  * Local Variables:
405  * eval: (c-set-style "gnu")
406  * End:
407  */
#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:212
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:406
#define ip_addr_v6(_a)
Definition: ip_types.h:59
int cnat_client_purge(void)
Check all the clients were purged by translation & session purge.
Definition: cnat_client.c:239
static void cnat_client_dpo_lock(dpo_id_t *dpo)
Definition: cnat_client.c:335
#define hash_set(h, key, value)
Definition: hash.h:255
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:119
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:80
A virtual function table regisitered for a DPO type.
Definition: dpo.h:401
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:103
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:255
Definition: fib_entry.h:123
static clib_error_t * cnat_client_init(vlib_main_t *vm)
Definition: cnat_client.c:379
dpo_proto_t dpoi_proto
the data-path protocol of the type.
Definition: dpo.h:178
ip46_address_t ip
Definition: ip_types.h:49
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
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:361
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
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:345
#define ip_addr_version(_a)
Definition: ip_types.h:60
index_t cnat_client_add(const ip_address_t *ip, u8 flags)
Definition: cnat_client.c:150
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:108
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 pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static const char *const cnat_client_dpo_ip6_nodes[]
Definition: cnat_client.c:324
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
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: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
static void cnat_client_db_add(cnat_client_t *cc)
Definition: cnat_client.c:135
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:342
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
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:534
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:74
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:302
static const char *const *const cnat_client_dpo_nodes[DPO_PROTO_NUM]
Definition: cnat_client.c:329
u8 * format_cnat_client(u8 *s, va_list *args)
Definition: cnat_client.c:248
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:319
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:246
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:145
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:113
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:910
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:30
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:275
#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:58
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:199
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:215
void cnat_client_translation_deleted(index_t cci)
A translation that references this VIP was deleted.
Definition: cnat_client.c:122
ip_address_family_t version
Definition: ip_types.h:50
void cnat_client_free_by_ip(ip46_address_t *ip, u8 af)
Definition: cnat_client.c:59
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:324
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:186
vl_api_address_t ip
Definition: l2.api:501
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
#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:25
u64 uword
Definition: types.h:112
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:197
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:130
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 pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:558
#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: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
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128