FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
lb.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 <lb/lb.h>
17 #include <vnet/plugin/plugin.h>
18 #include <vpp/app/version.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/udp/udp.h>
21 #include <vppinfra/lock.h>
22 
23 //GC runs at most once every so many seconds
24 #define LB_GARBAGE_RUN 60
25 
26 //After so many seconds. It is assumed that inter-core race condition will not occur.
27 #define LB_CONCURRENCY_TIMEOUT 10
28 
30 
31 #define lb_get_writer_lock() clib_spinlock_lock (&lb_main.writer_lock)
32 #define lb_put_writer_lock() clib_spinlock_unlock (&lb_main.writer_lock)
33 
34 static void lb_as_stack (lb_as_t *as);
35 
36 
37 const static char * const lb_dpo_gre4_ip4[] = { "lb4-gre4" , NULL };
38 const static char * const lb_dpo_gre4_ip6[] = { "lb6-gre4" , NULL };
39 const static char* const * const lb_dpo_gre4_nodes[DPO_PROTO_NUM] =
40  {
43  };
44 
45 const static char * const lb_dpo_gre6_ip4[] = { "lb4-gre6" , NULL };
46 const static char * const lb_dpo_gre6_ip6[] = { "lb6-gre6" , NULL };
47 const static char* const * const lb_dpo_gre6_nodes[DPO_PROTO_NUM] =
48  {
51  };
52 
53 const static char * const lb_dpo_gre4_ip4_port[] = { "lb4-gre4-port" , NULL };
54 const static char * const lb_dpo_gre4_ip6_port[] = { "lb6-gre4-port" , NULL };
55 const static char* const * const lb_dpo_gre4_port_nodes[DPO_PROTO_NUM] =
56  {
59  };
60 
61 const static char * const lb_dpo_gre6_ip4_port[] = { "lb4-gre6-port" , NULL };
62 const static char * const lb_dpo_gre6_ip6_port[] = { "lb6-gre6-port" , NULL };
63 const static char* const * const lb_dpo_gre6_port_nodes[DPO_PROTO_NUM] =
64  {
67  };
68 
69 const static char * const lb_dpo_l3dsr_ip4[] = {"lb4-l3dsr" , NULL};
70 const static char* const * const lb_dpo_l3dsr_nodes[DPO_PROTO_NUM] =
71  {
73  };
74 
75 const static char * const lb_dpo_l3dsr_ip4_port[] = {"lb4-l3dsr-port" , NULL};
76 const static char* const * const lb_dpo_l3dsr_port_nodes[DPO_PROTO_NUM] =
77  {
79  };
80 
81 const static char * const lb_dpo_nat4_ip4_port[] = { "lb4-nat4-port" , NULL };
82 const static char* const * const lb_dpo_nat4_port_nodes[DPO_PROTO_NUM] =
83  {
85  };
86 
87 const static char * const lb_dpo_nat6_ip6_port[] = { "lb6-nat6-port" , NULL };
88 const static char* const * const lb_dpo_nat6_port_nodes[DPO_PROTO_NUM] =
89  {
91  };
92 
94 {
95  return (u32) (vlib_time_now(vm) + 10000);
96 }
97 
98 u8 *format_lb_main (u8 * s, va_list * args)
99 {
101  lb_main_t *lbm = &lb_main;
102  s = format(s, "lb_main");
103  s = format(s, " ip4-src-address: %U \n", format_ip4_address, &lbm->ip4_src_address);
104  s = format(s, " ip6-src-address: %U \n", format_ip6_address, &lbm->ip6_src_address);
105  s = format(s, " #vips: %u\n", pool_elts(lbm->vips));
106  s = format(s, " #ass: %u\n", pool_elts(lbm->ass) - 1);
107 
108  u32 thread_index;
109  for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) {
110  lb_hash_t *h = lbm->per_cpu[thread_index].sticky_ht;
111  if (h) {
112  s = format(s, "core %d\n", thread_index);
113  s = format(s, " timeout: %ds\n", h->timeout);
114  s = format(s, " usage: %d / %d\n", lb_hash_elts(h, lb_hash_time_now(vlib_get_main())), lb_hash_size(h));
115  }
116  }
117 
118  return s;
119 }
120 
121 static char *lb_vip_type_strings[] = {
122  [LB_VIP_TYPE_IP6_GRE6] = "ip6-gre6",
123  [LB_VIP_TYPE_IP6_GRE4] = "ip6-gre4",
124  [LB_VIP_TYPE_IP4_GRE6] = "ip4-gre6",
125  [LB_VIP_TYPE_IP4_GRE4] = "ip4-gre4",
126  [LB_VIP_TYPE_IP4_L3DSR] = "ip4-l3dsr",
127  [LB_VIP_TYPE_IP4_NAT4] = "ip4-nat4",
128  [LB_VIP_TYPE_IP6_NAT6] = "ip6-nat6",
129 };
130 
131 u8 *format_lb_vip_type (u8 * s, va_list * args)
132 {
133  lb_vip_type_t vipt = va_arg (*args, lb_vip_type_t);
134  u32 i;
135  for (i=0; i<LB_VIP_N_TYPES; i++)
136  if (vipt == i)
137  return format(s, lb_vip_type_strings[i]);
138  return format(s, "_WRONG_TYPE_");
139 }
140 
141 uword unformat_lb_vip_type (unformat_input_t * input, va_list * args)
142 {
143  lb_vip_type_t *vipt = va_arg (*args, lb_vip_type_t *);
144  u32 i;
145  for (i=0; i<LB_VIP_N_TYPES; i++)
146  if (unformat(input, lb_vip_type_strings[i])) {
147  *vipt = i;
148  return 1;
149  }
150  return 0;
151 }
152 
153 u8 *format_lb_vip (u8 * s, va_list * args)
154 {
155  lb_vip_t *vip = va_arg (*args, lb_vip_t *);
156  s = format(s, "%U %U new_size:%u #as:%u%s",
157  format_lb_vip_type, vip->type,
159  vip->new_flow_table_mask + 1,
160  pool_elts(vip->as_indexes),
161  (vip->flags & LB_VIP_FLAGS_USED)?"":" removed");
162 
163  if (vip->port != 0)
164  {
165  s = format(s, " protocol:%u port:%u ", vip->protocol, vip->port);
166  }
167 
168  if (vip->type == LB_VIP_TYPE_IP4_L3DSR)
169  {
170  s = format(s, " dscp:%u", vip->encap_args.dscp);
171  }
172  else if ((vip->type == LB_VIP_TYPE_IP4_NAT4)
173  || (vip->type == LB_VIP_TYPE_IP6_NAT6))
174  {
175  s = format (s, " type:%s port:%u target_port:%u",
176  (vip->encap_args.srv_type == LB_SRV_TYPE_CLUSTERIP)?"clusterip":
177  "nodeport",
178  ntohs(vip->port), ntohs(vip->encap_args.target_port));
179  }
180 
181  return s;
182 }
183 
184 u8 *format_lb_as (u8 * s, va_list * args)
185 {
186  lb_as_t *as = va_arg (*args, lb_as_t *);
187  return format(s, "%U %s", format_ip46_address,
188  &as->address, IP46_TYPE_ANY,
189  (as->flags & LB_AS_FLAGS_USED)?"used":"removed");
190 }
191 
192 u8 *format_lb_vip_detailed (u8 * s, va_list * args)
193 {
194  lb_main_t *lbm = &lb_main;
195  lb_vip_t *vip = va_arg (*args, lb_vip_t *);
196  u32 indent = format_get_indent (s);
197 
198  s = format(s, "%U %U [%lu] %U%s\n"
199  "%U new_size:%u\n",
200  format_white_space, indent,
201  format_lb_vip_type, vip->type,
202  vip - lbm->vips,
204  (vip->flags & LB_VIP_FLAGS_USED)?"":" removed",
205  format_white_space, indent,
206  vip->new_flow_table_mask + 1);
207 
208  if (vip->port != 0)
209  {
210  s = format(s, "%U protocol:%u port:%u\n",
211  format_white_space, indent,
212  vip->protocol, vip->port);
213  }
214 
215  if (vip->type == LB_VIP_TYPE_IP4_L3DSR)
216  {
217  s = format(s, "%U dscp:%u\n",
218  format_white_space, indent,
219  vip->encap_args.dscp);
220  }
221  else if ((vip->type == LB_VIP_TYPE_IP4_NAT4)
222  || (vip->type == LB_VIP_TYPE_IP6_NAT6))
223  {
224  s = format (s, "%U type:%s port:%u target_port:%u",
225  format_white_space, indent,
226  (vip->encap_args.srv_type == LB_SRV_TYPE_CLUSTERIP)?"clusterip":
227  "nodeport",
228  ntohs(vip->port), ntohs(vip->encap_args.target_port));
229  }
230 
231  //Print counters
232  s = format(s, "%U counters:\n",
233  format_white_space, indent);
234  u32 i;
235  for (i=0; i<LB_N_VIP_COUNTERS; i++)
236  s = format(s, "%U %s: %Lu\n",
237  format_white_space, indent,
238  lbm->vip_counters[i].name,
239  vlib_get_simple_counter(&lbm->vip_counters[i], vip - lbm->vips));
240 
241 
242  s = format(s, "%U #as:%u\n",
243  format_white_space, indent,
244  pool_elts(vip->as_indexes));
245 
246  //Let's count the buckets for each AS
247  u32 *count = 0;
248  vec_validate(count, pool_len(lbm->ass)); //Possibly big alloc for not much...
249  lb_new_flow_entry_t *nfe;
250  vec_foreach(nfe, vip->new_flow_table)
251  count[nfe->as_index]++;
252 
253  lb_as_t *as;
254  u32 *as_index;
255  pool_foreach(as_index, vip->as_indexes, {
256  as = &lbm->ass[*as_index];
257  s = format(s, "%U %U %u buckets %Lu flows dpo:%u %s\n",
258  format_white_space, indent,
259  format_ip46_address, &as->address, IP46_TYPE_ANY,
260  count[as - lbm->ass],
261  vlib_refcount_get(&lbm->as_refcount, as - lbm->ass),
262  as->dpo.dpoi_index,
263  (as->flags & LB_AS_FLAGS_USED)?"used":" removed");
264  });
265 
266  vec_free(count);
267  return s;
268 }
269 
270 typedef struct {
275 
276 static int lb_pseudorand_compare(void *a, void *b)
277 {
278  lb_as_t *asa, *asb;
279  lb_main_t *lbm = &lb_main;
280  asa = &lbm->ass[((lb_pseudorand_t *)a)->as_index];
281  asb = &lbm->ass[((lb_pseudorand_t *)b)->as_index];
282  return memcmp(&asa->address, &asb->address, sizeof(asb->address));
283 }
284 
286 {
287  lb_main_t *lbm = &lb_main;
288  lb_snat4_key_t m_key4;
289  clib_bihash_kv_8_8_t kv4, value4;
290  lb_snat6_key_t m_key6;
291  clib_bihash_kv_24_8_t kv6, value6;
292  lb_snat_mapping_t *m = 0;
294 
295  u32 now = (u32) vlib_time_now(vlib_get_main());
297  return;
298 
299  vip->last_garbage_collection = now;
300  lb_as_t *as;
301  u32 *as_index;
302  pool_foreach(as_index, vip->as_indexes, {
303  as = &lbm->ass[*as_index];
304  if (!(as->flags & LB_AS_FLAGS_USED) && //Not used
305  clib_u32_loop_gt(now, as->last_used + LB_CONCURRENCY_TIMEOUT) &&
306  (vlib_refcount_get(&lbm->as_refcount, as - lbm->ass) == 0))
307  { //Not referenced
308 
309  if (lb_vip_is_nat4_port(vip)) {
310  m_key4.addr = as->address.ip4;
311  m_key4.port = vip->encap_args.target_port;
312  m_key4.protocol = 0;
313  m_key4.fib_index = 0;
314 
315  kv4.key = m_key4.as_u64;
316  if(!clib_bihash_search_8_8(&lbm->mapping_by_as4, &kv4, &value4))
317  m = pool_elt_at_index (lbm->snat_mappings, value4.value);
318  ASSERT (m);
319 
320  kv4.value = m - lbm->snat_mappings;
321  clib_bihash_add_del_8_8(&lbm->mapping_by_as4, &kv4, 0);
322  pool_put (lbm->snat_mappings, m);
323  } else if (lb_vip_is_nat6_port(vip)) {
324  m_key6.addr.as_u64[0] = as->address.ip6.as_u64[0];
325  m_key6.addr.as_u64[1] = as->address.ip6.as_u64[1];
326  m_key6.port = vip->encap_args.target_port;
327  m_key6.protocol = 0;
328  m_key6.fib_index = 0;
329 
330  kv6.key[0] = m_key6.as_u64[0];
331  kv6.key[1] = m_key6.as_u64[1];
332  kv6.key[2] = m_key6.as_u64[2];
333 
334  if (!clib_bihash_search_24_8 (&lbm->mapping_by_as6, &kv6, &value6))
335  m = pool_elt_at_index (lbm->snat_mappings, value6.value);
336  ASSERT (m);
337 
338  kv6.value = m - lbm->snat_mappings;
339  clib_bihash_add_del_24_8(&lbm->mapping_by_as6, &kv6, 0);
340  pool_put (lbm->snat_mappings, m);
341  }
342  fib_entry_child_remove(as->next_hop_fib_entry_index,
343  as->next_hop_child_index);
344  fib_table_entry_delete_index(as->next_hop_fib_entry_index,
345  FIB_SOURCE_RR);
346  as->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID;
347 
348  pool_put(vip->as_indexes, as_index);
349  pool_put(lbm->ass, as);
350  }
351  });
352 }
353 
355 {
356  lb_main_t *lbm = &lb_main;
358  lb_vip_t *vip;
359  u32 *to_be_removed_vips = 0, *i;
360  pool_foreach(vip, lbm->vips, {
361  lb_vip_garbage_collection(vip);
362 
363  if (!(vip->flags & LB_VIP_FLAGS_USED) &&
364  (pool_elts(vip->as_indexes) == 0)) {
365  vec_add1(to_be_removed_vips, vip - lbm->vips);
366  }
367  });
368 
369  vec_foreach(i, to_be_removed_vips) {
370  vip = &lbm->vips[*i];
371  pool_put(lbm->vips, vip);
372  pool_free(vip->as_indexes);
373  }
374 
375  vec_free(to_be_removed_vips);
377 }
378 
380 {
381  lb_main_t *lbm = &lb_main;
382  lb_new_flow_entry_t *old_table;
383  u32 i, *as_index;
384  lb_new_flow_entry_t *new_flow_table = 0;
385  lb_as_t *as;
386  lb_pseudorand_t *pr, *sort_arr = 0;
387 
388  CLIB_SPINLOCK_ASSERT_LOCKED (&lbm->writer_lock); // We must have the lock
389 
390  //Check if some AS is configured or not
391  i = 0;
392  pool_foreach(as_index, vip->as_indexes, {
393  as = &lbm->ass[*as_index];
394  if (as->flags & LB_AS_FLAGS_USED) { //Not used anymore
395  i = 1;
396  goto out; //Not sure 'break' works in this macro-loop
397  }
398  });
399 
400 out:
401  if (i == 0) {
402  //Only the default. i.e. no AS
403  vec_validate(new_flow_table, vip->new_flow_table_mask);
404  for (i=0; i<vec_len(new_flow_table); i++)
405  new_flow_table[i].as_index = 0;
406 
407  goto finished;
408  }
409 
410  //First, let's sort the ASs
411  vec_alloc(sort_arr, pool_elts(vip->as_indexes));
412 
413  i = 0;
414  pool_foreach(as_index, vip->as_indexes, {
415  as = &lbm->ass[*as_index];
416  if (!(as->flags & LB_AS_FLAGS_USED)) //Not used anymore
417  continue;
418 
419  sort_arr[i].as_index = as - lbm->ass;
420  i++;
421  });
422  _vec_len(sort_arr) = i;
423 
425 
426  //Now let's pseudo-randomly generate permutations
427  vec_foreach(pr, sort_arr) {
428  lb_as_t *as = &lbm->ass[pr->as_index];
429 
430  u64 seed = clib_xxhash(as->address.as_u64[0] ^
431  as->address.as_u64[1]);
432  /* We have 2^n buckets.
433  * skip must be prime with 2^n.
434  * So skip must be odd.
435  * MagLev actually state that M should be prime,
436  * but this has a big computation cost (% operation).
437  * Using 2^n is more better (& operation).
438  */
439  pr->skip = ((seed & 0xffffffff) | 1) & vip->new_flow_table_mask;
440  pr->last = (seed >> 32) & vip->new_flow_table_mask;
441  }
442 
443  //Let's create a new flow table
444  vec_validate(new_flow_table, vip->new_flow_table_mask);
445  for (i=0; i<vec_len(new_flow_table); i++)
446  new_flow_table[i].as_index = 0;
447 
448  u32 done = 0;
449  while (1) {
450  vec_foreach(pr, sort_arr) {
451  while (1) {
452  u32 last = pr->last;
453  pr->last = (pr->last + pr->skip) & vip->new_flow_table_mask;
454  if (new_flow_table[last].as_index == 0) {
455  new_flow_table[last].as_index = pr->as_index;
456  break;
457  }
458  }
459  done++;
460  if (done == vec_len(new_flow_table))
461  goto finished;
462  }
463  }
464 
465 finished:
466  vec_free(sort_arr);
467 
468  old_table = vip->new_flow_table;
469  vip->new_flow_table = new_flow_table;
470  vec_free(old_table);
471 }
472 
474  u32 per_cpu_sticky_buckets, u32 flow_timeout)
475 {
476  lb_main_t *lbm = &lb_main;
477 
478  if (!is_pow2(per_cpu_sticky_buckets))
479  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
480 
481  lb_get_writer_lock(); //Not exactly necessary but just a reminder that it exists for my future self
484  lbm->per_cpu_sticky_buckets = per_cpu_sticky_buckets;
485  lbm->flow_timeout = flow_timeout;
487  return 0;
488 }
489 
490 
491 
492 static
493 int lb_vip_port_find_index(ip46_address_t *prefix, u8 plen,
494  u8 protocol, u16 port,
495  lb_lkp_type_t lkp_type,
496  u32 *vip_index)
497 {
498  lb_main_t *lbm = &lb_main;
499  lb_vip_t *vip;
500  /* This must be called with the lock owned */
502  ip46_prefix_normalize(prefix, plen);
503  pool_foreach(vip, lbm->vips, {
504  if ((vip->flags & LB_AS_FLAGS_USED) &&
505  vip->plen == plen &&
506  vip->prefix.as_u64[0] == prefix->as_u64[0] &&
507  vip->prefix.as_u64[1] == prefix->as_u64[1])
508  {
509  if((lkp_type == LB_LKP_SAME_IP_PORT &&
510  vip->protocol == protocol &&
511  vip->port == port) ||
512  (lkp_type == LB_LKP_ALL_PORT_IP &&
513  vip->port == 0) ||
514  (lkp_type == LB_LKP_DIFF_IP_PORT &&
515  (vip->protocol != protocol ||
516  vip->port != port) ) )
517  {
518  *vip_index = vip - lbm->vips;
519  return 0;
520  }
521  }
522  });
523  return VNET_API_ERROR_NO_SUCH_ENTRY;
524 }
525 
526 static
527 int lb_vip_port_find_index_with_lock(ip46_address_t *prefix, u8 plen,
528  u8 protocol, u16 port, u32 *vip_index)
529 {
530  return lb_vip_port_find_index(prefix, plen, protocol, port,
531  LB_LKP_SAME_IP_PORT, vip_index);
532 }
533 
534 static
535 int lb_vip_port_find_all_port_vip(ip46_address_t *prefix, u8 plen,
536  u32 *vip_index)
537 {
538  return lb_vip_port_find_index(prefix, plen, ~0, 0,
539  LB_LKP_ALL_PORT_IP, vip_index);
540 }
541 
542 /* Find out per-port-vip entry with different protocol and port */
543 static
544 int lb_vip_port_find_diff_port(ip46_address_t *prefix, u8 plen,
545  u8 protocol, u16 port, u32 *vip_index)
546 {
547  return lb_vip_port_find_index(prefix, plen, protocol, port,
548  LB_LKP_DIFF_IP_PORT, vip_index);
549 }
550 
551 int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u8 protocol,
552  u16 port, u32 *vip_index)
553 {
554  int ret;
556  ret = lb_vip_port_find_index_with_lock(prefix, plen,
557  protocol, port, vip_index);
559  return ret;
560 }
561 
562 static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index)
563 {
564  lb_main_t *lbm = &lb_main;
565  /* This must be called with the lock owned */
567  lb_as_t *as;
568  u32 *asi;
569  pool_foreach(asi, vip->as_indexes, {
570  as = &lbm->ass[*asi];
571  if (as->vip_index == (vip - lbm->vips) &&
572  as->address.as_u64[0] == address->as_u64[0] &&
573  as->address.as_u64[1] == address->as_u64[1])
574  {
575  *as_index = as - lbm->ass;
576  return 0;
577  }
578  });
579  return -1;
580 }
581 
582 int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
583 {
584  lb_main_t *lbm = &lb_main;
586  lb_vip_t *vip;
587  if (!(vip = lb_vip_get_by_index(vip_index))) {
589  return VNET_API_ERROR_NO_SUCH_ENTRY;
590  }
591 
593  u32 *to_be_added = 0;
594  u32 *to_be_updated = 0;
595  u32 i;
596  u32 *ip;
598 
599  //Sanity check
600  while (n--) {
601 
602  if (!lb_as_find_index_vip(vip, &addresses[n], &i)) {
603  if (lbm->ass[i].flags & LB_AS_FLAGS_USED) {
604  vec_free(to_be_added);
605  vec_free(to_be_updated);
607  return VNET_API_ERROR_VALUE_EXIST;
608  }
609  vec_add1(to_be_updated, i);
610  goto next;
611  }
612 
613  if (ip46_address_type(&addresses[n]) != type) {
614  vec_free(to_be_added);
615  vec_free(to_be_updated);
617  return VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
618  }
619 
620  if (n) {
621  u32 n2 = n;
622  while(n2--) //Check for duplicates
623  if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] &&
624  addresses[n2].as_u64[1] == addresses[n].as_u64[1])
625  goto next;
626  }
627 
628  vec_add1(to_be_added, n);
629 
630 next:
631  continue;
632  }
633 
634  //Update reused ASs
635  vec_foreach(ip, to_be_updated) {
636  lbm->ass[*ip].flags = LB_AS_FLAGS_USED;
637  }
638  vec_free(to_be_updated);
639 
640  //Create those who have to be created
641  vec_foreach(ip, to_be_added) {
642  lb_as_t *as;
643  u32 *as_index;
644  pool_get(lbm->ass, as);
645  as->address = addresses[*ip];
646  as->flags = LB_AS_FLAGS_USED;
647  as->vip_index = vip_index;
648  pool_get(vip->as_indexes, as_index);
649  *as_index = as - lbm->ass;
650 
651  /*
652  * become a child of the FIB entry
653  * so we are informed when its forwarding changes
654  */
655  fib_prefix_t nh = {};
656  if (lb_encap_is_ip4(vip)) {
657  nh.fp_addr.ip4 = as->address.ip4;
658  nh.fp_len = 32;
660  } else {
661  nh.fp_addr.ip6 = as->address.ip6;
662  nh.fp_len = 128;
664  }
665 
668  &nh,
673  lbm->fib_node_type,
674  as - lbm->ass);
675 
676  lb_as_stack(as);
677 
678  if ( lb_vip_is_nat4_port(vip) || lb_vip_is_nat6_port(vip) )
679  {
680  /* Add SNAT static mapping */
681  pool_get (lbm->snat_mappings, m);
682  clib_memset (m, 0, sizeof (*m));
683  if (lb_vip_is_nat4_port(vip)) {
684  lb_snat4_key_t m_key4;
686  m_key4.addr = as->address.ip4;
687  m_key4.port = vip->encap_args.target_port;
688  m_key4.protocol = 0;
689  m_key4.fib_index = 0;
690 
692  {
693  m->src_ip.ip4 = vip->prefix.ip4;
694  }
695  else if (vip->encap_args.srv_type == LB_SRV_TYPE_NODEPORT)
696  {
697  m->src_ip.ip4 = lbm->ip4_src_address;
698  }
699  m->src_ip_is_ipv6 = 0;
700  m->as_ip.ip4 = as->address.ip4;
701  m->as_ip_is_ipv6 = 0;
702  m->src_port = vip->port;
704  m->vrf_id = 0;
705  m->fib_index = 0;
706 
707  kv4.key = m_key4.as_u64;
708  kv4.value = m - lbm->snat_mappings;
709  clib_bihash_add_del_8_8(&lbm->mapping_by_as4, &kv4, 1);
710  } else {
711  lb_snat6_key_t m_key6;
713  m_key6.addr.as_u64[0] = as->address.ip6.as_u64[0];
714  m_key6.addr.as_u64[1] = as->address.ip6.as_u64[1];
715  m_key6.port = vip->encap_args.target_port;
716  m_key6.protocol = 0;
717  m_key6.fib_index = 0;
718 
720  {
721  m->src_ip.ip6.as_u64[0] = vip->prefix.ip6.as_u64[0];
722  m->src_ip.ip6.as_u64[1] = vip->prefix.ip6.as_u64[1];
723  }
724  else if (vip->encap_args.srv_type == LB_SRV_TYPE_NODEPORT)
725  {
726  m->src_ip.ip6.as_u64[0] = lbm->ip6_src_address.as_u64[0];
727  m->src_ip.ip6.as_u64[1] = lbm->ip6_src_address.as_u64[1];
728  }
729  m->src_ip_is_ipv6 = 1;
730  m->as_ip.ip6.as_u64[0] = as->address.ip6.as_u64[0];
731  m->as_ip.ip6.as_u64[1] = as->address.ip6.as_u64[1];
732  m->as_ip_is_ipv6 = 1;
733  m->src_port = vip->port;
735  m->vrf_id = 0;
736  m->fib_index = 0;
737 
738  kv6.key[0] = m_key6.as_u64[0];
739  kv6.key[1] = m_key6.as_u64[1];
740  kv6.key[2] = m_key6.as_u64[2];
741  kv6.value = m - lbm->snat_mappings;
742  clib_bihash_add_del_24_8(&lbm->mapping_by_as6, &kv6, 1);
743  }
744  }
745  }
746  vec_free(to_be_added);
747 
748  //Recompute flows
750 
751  //Garbage collection maybe
753 
755  return 0;
756 }
757 
758 int
759 lb_flush_vip_as (u32 vip_index, u32 as_index)
760 {
761  u32 thread_index;
763  lb_main_t *lbm = &lb_main;
764 
765  for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) {
766  lb_hash_t *h = lbm->per_cpu[thread_index].sticky_ht;
767  if (h != NULL) {
768  u32 i;
769  lb_hash_bucket_t *b;
770 
771  lb_hash_foreach_entry(h, b, i) {
772  if ((vip_index == ~0)
773  || ((b->vip[i] == vip_index) && (as_index == ~0))
774  || ((b->vip[i] == vip_index) && (b->value[i] == as_index)))
775  {
776  vlib_refcount_add(&lbm->as_refcount, thread_index, b->value[i], -1);
777  vlib_refcount_add(&lbm->as_refcount, thread_index, 0, 1);
778  b->vip[i] = ~0;
779  b->value[i] = 0;
780  }
781  }
782  if (vip_index == ~0)
783  {
784  lb_hash_free(h);
785  lbm->per_cpu[thread_index].sticky_ht = 0;
786  }
787  }
788  }
789 
790  return 0;
791 }
792 
793 int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n,
794  u8 flush)
795 {
796  lb_main_t *lbm = &lb_main;
797  u32 now = (u32) vlib_time_now(vlib_get_main());
798  u32 *ip = 0;
799  u32 as_index = 0;
800 
801  lb_vip_t *vip;
802  if (!(vip = lb_vip_get_by_index(vip_index))) {
803  return VNET_API_ERROR_NO_SUCH_ENTRY;
804  }
805 
806  u32 *indexes = NULL;
807  while (n--) {
808  if (lb_as_find_index_vip(vip, &addresses[n], &as_index)) {
809  vec_free(indexes);
810  return VNET_API_ERROR_NO_SUCH_ENTRY;
811  }
812 
813  if (n) { //Check for duplicates
814  u32 n2 = n - 1;
815  while(n2--) {
816  if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] &&
817  addresses[n2].as_u64[1] == addresses[n].as_u64[1])
818  goto next;
819  }
820  }
821 
822  vec_add1(indexes, as_index);
823 next:
824  continue;
825  }
826 
827  //Garbage collection maybe
829 
830  if (indexes != NULL) {
831  vec_foreach(ip, indexes) {
832  lbm->ass[*ip].flags &= ~LB_AS_FLAGS_USED;
833  lbm->ass[*ip].last_used = now;
834 
835  if(flush)
836  {
837  /* flush flow table for deleted ASs*/
838  lb_flush_vip_as(vip_index, *ip);
839  }
840  }
841 
842  //Recompute flows
844  }
845 
846  vec_free(indexes);
847  return 0;
848 }
849 
850 int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n, u8 flush)
851 {
853  int ret = lb_vip_del_ass_withlock(vip_index, addresses, n, flush);
855 
856  return ret;
857 }
858 
859 static int
861 {
862  /*
863  * Check for dynamically allocated instance number.
864  */
865  u32 bit;
866 
868 
870 
871  return bit;
872 }
873 
874 static int
876 {
877 
878  if (clib_bitmap_get (lbm->vip_prefix_indexes, instance) == 0)
879  {
880  return -1;
881  }
882 
884  instance, 0);
885 
886  return 0;
887 }
888 
889 /**
890  * Add the VIP adjacency to the ip4 or ip6 fib
891  */
892 static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip,
893  u32 *vip_prefix_index)
894 {
895  dpo_proto_t proto = 0;
896  dpo_type_t dpo_type = 0;
897  u32 vip_idx = 0;
898 
899  if (vip->port != 0)
900  {
901  /* for per-port vip, if VIP adjacency has been added,
902  * no need to add adjacency. */
903  if (!lb_vip_port_find_diff_port(&(vip->prefix), vip->plen,
904  vip->protocol, vip->port, &vip_idx))
905  {
906  lb_vip_t *exists_vip = lb_vip_get_by_index(vip_idx);
907  *vip_prefix_index = exists_vip ? exists_vip->vip_prefix_index : ~0;
908  return;
909  }
910 
911  /* Allocate an index for per-port vip */
912  *vip_prefix_index = lb_vip_prefix_index_alloc(lbm);
913  }
914  else
915  {
916  *vip_prefix_index = vip - lbm->vips;
917  }
918 
919  dpo_id_t dpo = DPO_INVALID;
920  fib_prefix_t pfx = {};
921  if (lb_vip_is_ip4(vip->type)) {
922  pfx.fp_addr.ip4 = vip->prefix.ip4;
923  pfx.fp_len = vip->plen - 96;
925  proto = DPO_PROTO_IP4;
926  } else {
927  pfx.fp_addr.ip6 = vip->prefix.ip6;
928  pfx.fp_len = vip->plen;
930  proto = DPO_PROTO_IP6;
931  }
932 
933  if (lb_vip_is_gre4(vip))
934  dpo_type = lbm->dpo_gre4_type;
935  else if (lb_vip_is_gre6(vip))
936  dpo_type = lbm->dpo_gre6_type;
937  else if (lb_vip_is_gre4_port(vip))
938  dpo_type = lbm->dpo_gre4_port_type;
939  else if (lb_vip_is_gre6_port(vip))
940  dpo_type = lbm->dpo_gre6_port_type;
941  else if (lb_vip_is_l3dsr(vip))
942  dpo_type = lbm->dpo_l3dsr_type;
943  else if (lb_vip_is_l3dsr_port(vip))
944  dpo_type = lbm->dpo_l3dsr_port_type;
945  else if(lb_vip_is_nat4_port(vip))
946  dpo_type = lbm->dpo_nat4_port_type;
947  else if (lb_vip_is_nat6_port(vip))
948  dpo_type = lbm->dpo_nat6_port_type;
949 
950  dpo_set(&dpo, dpo_type, proto, *vip_prefix_index);
952  &pfx,
955  &dpo);
956  dpo_reset(&dpo);
957 }
958 
959 /**
960  * Add the VIP filter entry
961  */
963  u32 vip_prefix_index, u32 vip_idx)
964 {
967 
968  key.vip_prefix_index = vip_prefix_index;
969  key.protocol = vip->protocol;
970  key.port = clib_host_to_net_u16(vip->port);
971  key.rsv = 0;
972 
973  kv.key = key.as_u64;
974  kv.value = vip_idx;
975  clib_bihash_add_del_8_8(&lbm->vip_index_per_port, &kv, 1);
976 
977  return 0;
978 }
979 
980 /**
981  * Del the VIP filter entry
982  */
984 {
987  lb_vip_t *m = 0;
988 
990  key.protocol = vip->protocol;
991  key.port = clib_host_to_net_u16(vip->port);
992  key.rsv = 0;
993 
994  kv.key = key.as_u64;
995  if(clib_bihash_search_8_8(&lbm->vip_index_per_port, &kv, &value) != 0)
996  {
997  clib_warning("looking up vip_index_per_port failed.");
998  return VNET_API_ERROR_NO_SUCH_ENTRY;
999  }
1000  m = pool_elt_at_index (lbm->vips, value.value);
1001  ASSERT (m);
1002 
1003  kv.value = m - lbm->vips;
1004  clib_bihash_add_del_8_8(&lbm->vip_index_per_port, &kv, 0);
1005 
1006  return 0;
1007 }
1008 
1009 /**
1010  * Deletes the adjacency associated with the VIP
1011  */
1012 static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip)
1013 {
1014  fib_prefix_t pfx = {};
1015  u32 vip_idx = 0;
1016 
1017  if (vip->port != 0)
1018  {
1019  /* If this vip adjacency is used by other per-port vip,
1020  * no need to del this adjacency. */
1021  if (!lb_vip_port_find_diff_port(&(vip->prefix), vip->plen,
1022  vip->protocol, vip->port, &vip_idx))
1023  {
1025  return;
1026  }
1027 
1028  /* Return vip_prefix_index for per-port vip */
1030 
1031  }
1032 
1033  if (lb_vip_is_ip4(vip->type)) {
1034  pfx.fp_addr.ip4 = vip->prefix.ip4;
1035  pfx.fp_len = vip->plen - 96;
1036  pfx.fp_proto = FIB_PROTOCOL_IP4;
1037  } else {
1038  pfx.fp_addr.ip6 = vip->prefix.ip6;
1039  pfx.fp_len = vip->plen;
1040  pfx.fp_proto = FIB_PROTOCOL_IP6;
1041  }
1043 }
1044 
1045 int lb_vip_add(lb_vip_add_args_t args, u32 *vip_index)
1046 {
1047  lb_main_t *lbm = &lb_main;
1049  lb_vip_t *vip;
1050  lb_vip_type_t type = args.type;
1051  u32 vip_prefix_index = 0;
1052 
1054  ip46_prefix_normalize(&(args.prefix), args.plen);
1055 
1056  if (!lb_vip_port_find_index_with_lock(&(args.prefix), args.plen,
1057  args.protocol, args.port,
1058  vip_index))
1059  {
1061  return VNET_API_ERROR_VALUE_EXIST;
1062  }
1063 
1064  /* Make sure we can't add a per-port VIP entry
1065  * when there already is an all-port VIP for the same prefix. */
1066  if ((args.port != 0) &&
1067  !lb_vip_port_find_all_port_vip(&(args.prefix), args.plen, vip_index))
1068  {
1070  return VNET_API_ERROR_VALUE_EXIST;
1071  }
1072 
1073  /* Make sure we can't add a all-port VIP entry
1074  * when there already is an per-port VIP for the same prefix. */
1075  if ((args.port == 0) &&
1076  !lb_vip_port_find_diff_port(&(args.prefix), args.plen,
1077  args.protocol, args.port, vip_index))
1078  {
1080  return VNET_API_ERROR_VALUE_EXIST;
1081  }
1082 
1083  /* Make sure all VIP for a given prefix (using different ports) have the same type. */
1084  if ((args.port != 0) &&
1085  !lb_vip_port_find_diff_port(&(args.prefix), args.plen,
1086  args.protocol, args.port, vip_index)
1087  && (args.type != lbm->vips[*vip_index].type))
1088  {
1090  return VNET_API_ERROR_INVALID_ARGUMENT;
1091  }
1092 
1093  if (!is_pow2(args.new_length)) {
1095  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
1096  }
1097 
1098  if (ip46_prefix_is_ip4(&(args.prefix), args.plen) &&
1099  !lb_vip_is_ip4(type)) {
1101  return VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
1102  }
1103 
1104  if ((!ip46_prefix_is_ip4(&(args.prefix), args.plen)) &&
1105  !lb_vip_is_ip6(type)) {
1107  return VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
1108  }
1109 
1110  if ((type == LB_VIP_TYPE_IP4_L3DSR) &&
1111  (args.encap_args.dscp >= 64) )
1112  {
1114  return VNET_API_ERROR_VALUE_EXIST;
1115  }
1116 
1117  //Allocate
1118  pool_get(lbm->vips, vip);
1119 
1120  //Init
1121  memcpy (&(vip->prefix), &(args.prefix), sizeof(args.prefix));
1122  vip->plen = args.plen;
1123  if (args.port != 0)
1124  {
1125  vip->protocol = args.protocol;
1126  vip->port = args.port;
1127  }
1128  else
1129  {
1130  vip->protocol = (u8)~0;
1131  vip->port = 0;
1132  }
1134  vip->type = args.type;
1135 
1136  if (args.type == LB_VIP_TYPE_IP4_L3DSR) {
1137  vip->encap_args.dscp = args.encap_args.dscp;
1138  }
1139  else if ((args.type == LB_VIP_TYPE_IP4_NAT4)
1140  ||(args.type == LB_VIP_TYPE_IP6_NAT6)) {
1141  vip->encap_args.srv_type = args.encap_args.srv_type;
1142  vip->encap_args.target_port =
1143  clib_host_to_net_u16(args.encap_args.target_port);
1144  }
1145 
1146  vip->flags = LB_VIP_FLAGS_USED;
1147  vip->as_indexes = 0;
1148 
1149  //Validate counters
1150  u32 i;
1151  for (i = 0; i < LB_N_VIP_COUNTERS; i++) {
1152  vlib_validate_simple_counter(&lbm->vip_counters[i], vip - lbm->vips);
1153  vlib_zero_simple_counter(&lbm->vip_counters[i], vip - lbm->vips);
1154  }
1155 
1156  //Configure new flow table
1157  vip->new_flow_table_mask = args.new_length - 1;
1158  vip->new_flow_table = 0;
1159 
1160  //Update flow hash table
1162 
1163  //Create adjacency to direct traffic
1164  lb_vip_add_adjacency(lbm, vip, &vip_prefix_index);
1165 
1166  if ( (lb_vip_is_nat4_port(vip) || lb_vip_is_nat6_port(vip))
1168  {
1169  u32 key;
1170  uword * entry;
1171 
1172  //Create maping from nodeport to vip_index
1173  key = clib_host_to_net_u16(args.port);
1174  entry = hash_get_mem (lbm->vip_index_by_nodeport, &key);
1175  if (entry) {
1177  return VNET_API_ERROR_VALUE_EXIST;
1178  }
1179 
1180  hash_set_mem (lbm->vip_index_by_nodeport, &key, vip - lbm->vips);
1181 
1182  /* receive packets destined to NodeIP:NodePort */
1183  udp_register_dst_port (vm, args.port, lb4_nodeport_node.index, 1);
1184  udp_register_dst_port (vm, args.port, lb6_nodeport_node.index, 0);
1185  }
1186 
1187  *vip_index = vip - lbm->vips;
1188  //Create per-port vip filtering table
1189  if (args.port != 0)
1190  {
1191  lb_vip_add_port_filter(lbm, vip, vip_prefix_index, *vip_index);
1192  vip->vip_prefix_index = vip_prefix_index;
1193  }
1194 
1196  return 0;
1197 }
1198 
1199 int lb_vip_del(u32 vip_index)
1200 {
1201  lb_main_t *lbm = &lb_main;
1202  lb_vip_t *vip;
1203  int rv = 0;
1204 
1205  /* Does not remove default vip, i.e. vip_index = 0 */
1206  if (vip_index == 0)
1207  return VNET_API_ERROR_INVALID_VALUE;
1208 
1210  if (!(vip = lb_vip_get_by_index(vip_index))) {
1212  return VNET_API_ERROR_NO_SUCH_ENTRY;
1213  }
1214 
1215  //FIXME: This operation is actually not working
1216  //We will need to remove state before performing this.
1217 
1218  {
1219  //Remove all ASs
1220  ip46_address_t *ass = 0;
1221  lb_as_t *as;
1222  u32 *as_index;
1223 
1224  pool_foreach(as_index, vip->as_indexes, {
1225  as = &lbm->ass[*as_index];
1226  vec_add1(ass, as->address);
1227  });
1228  if (vec_len(ass))
1229  lb_vip_del_ass_withlock(vip_index, ass, vec_len(ass), 0);
1230  vec_free(ass);
1231  }
1232 
1233  //Delete adjacency
1234  lb_vip_del_adjacency(lbm, vip);
1235 
1236  //Delete per-port vip filtering entry
1237  if (vip->port != 0)
1238  {
1239  rv = lb_vip_del_port_filter(lbm, vip);
1240  }
1241 
1242  //Set the VIP as unused
1243  vip->flags &= ~LB_VIP_FLAGS_USED;
1244 
1246  return rv;
1247 }
1248 
1249 /* *INDENT-OFF* */
1250 VLIB_PLUGIN_REGISTER () = {
1251  .version = VPP_BUILD_VER,
1252  .description = "Load Balancer (LB)",
1253 };
1254 /* *INDENT-ON* */
1255 
1256 u8 *format_lb_dpo (u8 * s, va_list * va)
1257 {
1258  index_t index = va_arg (*va, index_t);
1259  CLIB_UNUSED(u32 indent) = va_arg (*va, u32);
1260  lb_main_t *lbm = &lb_main;
1261  lb_vip_t *vip = pool_elt_at_index (lbm->vips, index);
1262  return format (s, "%U", format_lb_vip, vip);
1263 }
1264 
1265 static void lb_dpo_lock (dpo_id_t *dpo) {}
1266 static void lb_dpo_unlock (dpo_id_t *dpo) {}
1267 
1268 static fib_node_t *
1270 {
1271  lb_main_t *lbm = &lb_main;
1272  lb_as_t *as = pool_elt_at_index (lbm->ass, index);
1273  return (&as->fib_node);
1274 }
1275 
1276 static void
1278 {
1279 }
1280 
1281 static lb_as_t *
1283 {
1284  return ((lb_as_t*)(((char*)node) -
1285  STRUCT_OFFSET_OF(lb_as_t, fib_node)));
1286 }
1287 
1288 static void
1290 {
1291  lb_main_t *lbm = &lb_main;
1292  lb_vip_t *vip = &lbm->vips[as->vip_index];
1293  dpo_type_t dpo_type = 0;
1294 
1295  if (lb_vip_is_gre4(vip))
1296  dpo_type = lbm->dpo_gre4_type;
1297  else if (lb_vip_is_gre6(vip))
1298  dpo_type = lbm->dpo_gre6_type;
1299  else if (lb_vip_is_gre4_port(vip))
1300  dpo_type = lbm->dpo_gre4_port_type;
1301  else if (lb_vip_is_gre6_port(vip))
1302  dpo_type = lbm->dpo_gre6_port_type;
1303  else if (lb_vip_is_l3dsr(vip))
1304  dpo_type = lbm->dpo_l3dsr_type;
1305  else if (lb_vip_is_l3dsr_port(vip))
1306  dpo_type = lbm->dpo_l3dsr_port_type;
1307  else if(lb_vip_is_nat4_port(vip))
1308  dpo_type = lbm->dpo_nat4_port_type;
1309  else if (lb_vip_is_nat6_port(vip))
1310  dpo_type = lbm->dpo_nat6_port_type;
1311 
1312  dpo_stack(dpo_type,
1314  &as->dpo,
1317 }
1318 
1322 {
1324  return (FIB_NODE_BACK_WALK_CONTINUE);
1325 }
1326 
1328 {
1329  if (is_del)
1330  {
1331  vnet_feature_enable_disable ("ip4-unicast", "lb-nat4-in2out",
1332  sw_if_index, 0, 0, 0);
1333  }
1334  else
1335  {
1336  vnet_feature_enable_disable ("ip4-unicast", "lb-nat4-in2out",
1337  sw_if_index, 1, 0, 0);
1338  }
1339 
1340  return 0;
1341 }
1342 
1344 {
1345  if (is_del)
1346  {
1347  vnet_feature_enable_disable ("ip6-unicast", "lb-nat6-in2out",
1348  sw_if_index, 0, 0, 0);
1349  }
1350  else
1351  {
1352  vnet_feature_enable_disable ("ip6-unicast", "lb-nat6-in2out",
1353  sw_if_index, 1, 0, 0);
1354  }
1355 
1356  return 0;
1357 }
1358 
1359 clib_error_t *
1361 {
1363  lb_main_t *lbm = &lb_main;
1364  lbm->vnet_main = vnet_get_main ();
1365  lbm->vlib_main = vm;
1366 
1367  lb_vip_t *default_vip;
1368  lb_as_t *default_as;
1369  fib_node_vft_t lb_fib_node_vft = {
1371  .fnv_last_lock = lb_fib_node_last_lock_gone,
1372  .fnv_back_walk = lb_fib_node_back_walk_notify,
1373  };
1374  dpo_vft_t lb_vft = {
1375  .dv_lock = lb_dpo_lock,
1376  .dv_unlock = lb_dpo_unlock,
1377  .dv_format = format_lb_dpo,
1378  };
1379 
1380  //Allocate and init default VIP.
1381  lbm->vips = 0;
1382  pool_get(lbm->vips, default_vip);
1383  default_vip->new_flow_table_mask = 0;
1384  default_vip->prefix.ip6.as_u64[0] = 0xffffffffffffffffL;
1385  default_vip->prefix.ip6.as_u64[1] = 0xffffffffffffffffL;
1386  default_vip->protocol = ~0;
1387  default_vip->port = 0;
1388  default_vip->flags = LB_VIP_FLAGS_USED;
1389 
1390  lbm->per_cpu = 0;
1391  vec_validate(lbm->per_cpu, tm->n_vlib_mains - 1);
1395  lbm->ip4_src_address.as_u32 = 0xffffffff;
1396  lbm->ip6_src_address.as_u64[0] = 0xffffffffffffffffL;
1397  lbm->ip6_src_address.as_u64[1] = 0xffffffffffffffffL;
1404  lbm->dpo_l3dsr_type = dpo_register_new_type(&lb_vft,
1412  lbm->fib_node_type = fib_node_register_new_type(&lb_fib_node_vft);
1413 
1414  //Init AS reference counters
1416 
1417  //Allocate and init default AS.
1418  lbm->ass = 0;
1419  pool_get(lbm->ass, default_as);
1420  default_as->flags = 0;
1421  default_as->dpo.dpoi_next_node = LB_NEXT_DROP;
1422  default_as->vip_index = ~0;
1423  default_as->address.ip6.as_u64[0] = 0xffffffffffffffffL;
1424  default_as->address.ip6.as_u64[1] = 0xffffffffffffffffL;
1425 
1426  /* Generate a valid flow table for default VIP */
1427  default_vip->as_indexes = NULL;
1429  lb_vip_update_new_flow_table(default_vip);
1431 
1433  = hash_create_mem (0, sizeof(u16), sizeof (uword));
1434 
1435  clib_bihash_init_8_8 (&lbm->vip_index_per_port,
1436  "vip_index_per_port", LB_VIP_PER_PORT_BUCKETS,
1438 
1439  clib_bihash_init_8_8 (&lbm->mapping_by_as4,
1440  "mapping_by_as4", LB_MAPPING_BUCKETS,
1442 
1443  clib_bihash_init_24_8 (&lbm->mapping_by_as6,
1444  "mapping_by_as6", LB_MAPPING_BUCKETS,
1446 
1447 #define _(a,b,c) lbm->vip_counters[c].name = b;
1449 #undef _
1450  return NULL;
1451 }
1452 
u32 skip
Definition: lb.c:273
int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n, u8 flush)
Definition: lb.c:850
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:406
static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip, u32 *vip_prefix_index)
Add the VIP adjacency to the ip4 or ip6 fib.
Definition: lb.c:892
u64 as_u64
Definition: lb.h:423
u32 lb_hash_time_now(vlib_main_t *vm)
Definition: lb.c:93
static int lb_vip_port_find_all_port_vip(ip46_address_t *prefix, u8 plen, u32 *vip_index)
Definition: lb.c:535
typedef address
Definition: ip_types.api:83
u64 as_u64[3]
Definition: lb.h:438
int lb_nat4_interface_add_del(u32 sw_if_index, int is_del)
Definition: lb.c:1327
Recursive resolution source.
Definition: fib_entry.h:130
static int lb_pseudorand_compare(void *a, void *b)
Definition: lb.c:276
vnet_main_t * vnet_main
Definition: lb.h:569
Each VIP is configured with a set of application server.
Definition: lb.h:108
#define LB_GARBAGE_RUN
Definition: lb.c:24
#define CLIB_UNUSED(x)
Definition: clib.h:83
A virtual function table regisitered for a DPO type.
Definition: dpo.h:401
#define lb_vip_is_gre6(vip)
Definition: lb.h:354
a
Definition: bitmap.h:538
static bool lb_vip_is_l3dsr(const lb_vip_t *vip)
Definition: lb.h:367
#define lb_vip_is_gre6_port(vip)
Definition: lb.h:362
u32 last
Definition: lb.c:272
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u32 fib_index
Definition: lb.h:436
u32 per_cpu_sticky_buckets
Number of buckets in the per-cpu sticky hash table.
Definition: lb.h:522
vl_api_fib_path_nh_t nh
Definition: fib_types.api:126
clib_error_t * lb_init(vlib_main_t *vm)
Definition: lb.c:1360
u64 as_u64
Definition: bihash_doc.h:63
u32 fib_entry_child_add(fib_node_index_t fib_entry_index, fib_node_type_t child_type, fib_node_index_t child_index)
Definition: fib_entry.c:566
static void lb_fib_node_last_lock_gone(fib_node_t *node)
Definition: lb.c:1277
u64 as_u64[2]
Definition: ip6_packet.h:51
static void lb_vip_update_new_flow_table(lb_vip_t *vip)
Definition: lb.c:379
unsigned long u64
Definition: types.h:89
static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index)
Definition: lb.c:562
#define LB_VIP_PER_PORT_MEMORY_SIZE
Definition: lb.h:52
static const char *const lb_dpo_gre4_ip6_port[]
Definition: lb.c:54
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
const dpo_id_t * fib_entry_contribute_ip_forwarding(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:517
static int lb_vip_prefix_index_alloc(lb_main_t *lbm)
Definition: lb.c:860
static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip)
Deletes the adjacency associated with the VIP.
Definition: lb.c:1012
int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address, u32 per_cpu_sticky_buckets, u32 flow_timeout)
Fix global load-balancer parameters.
Definition: lb.c:473
#define lb_get_writer_lock()
Definition: lb.c:31
u8 * format_ip46_prefix(u8 *s, va_list *args)
Definition: util.c:54
int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:582
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:522
ip46_address_t prefix
A Virtual IP represents a given service delivered by a set of application servers.
Definition: lb.h:292
#define clib_u32_loop_gt(a, b)
32 bits integer comparison for running values.
Definition: util.h:38
static u64 clib_xxhash(u64 key)
Definition: xxhash.h:58
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
u16 port
Definition: lb.h:419
static_always_inline void vlib_refcount_init(vlib_refcount_t *r)
Definition: refcount.h:80
int i
static void lb_dpo_lock(dpo_id_t *dpo)
Definition: lb.c:1265
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
u32 vip_prefix_index
Definition: lb.h:245
format_function_t format_ip46_address
Definition: format.h:61
static u32 format_get_indent(u8 *s)
Definition: format.h:72
#define hash_set_mem(h, key, value)
Definition: hash.h:275
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:66
#define lb_vip_is_ip4(type)
Definition: lb.h:335
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static void lb_as_stack(lb_as_t *as)
Definition: lb.c:1289
vl_api_mprefix_t prefix
Definition: ip.api:456
u32 vip[LBHASH_ENTRY_PER_BUCKET]
Definition: lbhash.h:54
#define lb_vip_get_by_index(index)
Definition: lb.h:607
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
u32 vip_index
ASs are indexed by address and VIP Index.
Definition: lb.h:127
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:280
static const char *const *const lb_dpo_gre6_nodes[DPO_PROTO_NUM]
Definition: lb.c:47
lb_hash_t * sticky_ht
Each CPU has its own sticky flow hash table.
Definition: lb.h:467
unsigned char u8
Definition: types.h:56
#define pool_len(p)
Number of elements in pool vector.
Definition: pool.h:140
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
static int lb_vip_del_port_filter(lb_main_t *lbm, lb_vip_t *vip)
Del the VIP filter entry.
Definition: lb.c:983
#define LB_MAPPING_BUCKETS
Definition: lb.h:48
#define LB_VIP_FLAGS_USED
Definition: lb.h:326
#define ip46_address_type(ip46)
Definition: util.h:26
ip46_address_t address
Destination address used to tunnel traffic towards that application server.
Definition: lb.h:120
u32 timeout
Definition: lbhash.h:60
static counter_t vlib_get_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Get the value of a simple counter Scrapes the entire set of per-thread counters.
Definition: counter.h:113
format_function_t format_ip4_address
Definition: format.h:75
#define LB_AS_FLAGS_USED
Definition: lb.h:135
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:493
vl_api_interface_index_t sw_if_index
Definition: gre.api:50
u8 as_ip_is_ipv6
Definition: lb.h:450
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static lb_as_t * lb_as_from_fib_node(fib_node_t *node)
Definition: lb.c:1282
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:407
VLIB_PLUGIN_REGISTER()
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
lb_lkp_type_t
Lookup type.
Definition: lb.h:197
#define LB_DEFAULT_PER_CPU_STICKY_BUCKETS
lb-plugin implements a MagLev-like load balancer.
Definition: lb.h:46
#define LB_MAPPING_MEMORY_SIZE
Definition: lb.h:49
lb_main_t lb_main
Definition: lb.c:29
static const char *const lb_dpo_gre4_ip4[]
Definition: lb.c:37
u32 flow_timeout
Flow timeout in seconds.
Definition: lb.h:527
A high priority source a plugin can use.
Definition: fib_entry.h:67
u16 port
Definition: lb.h:304
Definition: lb.h:470
fib_node_type_t fib_node_type
Node type for registering to fib changes.
Definition: lb.h:548
dpo_type_t dpo_gre4_type
DPO used to send packet from IP4/6 lookup to LB node.
Definition: lb.h:537
Aggregate type for a prefix.
Definition: fib_types.h:203
u16 protocol
Definition: lb.h:420
static const char *const *const lb_dpo_nat4_port_nodes[DPO_PROTO_NUM]
Definition: lb.c:82
u8 protocol
Definition: lb.h:301
vlib_refcount_t as_refcount
Each AS has an associated reference counter.
Definition: lb.h:494
lb_vip_encap_args_t encap_args
Definition: lb.h:316
static const char *const lb_dpo_gre6_ip4_port[]
Definition: lb.c:61
static void lb_vip_garbage_collection(lb_vip_t *vip)
Definition: lb.c:285
u8 * format_lb_main(u8 *s, va_list *args)
Definition: lb.c:98
uword * vip_prefix_indexes
bitmap for vip prefix to support per-port vip
Definition: lb.h:479
unsigned int u32
Definition: types.h:88
u8 * format_lb_vip(u8 *s, va_list *args)
Definition: lb.c:153
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
u16 fp_len
The mask length.
Definition: fib_types.h:207
vlib_node_registration_t lb6_nodeport_node
(constructor) VLIB_REGISTER_NODE (lb6_nodeport_node)
Definition: node.c:1220
lb_vip_t * vips
Pool of all Virtual IPs.
Definition: lb.h:474
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
u32 last_used
Rotating timestamp of when LB_AS_FLAGS_USED flag was last set.
Definition: lb.h:146
ip4_address_t ip4_src_address
Source address used for IPv4 encapsulated traffic.
Definition: lb.h:517
static const char *const lb_dpo_l3dsr_ip4_port[]
Definition: lb.c:75
Definition: fib_entry.h:281
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
char * name
The counter collection&#39;s name.
Definition: counter.h:64
vl_api_fib_path_type_t type
Definition: fib_types.api:123
u8 plen
The VIP prefix length.
Definition: lb.h:298
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
static const char *const lb_dpo_nat6_ip6_port[]
Definition: lb.c:87
static const char *const lb_dpo_nat4_ip4_port[]
Definition: lb.c:81
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
Definition: fib_entry.h:285
#define lb_vip_is_gre4(vip)
Definition: lb.h:349
static const char *const lb_dpo_gre6_ip4[]
Definition: lb.c:45
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
#define lb_vip_is_gre4_port(vip)
Definition: lb.h:358
static const char *const *const lb_dpo_gre4_port_nodes[DPO_PROTO_NUM]
Definition: lb.c:55
#define lb_encap_is_ip4(vip)
Definition: lb.h:344
u32 value[LBHASH_ENTRY_PER_BUCKET]
Definition: lbhash.h:55
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
u64 key
the key
Definition: bihash_8_8.h:35
int lb_vip_del(u32 vip_index)
Definition: lb.c:1199
long ctx[MAX_CONNS]
Definition: main.c:144
vl_api_ip_proto_t protocol
Definition: punt.api:39
u8 * format_lb_vip_type(u8 *s, va_list *args)
Definition: lb.c:131
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u16 src_port
Network byte order for vip + port case, src_port = port; for node ip + node_port, src_port = node_por...
Definition: lb.h:456
static const char *const *const lb_dpo_l3dsr_port_nodes[DPO_PROTO_NUM]
Definition: lb.c:76
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
uword unformat_lb_vip_type(unformat_input_t *input, va_list *args)
Definition: lb.c:141
int lb_flush_vip_as(u32 vip_index, u32 as_index)
Definition: lb.c:759
#define LB_DEFAULT_FLOW_TIMEOUT
Definition: lb.h:47
static int lb_vip_port_find_index(ip46_address_t *prefix, u8 plen, u8 protocol, u16 port, lb_lkp_type_t lkp_type, u32 *vip_index)
Definition: lb.c:493
void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen)
Definition: util.c:18
vlib_node_registration_t lb4_nodeport_node
(constructor) VLIB_REGISTER_NODE (lb4_nodeport_node)
Definition: node.c:1204
u16 port
Definition: punt.api:40
clib_bihash_8_8_t mapping_by_as4
Definition: lb.h:554
static const char *const *const lb_dpo_gre4_nodes[DPO_PROTO_NUM]
Definition: lb.c:39
An node in the FIB graph.
Definition: fib_node.h:295
Definition: lb.h:167
fib_node_t fib_node
Registration to FIB event.
Definition: lb.h:112
u16 port
Definition: lb.h:246
u8 src_ip_is_ipv6
Definition: lb.h:449
static_always_inline void vlib_refcount_add(vlib_refcount_t *r, u32 thread_index, u32 counter_index, i32 v)
Definition: refcount.h:68
#define lb_hash_foreach_entry(h, bucket, i)
Definition: lbhash.h:72
ip46_address_t src_ip
for vip + port case, src_ip = vip; for node ip + node_port, src_ip = node_ip
Definition: lb.h:447
static const char *const lb_dpo_gre6_ip6[]
Definition: lb.c:46
u32 new_length
Definition: lb.h:579
static const dpo_vft_t lb_vft
Definition: load_balance.c:920
#define ip46_prefix_is_ip4(ip46, len)
Definition: util.h:27
#define pool_free(p)
Free a pool.
Definition: pool.h:407
static bool lb_vip_is_nat4_port(const lb_vip_t *vip)
Definition: lb.h:378
fib_node_index_t fib_table_entry_special_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags)
Add a &#39;special&#39; entry to the FIB.
Definition: fib_table.c:388
u64 value
the value
Definition: bihash_8_8.h:36
dpo_type_t dpo_l3dsr_port_type
Definition: lb.h:542
dpo_type_t dpo_nat4_port_type
Definition: lb.h:543
static const char *const lb_dpo_gre6_ip6_port[]
Definition: lb.c:62
format_function_t format_ip6_address
Definition: format.h:93
vlib_main_t * vm
Definition: buffer.c:323
static int lb_vip_prefix_index_free(lb_main_t *lbm, u32 instance)
Definition: lb.c:875
dpo_type_t dpo_gre4_port_type
Definition: lb.h:539
u32 vrf_id
Definition: lb.h:458
#define lb_vip_is_ip6(type)
Definition: lb.h:340
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
static bool lb_vip_is_nat6_port(const lb_vip_t *vip)
Definition: lb.h:383
#define lb_foreach_vip_counter
Definition: lb.h:171
#define clib_warning(format, args...)
Definition: error.h:59
vlib_main_t * vlib_main
Definition: lb.h:568
fib_node_get_t fnv_get
Definition: fib_node.h:283
u8 ip6_address[16]
Definition: ip_types.api:18
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
u32 as_index
Definition: lb.h:168
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
static fib_node_back_walk_rc_t lb_fib_node_back_walk_notify(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
Definition: lb.c:1320
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
Definition: bitmap.h:197
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
dpo_type_t dpo_gre6_type
Definition: lb.h:538
u32 last_garbage_collection
Last time garbage collection was run to free the ASs.
Definition: lb.h:281
static_always_inline void lb_hash_free(lb_hash_t *h)
Definition: lbhash.h:100
lb_as_t * ass
Pool of ASs.
Definition: lb.h:487
uword * vip_index_by_nodeport
Definition: lb.h:497
ip6_address_t addr
Definition: lb.h:433
lb_vip_type_t type
The type of traffic for this.
Definition: lb.h:313
Context passed between object during a back walk.
Definition: fib_node.h:208
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:307
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:79
u8 value
Definition: qos.api:53
#define ASSERT(truth)
static int lb_vip_port_find_diff_port(ip46_address_t *prefix, u8 plen, u8 protocol, u16 port, u32 *vip_index)
Definition: lb.c:544
int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n, u8 flush)
Definition: lb.c:793
lb_vip_type_t
The load balancer supports IPv4 and IPv6 traffic and GRE4, GRE6, L3DSR and NAT4, NAT6 encap...
Definition: lb.h:208
u16 target_port
Definition: lb.h:457
ip46_type_t
Definition: ip6_packet.h:70
int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u8 protocol, u16 port, u32 *vip_index)
Definition: lb.c:551
u8 * format_lb_as(u8 *s, va_list *args)
Definition: lb.c:184
ip46_address_t prefix
Definition: lb.h:574
u32 new_flow_table_mask
New flows table length - 1 (length MUST be a power of 2)
Definition: lb.h:276
dpo_type_t dpo_gre6_port_type
Definition: lb.h:540
static const char *const *const lb_dpo_nat6_port_nodes[DPO_PROTO_NUM]
Definition: lb.c:88
static void vlib_zero_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Clear a simple counter Clears the set of per-thread u16 counters, and the u64 counter.
Definition: counter.h:139
size_t count
Definition: vapi.c:47
lb_vip_encap_args_t encap_args
Definition: lb.h:580
u32 vip_prefix_index
Definition: lb.h:307
lb_per_cpu_t * per_cpu
Some global data is per-cpu.
Definition: lb.h:502
static void lb_dpo_unlock(dpo_id_t *dpo)
Definition: lb.c:1266
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static uword is_pow2(uword x)
Definition: clib.h:236
u16 target_port
Definition: lb.h:233
u32 as_index
Definition: lb.c:271
vlib_simple_counter_main_t vip_counters[LB_N_VIP_COUNTERS]
Per VIP counter.
Definition: lb.h:532
int lb_nat6_interface_add_del(u32 sw_if_index, int is_del)
Definition: lb.c:1343
u64 as_u64
Definition: lb.h:250
int lb_vip_add(lb_vip_add_args_t args, u32 *vip_index)
Definition: lb.c:1045
static int lb_vip_port_find_index_with_lock(ip46_address_t *prefix, u8 plen, u8 protocol, u16 port, u32 *vip_index)
Definition: lb.c:527
u8 ip4_address[4]
Definition: ip_types.api:17
static const char *const lb_dpo_gre4_ip6[]
Definition: lb.c:38
#define CLIB_SPINLOCK_ASSERT_LOCKED(_p)
Definition: lock.h:49
#define DPO_PROTO_NUM
Definition: dpo.h:70
#define LB_VIP_PER_PORT_BUCKETS
Definition: lb.h:51
ip6_address_t ip6_src_address
Source address used in IPv6 encapsulated traffic.
Definition: lb.h:512
u8 * format_lb_vip_detailed(u8 *s, va_list *args)
Definition: lb.c:192
vl_api_address_t ip
Definition: l2.api:489
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static fib_node_t * lb_fib_node_get_node(fib_node_index_t index)
Definition: lb.c:1269
u32 instance
Definition: gre.api:48
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:983
clib_spinlock_t writer_lock
Definition: lb.h:565
lb_snat_mapping_t * snat_mappings
Definition: lb.h:558
typedef key
Definition: ipsec.api:247
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:197
void lb_garbage_collection()
Definition: lb.c:354
static bool lb_vip_is_l3dsr_port(const lb_vip_t *vip)
Definition: lb.h:373
u8 protocol
Definition: lb.h:247
u16 port
Definition: lb.h:434
u32 next_hop_child_index
The child index on the FIB entry.
Definition: lb.h:156
dpo_type_t dpo_l3dsr_type
Definition: lb.h:541
#define hash_get_mem(h, key)
Definition: hash.h:269
A FIB graph nodes virtual function table.
Definition: fib_node.h:282
u32 fib_index
Definition: lb.h:459
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
clib_bihash_8_8_t vip_index_per_port
Definition: lb.h:551
static int lb_vip_add_port_filter(lb_main_t *lbm, lb_vip_t *vip, u32 vip_prefix_index, u32 vip_idx)
Add the VIP filter entry.
Definition: lb.c:962
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.
u16 protocol
Definition: lb.h:435
dpo_id_t dpo
The next DPO in the graph to follow.
Definition: lb.h:161
static const char *const lb_dpo_l3dsr_ip4[]
Definition: lb.c:69
static const char *const lb_dpo_gre4_ip4_port[]
Definition: lb.c:53
u8 flags
Some per-AS flags.
Definition: lb.h:133
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:182
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:468
ip4_address_t addr
Definition: lb.h:418
clib_bihash_24_8_t mapping_by_as6
Definition: lb.h:555
lb_new_flow_entry_t * new_flow_table
Vector mapping (flow-hash & new_connect_table_mask) to AS index.
Definition: lb.h:270
static const char *const *const lb_dpo_l3dsr_nodes[DPO_PROTO_NUM]
Definition: lb.c:70
dpo_type_t dpo_nat6_port_type
Definition: lb.h:544
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:445
u8 flags
Flags related to this VIP.
Definition: lb.h:325
lb_vip_type_t type
Definition: lb.h:578
static const char *const *const lb_dpo_gre6_port_nodes[DPO_PROTO_NUM]
Definition: lb.c:63
static char * lb_vip_type_strings[]
Definition: lb.c:121
u8 * format_lb_dpo(u8 *s, va_list *va)
Definition: lb.c:1256
ip46_address_t as_ip
Definition: lb.h:448
Load balancing service is provided per VIP+protocol+port.
Definition: lb.h:262
u32 * as_indexes
Pool of AS indexes used for this VIP.
Definition: lb.h:332
u16 fib_index
Definition: lb.h:420
#define lb_hash_size(h)
Definition: lbhash.h:65
u8 rsv
Definition: lb.h:248
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
vl_api_fib_path_nh_proto_t proto
Definition: fib_types.api:125
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:275
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
#define lb_put_writer_lock()
Definition: lb.c:32
fib_node_index_t next_hop_fib_entry_index
The FIB entry index for the next-hop.
Definition: lb.h:151
static_always_inline u32 lb_hash_elts(lb_hash_t *h, u32 time_now)
Definition: lbhash.h:186
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128