FD.io VPP  v21.06
Vector Packet Processing
nat44_ed_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/lib/log.h>
21 
22 #include <nat/nat44-ed/nat44_ed.h>
24 
26 
27 #define AFFINITY_HASH_BUCKETS 65536
28 #define AFFINITY_HASH_MEMORY (2 << 25)
29 
30 u8 *
31 format_affinity_kvp (u8 * s, va_list * args)
32 {
33  clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
35 
36  k.as_u64[0] = v->key[0];
37  k.as_u64[1] = v->key[1];
38 
39  s = format (s, "client %U backend %U:%d proto %U index %llu",
42  clib_net_to_host_u16 (k.service_port),
44 
45  return s;
46 }
47 
48 void
50 {
53 
54  if (tm->n_vlib_mains > 1)
56  clib_bihash_init_16_8 (&nam->affinity_hash, "nat-affinity",
58  clib_bihash_set_kvp_format_fn_16_8 (&nam->affinity_hash,
60 }
61 
62 void
64 {
67 
68  if (tm->n_vlib_mains > 1)
70  clib_bihash_free_16_8 (&nam->affinity_hash);
71 }
72 
75 {
77  nam->vlib_main = vm;
78  return 0;
79 }
80 
83  ip4_address_t service_addr, u8 proto, u16 service_port)
84 {
86 
87  key->client_addr = client_addr;
88  key->service_addr = service_addr;
89  key->proto = proto;
90  key->service_port = service_port;
91 
92  kv->value = ~0ULL;
93 }
94 
95 u32
97 {
99  dlist_elt_t *head_elt;
100 
102 
103  pool_get (nam->list_pool, head_elt);
104  clib_dlist_init (nam->list_pool, head_elt - nam->list_pool);
105 
107 
108  return head_elt - nam->list_pool;
109 }
110 
111 void
112 nat_affinity_flush_service (u32 affinity_per_service_list_head_index)
113 {
114  snat_main_t *sm = &snat_main;
116  u32 elt_index;
117  dlist_elt_t *elt;
118  nat_affinity_t *a;
120 
122 
123  while ((elt_index =
125  affinity_per_service_list_head_index)) !=
126  ~0)
127  {
128  elt = pool_elt_at_index (nam->list_pool, elt_index);
129  a = pool_elt_at_index (nam->affinity_pool, elt->value);
130  kv.key[0] = a->key.as_u64[0];
131  kv.key[1] = a->key.as_u64[1];
132  pool_put_index (nam->affinity_pool, elt->value);
133  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
134  nat_elog_warn (sm, "affinity key del failed");
135  pool_put_index (nam->list_pool, elt_index);
136  }
137  pool_put_index (nam->list_pool, affinity_per_service_list_head_index);
138 
140 }
141 
142 int
144  ip4_address_t service_addr, u8 proto,
145  u16 service_port, u8 *backend_index)
146 {
147  snat_main_t *sm = &snat_main;
150  nat_affinity_t *a;
151  int rv = 0;
152 
153  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
155  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
156  {
157  rv = 1;
158  goto unlock;
159  }
160 
161  a = pool_elt_at_index (nam->affinity_pool, value.value);
162  /* if already expired delete */
163  if (a->ref_cnt == 0)
164  {
165  if (a->expire < vlib_time_now (vm))
166  {
167  clib_dlist_remove (nam->list_pool, a->per_service_index);
168  pool_put_index (nam->list_pool, a->per_service_index);
169  pool_put_index (nam->affinity_pool, value.value);
170  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
171  nat_elog_warn (sm, "affinity key del failed");
172  rv = 1;
173  goto unlock;
174  }
175  }
176  a->ref_cnt++;
177  *backend_index = a->backend_index;
178 
179 unlock:
181  return rv;
182 }
183 
184 static int
186 {
187  snat_main_t *sm = &snat_main;
189  nat_affinity_t *a;
190 
191  a = pool_elt_at_index (nam->affinity_pool, kv->value);
192  if (a->ref_cnt == 0)
193  {
194  if (a->expire < vlib_time_now (nam->vlib_main))
195  {
196  clib_dlist_remove (nam->list_pool, a->per_service_index);
197  pool_put_index (nam->list_pool, a->per_service_index);
198  pool_put_index (nam->affinity_pool, kv->value);
199  if (clib_bihash_add_del_16_8 (&nam->affinity_hash, kv, 0))
200  nat_elog_warn (sm, "affinity key del failed");
201  return 1;
202  }
203  }
204 
205  return 0;
206 }
207 
208 int
210  ip4_address_t service_addr, u8 proto,
211  u16 service_port, u8 backend_index,
212  u32 sticky_time,
213  u32 affinity_per_service_list_head_index)
214 {
215  snat_main_t *sm = &snat_main;
218  nat_affinity_t *a;
219  dlist_elt_t *list_elt;
220  int rv = 0;
221 
222  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
224  if (!clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
225  {
226  rv = 1;
227  nat_elog_notice (sm, "affinity key already exist");
228  goto unlock;
229  }
230 
231  pool_get (nam->affinity_pool, a);
232  kv.value = a - nam->affinity_pool;
233  rv =
234  clib_bihash_add_or_overwrite_stale_16_8 (&nam->affinity_hash, &kv,
235  affinity_is_expired_cb, NULL);
236  if (rv)
237  {
238  nat_elog_notice (sm, "affinity key add failed");
239  pool_put (nam->affinity_pool, a);
240  goto unlock;
241  }
242 
243  pool_get (nam->list_pool, list_elt);
244  clib_dlist_init (nam->list_pool, list_elt - nam->list_pool);
245  list_elt->value = a - nam->affinity_pool;
246  a->per_service_index = list_elt - nam->list_pool;
247  a->backend_index = backend_index;
248  a->ref_cnt = 1;
249  a->sticky_time = sticky_time;
250  a->key.as_u64[0] = kv.key[0];
251  a->key.as_u64[1] = kv.key[1];
252  clib_dlist_addtail (nam->list_pool, affinity_per_service_list_head_index,
253  a->per_service_index);
254 
255 unlock:
257  return rv;
258 }
259 
260 void
262  u8 proto, u16 service_port)
263 {
266  nat_affinity_t *a;
267 
268  make_affinity_kv (&kv, client_addr, service_addr, proto, service_port);
270  if (clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
271  goto unlock;
272 
273  a = pool_elt_at_index (nam->affinity_pool, value.value);
274  a->ref_cnt--;
275  if (a->ref_cnt == 0)
276  a->expire = (u64) a->sticky_time + vlib_time_now (nam->vlib_main);
277 
278 unlock:
280 }
281 
282 /*
283  * fd.io coding-style-patch-verification: ON
284  *
285  * Local Variables:
286  * eval: (c-set-style "gnu")
287  * End:
288  */
ip4_address_t client_addr
a
Definition: bitmap.h:544
static void clib_dlist_init(dlist_elt_t *pool, u32 index)
Definition: dlist.h:36
u32 nat_affinity_get_per_service_list_head_index(void)
Get new affinity per service list head index.
unsigned long u64
Definition: types.h:89
void nat_affinity_enable()
NAT affinity enable.
int nat_affinity_find_and_lock(vlib_main_t *vm, 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.
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.
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:325
#define AFFINITY_HASH_MEMORY
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:129
NAT plugin client-IP based session affinity for load-balancing.
dlist_elt_t * list_pool
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
unsigned char u8
Definition: types.h:56
static void clib_spinlock_free(clib_spinlock_t *p)
Definition: lock.h:72
unsigned int u32
Definition: types.h:88
ip4_address_t service_addr
format_function_t format_ip4_address
Definition: format.h:73
#define static_always_inline
Definition: clib.h:112
void nat_affinity_flush_service(u32 affinity_per_service_list_head_index)
Flush all service affinity data.
clib_bihash_16_8_t affinity_hash
description fragment has unexpected format
Definition: map.api:433
#define nat_elog_warn(_pm, nat_elog_str)
Definition: log.h:177
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.
vlib_main_t * vlib_main
int __clib_unused rv
Definition: application.c:491
clib_error_t * nat_affinity_init(vlib_main_t *vm)
Initialize NAT client-IP based affinity.
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
clib_spinlock_t affinity_lock
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
snat_main_t snat_main
Definition: nat44_ed.c:41
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
format_function_t format_nat_protocol
Definition: nat64.h:506
unsigned short u16
Definition: types.h:57
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
nat_affinity_main_t nat_affinity_main
void nat_affinity_disable()
NAT affinity disable.
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
nat_affinity_t * affinity_pool
#define AFFINITY_HASH_BUCKETS
u8 value
Definition: qos.api:54
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
app_rx_mq_elt_t * elt
Definition: application.c:488
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)
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:88
NAT port/address allocation lib.
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:56
u8 * format_affinity_kvp(u8 *s, va_list *args)
#define nat_elog_notice(_pm, nat_elog_str)
Definition: log.h:175
static int affinity_is_expired_cb(clib_bihash_kv_16_8_t *kv, void *arg)
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