FD.io VPP  v21.01.1
Vector Packet Processing
nat_affinity.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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  * @file
17  * @brief NAT plugin client-IP based session affinity for load-balancing
18  */
19 
20 #include <nat/nat_affinity.h>
21 #include <nat/nat.h>
22 
24 
25 #define AFFINITY_HASH_BUCKETS 65536
26 #define AFFINITY_HASH_MEMORY (2 << 25)
27 
28 u8 *
29 format_affinity_kvp (u8 * s, va_list * args)
30 {
31  clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
33 
34  k.as_u64[0] = v->key[0];
35  k.as_u64[1] = v->key[1];
36 
37  s = format (s, "client %U backend %U:%d proto %U index %llu",
40  clib_net_to_host_u16 (k.service_port),
42 
43  return s;
44 }
45 
46 void
48 {
51 
52  if (tm->n_vlib_mains > 1)
54  clib_bihash_init_16_8 (&nam->affinity_hash, "nat-affinity",
56  clib_bihash_set_kvp_format_fn_16_8 (&nam->affinity_hash,
58 }
59 
60 void
62 {
65 
66  if (tm->n_vlib_mains > 1)
68  clib_bihash_free_16_8 (&nam->affinity_hash);
69 }
70 
73 {
75  nam->vlib_main = vm;
76  return 0;
77 }
78 
81  ip4_address_t service_addr, u8 proto, u16 service_port)
82 {
84 
85  key->client_addr = client_addr;
86  key->service_addr = service_addr;
87  key->proto = proto;
88  key->service_port = service_port;
89 
90  kv->value = ~0ULL;
91 }
92 
93 u32
95 {
97  dlist_elt_t *head_elt;
98 
100 
101  pool_get (nam->list_pool, head_elt);
102  clib_dlist_init (nam->list_pool, head_elt - nam->list_pool);
103 
105 
106  return head_elt - nam->list_pool;
107 }
108 
109 void
110 nat_affinity_flush_service (u32 affinity_per_service_list_head_index)
111 {
113  u32 elt_index;
114  dlist_elt_t *elt;
115  nat_affinity_t *a;
117 
119 
120  while ((elt_index =
122  affinity_per_service_list_head_index)) !=
123  ~0)
124  {
125  elt = pool_elt_at_index (nam->list_pool, elt_index);
126  a = pool_elt_at_index (nam->affinity_pool, elt->value);
127  kv.key[0] = a->key.as_u64[0];
128  kv.key[1] = a->key.as_u64[1];
129  pool_put_index (nam->affinity_pool, elt->value);
130  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
131  nat_elog_warn ("affinity key del failed");
132  pool_put_index (nam->list_pool, elt_index);
133  }
134  pool_put_index (nam->list_pool, affinity_per_service_list_head_index);
135 
137 }
138 
139 int
141  ip4_address_t service_addr, u8 proto,
142  u16 service_port, u8 * backend_index)
143 {
146  nat_affinity_t *a;
147  int rv = 0;
148 
149  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
151  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
152  {
153  rv = 1;
154  goto unlock;
155  }
156 
157  a = pool_elt_at_index (nam->affinity_pool, value.value);
158  /* if already expired delete */
159  if (a->ref_cnt == 0)
160  {
161  if (a->expire < vlib_time_now (nam->vlib_main))
162  {
163  clib_dlist_remove (nam->list_pool, a->per_service_index);
164  pool_put_index (nam->list_pool, a->per_service_index);
165  pool_put_index (nam->affinity_pool, value.value);
166  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
167  nat_elog_warn ("affinity key del failed");
168  rv = 1;
169  goto unlock;
170  }
171  }
172  a->ref_cnt++;
173  *backend_index = a->backend_index;
174 
175 unlock:
177  return rv;
178 }
179 
180 static int
182 {
184  nat_affinity_t *a;
185 
186  a = pool_elt_at_index (nam->affinity_pool, kv->value);
187  if (a->ref_cnt == 0)
188  {
189  if (a->expire < vlib_time_now (nam->vlib_main))
190  {
191  clib_dlist_remove (nam->list_pool, a->per_service_index);
192  pool_put_index (nam->list_pool, a->per_service_index);
193  pool_put_index (nam->affinity_pool, kv->value);
194  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, kv, 0))
195  nat_elog_warn ("affinity key del failed");
196  return 1;
197  }
198  }
199 
200  return 0;
201 }
202 
203 int
205  ip4_address_t service_addr, u8 proto,
206  u16 service_port, u8 backend_index,
207  u32 sticky_time,
208  u32 affinity_per_service_list_head_index)
209 {
212  nat_affinity_t *a;
213  dlist_elt_t *list_elt;
214  int rv = 0;
215 
216  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
218  if (!clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
219  {
220  rv = 1;
221  nat_elog_notice ("affinity key already exist");
222  goto unlock;
223  }
224 
225  pool_get (nam->affinity_pool, a);
226  kv.value = a - nam->affinity_pool;
227  rv =
228  clib_bihash_add_or_overwrite_stale_16_8 (&nam->affinity_hash, &kv,
229  affinity_is_expired_cb, NULL);
230  if (rv)
231  {
232  nat_elog_notice ("affinity key add failed");
233  pool_put (nam->affinity_pool, a);
234  goto unlock;
235  }
236 
237  pool_get (nam->list_pool, list_elt);
238  clib_dlist_init (nam->list_pool, list_elt - nam->list_pool);
239  list_elt->value = a - nam->affinity_pool;
240  a->per_service_index = list_elt - nam->list_pool;
241  a->backend_index = backend_index;
242  a->ref_cnt = 1;
243  a->sticky_time = sticky_time;
244  a->key.as_u64[0] = kv.key[0];
245  a->key.as_u64[1] = kv.key[1];
246  clib_dlist_addtail (nam->list_pool, affinity_per_service_list_head_index,
247  a->per_service_index);
248 
249 unlock:
251  return rv;
252 }
253 
254 void
256  u8 proto, u16 service_port)
257 {
260  nat_affinity_t *a;
261 
262  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
264  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
265  goto unlock;
266 
267  a = pool_elt_at_index (nam->affinity_pool, value.value);
268  a->ref_cnt--;
269  if (a->ref_cnt == 0)
270  a->expire = (u64) a->sticky_time + vlib_time_now (nam->vlib_main);
271 
272 unlock:
274 }
275 
276 /*
277  * fd.io coding-style-patch-verification: ON
278  *
279  * Local Variables:
280  * eval: (c-set-style "gnu")
281  * End:
282  */
int nat_affinity_create_and_lock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port, u8 backend_index, u32 sticky_time, u32 affinity_per_service_list_head_index)
Create affinity record and take reference counting lock.
Definition: nat_affinity.c:204
ip4_address_t client_addr
Definition: nat_affinity.h:34
nat_affinity_main_t nat_affinity_main
Definition: nat_affinity.c:23
a
Definition: bitmap.h:544
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u8 * format_affinity_kvp(u8 *s, va_list *args)
Definition: nat_affinity.c:29
#define nat_elog_notice(nat_elog_str)
Definition: nat.h:1056
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
void nat_affinity_enable()
NAT affinity enable.
Definition: nat_affinity.c:47
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:129
format_function_t format_nat_protocol
Definition: nat.h:777
#define AFFINITY_HASH_BUCKETS
Definition: nat_affinity.c:25
#define nat_elog_warn(nat_elog_str)
Definition: nat.h:1058
vlib_main_t * vm
Definition: in2out_ed.c:1580
dlist_elt_t * list_pool
Definition: nat_affinity.h:61
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
unsigned char u8
Definition: types.h:56
static void clib_spinlock_free(clib_spinlock_t *p)
Definition: lock.h:72
ip4_address_t service_addr
Definition: nat_affinity.h:33
format_function_t format_ip4_address
Definition: format.h:73
#define static_always_inline
Definition: clib.h:109
clib_bihash_16_8_t affinity_hash
Definition: nat_affinity.h:59
description fragment has unexpected format
Definition: map.api:433
vlib_main_t * vlib_main
Definition: nat_affinity.h:62
unsigned int u32
Definition: types.h:88
void nat_affinity_unlock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port)
Release a reference counting lock for affinity.
Definition: nat_affinity.c:255
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
clib_spinlock_t affinity_lock
Definition: nat_affinity.h:60
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:546
vl_api_ip_proto_t proto
Definition: acl_types.api:51
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
unsigned short u16
Definition: types.h:57
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
static int affinity_is_expired_cb(clib_bihash_kv_16_8_t *kv, void *arg)
Definition: nat_affinity.c:181
nat_affinity_t * affinity_pool
Definition: nat_affinity.h:58
u32 nat_affinity_get_per_service_list_head_index(void)
Get new affinity per service list head index.
Definition: nat_affinity.c:94
int nat_affinity_find_and_lock(ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port, u8 *backend_index)
Find service backend index for client-IP and take a reference counting lock.
Definition: nat_affinity.c:140
static_always_inline void make_affinity_kv(clib_bihash_kv_16_8_t *kv, ip4_address_t client_addr, ip4_address_t service_addr, u8 proto, u16 service_port)
Definition: nat_affinity.c:80
u8 value
Definition: qos.api:54
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:330
clib_error_t * nat_affinity_init(vlib_main_t *vm)
Initialize NAT client-IP based affinity.
Definition: nat_affinity.c:72
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
u32 value
Definition: dlist.h:32
typedef key
Definition: ipsec_types.api:86
void nat_affinity_disable()
NAT affinity disable.
Definition: nat_affinity.c:61
void nat_affinity_flush_service(u32 affinity_per_service_list_head_index)
Flush all service affinity data.
Definition: nat_affinity.c:110
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
NAT plugin client-IP based session affinity for load-balancing.
#define AFFINITY_HASH_MEMORY
Definition: nat_affinity.c:26
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:106
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117