FD.io VPP  v16.09
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 <vnet/api_errno.h>
19 
20 //GC runs at most once every so many seconds
21 #define LB_GARBAGE_RUN 60
22 
23 //After so many seconds. It is assumed that inter-core race condition will not occur.
24 #define LB_CONCURRENCY_TIMEOUT 10
25 
27 
28 #define lb_get_writer_lock() do {} while(__sync_lock_test_and_set (lb_main.writer_lock, 1))
29 #define lb_put_writer_lock() lb_main.writer_lock[0] = 0
30 
32 {
33  return (u32) (vlib_time_now(vm) + 10000);
34 }
35 
36 u8 *format_lb_main (u8 * s, va_list * args)
37 {
39  lb_main_t *lbm = &lb_main;
40  s = format(s, "lb_main");
41  s = format(s, " ip4-src-address: %U \n", format_ip4_address, &lbm->ip4_src_address);
42  s = format(s, " ip6-src-address: %U \n", format_ip6_address, &lbm->ip6_src_address);
43  s = format(s, " #vips: %u\n", pool_elts(lbm->vips));
44  s = format(s, " #ass: %u\n", pool_elts(lbm->ass) - 1);
45 
46  u32 cpu_index;
47  for(cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++ ) {
48  lb_hash_t *h = lbm->per_cpu[cpu_index].sticky_ht;
49  if (h) {
50  s = format(s, "core %d\n", cpu_index);
51  s = format(s, " timeout: %ds\n", h->timeout);
52  s = format(s, " usage: %d / %d\n", lb_hash_elts(h, lb_hash_time_now(vlib_get_main())), lb_hash_size(h));
53  }
54  }
55 
56  return s;
57 }
58 
59 static char *lb_vip_type_strings[] = {
60  [LB_VIP_TYPE_IP6_GRE6] = "ip6-gre6",
61  [LB_VIP_TYPE_IP6_GRE4] = "ip6-gre4",
62  [LB_VIP_TYPE_IP4_GRE6] = "ip4-gre6",
63  [LB_VIP_TYPE_IP4_GRE4] = "ip4-gre4",
64 };
65 
66 u8 *format_lb_vip_type (u8 * s, va_list * args)
67 {
68  lb_vip_type_t vipt = va_arg (*args, lb_vip_type_t);
69  u32 i;
70  for (i=0; i<LB_VIP_N_TYPES; i++)
71  if (vipt == i)
72  return format(s, lb_vip_type_strings[i]);
73  return format(s, "_WRONG_TYPE_");
74 }
75 
76 uword unformat_lb_vip_type (unformat_input_t * input, va_list * args)
77 {
78  lb_vip_type_t *vipt = va_arg (*args, lb_vip_type_t *);
79  u32 i;
80  for (i=0; i<LB_VIP_N_TYPES; i++)
81  if (unformat(input, lb_vip_type_strings[i])) {
82  *vipt = i;
83  return 1;
84  }
85  return 0;
86 }
87 
88 u8 *format_lb_vip (u8 * s, va_list * args)
89 {
90  lb_vip_t *vip = va_arg (*args, lb_vip_t *);
91  return format(s, "%U %U new_size:%u #as:%u%s",
94  vip->new_flow_table_mask + 1,
95  pool_elts(vip->as_indexes),
96  (vip->flags & LB_VIP_FLAGS_USED)?"":" removed");
97 }
98 
99 u8 *format_lb_as (u8 * s, va_list * args)
100 {
101  lb_as_t *as = va_arg (*args, lb_as_t *);
102  return format(s, "%U %s", format_ip46_address, &as->address, (as->flags & LB_AS_FLAGS_USED)?"used":"removed");
103 }
104 
105 u8 *format_lb_vip_detailed (u8 * s, va_list * args)
106 {
107  lb_main_t *lbm = &lb_main;
108  lb_vip_t *vip = va_arg (*args, lb_vip_t *);
109  uword indent = format_get_indent (s);
110 
111  s = format(s, "%U %U [%u] %U%s\n"
112  "%U new_size:%u\n",
113  format_white_space, indent,
114  format_lb_vip_type, vip->type,
115  vip - lbm->vips, format_ip46_prefix, &vip->prefix, vip->plen, IP46_TYPE_ANY,
116  (vip->flags & LB_VIP_FLAGS_USED)?"":" removed",
117  format_white_space, indent,
118  vip->new_flow_table_mask + 1);
119 
120  //Print counters
121  s = format(s, "%U counters:\n",
122  format_white_space, indent);
123  u32 i;
124  for (i=0; i<LB_N_VIP_COUNTERS; i++)
125  s = format(s, "%U %s: %d\n",
126  format_white_space, indent,
127  lbm->vip_counters[i].name,
128  vlib_get_simple_counter(&lbm->vip_counters[i], vip - lbm->vips));
129 
130 
131  s = format(s, "%U #as:%u\n",
132  format_white_space, indent,
133  pool_elts(vip->as_indexes));
134 
135  //Let's count the buckets for each AS
136  u32 *count = 0;
137  vec_validate(count, pool_len(lbm->ass)); //Possibly big alloc for not much...
138  lb_new_flow_entry_t *nfe;
139  vec_foreach(nfe, vip->new_flow_table)
140  count[nfe->as_index]++;
141 
142  lb_as_t *as;
143  u32 *as_index;
144  pool_foreach(as_index, vip->as_indexes, {
145  as = &lbm->ass[*as_index];
146  s = format(s, "%U %U %d buckets %d flows adj:%u %s\n",
147  format_white_space, indent,
148  format_ip46_address, &as->address, IP46_TYPE_ANY,
149  count[as - lbm->ass],
150  vlib_refcount_get(&lbm->as_refcount, as - lbm->ass),
151  as->adj_index,
152  (as->flags & LB_AS_FLAGS_USED)?"used":" removed");
153  });
154 
155  vec_free(count);
156 
157  /*
158  s = format(s, "%U new flows table:\n", format_white_space, indent);
159  lb_new_flow_entry_t *nfe;
160  vec_foreach(nfe, vip->new_flow_table) {
161  s = format(s, "%U %d: %d\n", format_white_space, indent, nfe - vip->new_flow_table, nfe->as_index);
162  }
163  */
164  return s;
165 }
166 
167 
168 typedef struct {
173 
174 static int lb_pseudorand_compare(void *a, void *b)
175 {
176  lb_as_t *asa, *asb;
177  lb_main_t *lbm = &lb_main;
178  asa = &lbm->ass[((lb_pseudorand_t *)a)->as_index];
179  asb = &lbm->ass[((lb_pseudorand_t *)b)->as_index];
180  return memcmp(&asa->address, &asb->address, sizeof(asb->address));
181 }
182 
184 {
185  lb_main_t *lbm = &lb_main;
186  ASSERT (lbm->writer_lock[0]);
187 
188  u32 now = (u32) vlib_time_now(vlib_get_main());
190  return;
191 
192  vip->last_garbage_collection = now;
193  lb_as_t *as;
194  u32 *as_index;
195  pool_foreach(as_index, vip->as_indexes, {
196  as = &lbm->ass[*as_index];
197  if (!(as->flags & LB_AS_FLAGS_USED) && //Not used
198  clib_u32_loop_gt(now, as->last_used + LB_CONCURRENCY_TIMEOUT) && //Not recently used
199  (vlib_refcount_get(&lbm->as_refcount, as - lbm->ass) == 0)) { //Not referenced
200  pool_put(vip->as_indexes, as_index);
201  pool_put(lbm->ass, as);
202  }
203  });
204 }
205 
207 {
208  lb_main_t *lbm = &lb_main;
210  lb_vip_t *vip;
211  u32 *to_be_removed_vips = 0, *i;
212  pool_foreach(vip, lbm->vips, {
213  lb_vip_garbage_collection(vip);
214 
215  if (!(vip->flags & LB_VIP_FLAGS_USED) &&
216  (pool_elts(vip->as_indexes) == 0)) {
217  vec_add1(to_be_removed_vips, vip - lbm->vips);
218  }
219  });
220 
221  vec_foreach(i, to_be_removed_vips) {
222  vip = &lbm->vips[*i];
223  pool_put(lbm->vips, vip);
224  pool_free(vip->as_indexes);
225  }
226 
227  vec_free(to_be_removed_vips);
229 }
230 
232 {
233  lb_main_t *lbm = &lb_main;
234  lb_new_flow_entry_t *old_table;
235  u32 i, *as_index;
236  lb_new_flow_entry_t *new_flow_table = 0;
237  lb_as_t *as;
238  lb_pseudorand_t *pr, *sort_arr = 0;
239  u32 count;
240 
241  ASSERT (lbm->writer_lock[0]); //We must have the lock
242 
243  //Check if some AS is configured or not
244  i = 0;
245  pool_foreach(as_index, vip->as_indexes, {
246  as = &lbm->ass[*as_index];
247  if (as->flags & LB_AS_FLAGS_USED) { //Not used anymore
248  i = 1;
249  goto out; //Not sure 'break' works in this macro-loop
250  }
251  });
252 
253 out:
254  if (i == 0) {
255  //Only the default. i.e. no AS
256  vec_validate(new_flow_table, vip->new_flow_table_mask);
257  for (i=0; i<vec_len(new_flow_table); i++)
258  new_flow_table[i].as_index = 0;
259 
260  goto finished;
261  }
262 
263  //First, let's sort the ASs
264  sort_arr = 0;
265  vec_alloc(sort_arr, pool_elts(vip->as_indexes));
266 
267  i = 0;
268  pool_foreach(as_index, vip->as_indexes, {
269  as = &lbm->ass[*as_index];
270  if (!(as->flags & LB_AS_FLAGS_USED)) //Not used anymore
271  continue;
272 
273  sort_arr[i].as_index = as - lbm->ass;
274  i++;
275  });
276  _vec_len(sort_arr) = i;
277 
279 
280  //Now let's pseudo-randomly generate permutations
281  vec_foreach(pr, sort_arr) {
282  lb_as_t *as = &lbm->ass[pr->as_index];
283 
284  u64 seed = clib_xxhash(as->address.as_u64[0] ^
285  as->address.as_u64[1]);
286  /* We have 2^n buckets.
287  * skip must be prime with 2^n.
288  * So skip must be odd.
289  * MagLev actually state that M should be prime,
290  * but this has a big computation cost (% operation).
291  * Using 2^n is more better (& operation).
292  */
293  pr->skip = ((seed & 0xffffffff) | 1) & vip->new_flow_table_mask;
294  pr->last = (seed >> 32) & vip->new_flow_table_mask;
295  }
296 
297  //Let's create a new flow table
298  vec_validate(new_flow_table, vip->new_flow_table_mask);
299  for (i=0; i<vec_len(new_flow_table); i++)
300  new_flow_table[i].as_index = ~0;
301 
302  u32 done = 0;
303  while (1) {
304  vec_foreach(pr, sort_arr) {
305  while (1) {
306  u32 last = pr->last;
307  pr->last = (pr->last + pr->skip) & vip->new_flow_table_mask;
308  if (new_flow_table[last].as_index == ~0) {
309  new_flow_table[last].as_index = pr->as_index;
310  break;
311  }
312  }
313  done++;
314  if (done == vec_len(new_flow_table))
315  goto finished;
316  }
317  }
318 
319  vec_free(sort_arr);
320 
321 finished:
322 
323 //Count number of changed entries
324  count = 0;
325  for (i=0; i<vec_len(new_flow_table); i++)
326  if (vip->new_flow_table == 0 ||
327  new_flow_table[i].as_index != vip->new_flow_table[i].as_index)
328  count++;
329 
330  old_table = vip->new_flow_table;
331  vip->new_flow_table = new_flow_table;
332  vec_free(old_table);
333 }
334 
335 int lb_conf(ip4_address_t *ip4_address, ip6_address_t *ip6_address,
336  u32 per_cpu_sticky_buckets, u32 flow_timeout)
337 {
338  lb_main_t *lbm = &lb_main;
339 
340  if (!is_pow2(per_cpu_sticky_buckets))
341  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
342 
343  lb_get_writer_lock(); //Not exactly necessary but just a reminder that it exists for my future self
344  lbm->ip4_src_address = *ip4_address;
345  lbm->ip6_src_address = *ip6_address;
346  lbm->per_cpu_sticky_buckets = per_cpu_sticky_buckets;
347  lbm->flow_timeout = flow_timeout;
349  return 0;
350 }
351 
352 static
353 int lb_vip_find_index_with_lock(ip46_address_t *prefix, u8 plen, u32 *vip_index)
354 {
355  lb_main_t *lbm = &lb_main;
356  lb_vip_t *vip;
357  ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
358  ip46_prefix_normalize(prefix, plen);
359  pool_foreach(vip, lbm->vips, {
360  if ((vip->flags & LB_AS_FLAGS_USED) &&
361  vip->plen == plen &&
362  vip->prefix.as_u64[0] == prefix->as_u64[0] &&
363  vip->prefix.as_u64[1] == prefix->as_u64[1]) {
364  *vip_index = vip - lbm->vips;
365  return 0;
366  }
367  });
368  return VNET_API_ERROR_NO_SUCH_ENTRY;
369 }
370 
371 int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index)
372 {
373  int ret;
375  ret = lb_vip_find_index_with_lock(prefix, plen, vip_index);
377  return ret;
378 }
379 
380 static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index)
381 {
382  lb_main_t *lbm = &lb_main;
383  ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
384  lb_as_t *as;
385  u32 *asi;
386  pool_foreach(asi, vip->as_indexes, {
387  as = &lbm->ass[*asi];
388  if (as->vip_index == (vip - lbm->vips) &&
389  as->address.as_u64[0] == address->as_u64[0] &&
390  as->address.as_u64[1] == address->as_u64[1]) {
391  *as_index = as - lbm->ass;
392  return 0;
393  }
394  });
395  return -1;
396 }
397 
398 int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
399 {
400  lb_main_t *lbm = &lb_main;
402  lb_vip_t *vip;
403  if (!(vip = lb_vip_get_by_index(vip_index))) {
405  return VNET_API_ERROR_NO_SUCH_ENTRY;
406  }
407 
409  u32 *to_be_added = 0;
410  u32 *to_be_updated = 0;
411  u32 i;
412  u32 *ip;
413 
414  //Sanity check
415  while (n--) {
416 
417  if (!lb_as_find_index_vip(vip, &addresses[n], &i)) {
418  if (lbm->ass[i].flags & LB_AS_FLAGS_USED) {
419  vec_free(to_be_added);
420  vec_free(to_be_updated);
422  return VNET_API_ERROR_VALUE_EXIST;
423  }
424  vec_add1(to_be_updated, i);
425  goto next;
426  }
427 
428  if (ip46_address_type(&addresses[n]) != type) {
429  vec_free(to_be_added);
430  vec_free(to_be_updated);
432  return VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
433  }
434 
435  if (n) {
436  u32 n2 = n;
437  while(n2--) //Check for duplicates
438  if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] &&
439  addresses[n2].as_u64[1] == addresses[n].as_u64[1])
440  goto next;
441  }
442 
443  vec_add1(to_be_added, n);
444 
445 next:
446  continue;
447  }
448 
449  //Update reused ASs
450  vec_foreach(ip, to_be_updated) {
451  lbm->ass[*ip].flags = LB_AS_FLAGS_USED;
452  lbm->ass[*ip].adj_index = ~0;
453  }
454  vec_free(to_be_updated);
455 
456  //Create those who have to be created
457  vec_foreach(ip, to_be_added) {
458  lb_as_t *as;
459  u32 *as_index;
460  pool_get(lbm->ass, as);
461  as->address = addresses[*ip];
462  as->flags = LB_AS_FLAGS_USED;
463  as->vip_index = vip_index;
464  as->adj_index = ~0;
465  pool_get(vip->as_indexes, as_index);
466  *as_index = as - lbm->ass;
467  }
468  vec_free(to_be_added);
469 
470  //Recompute flows
472 
473  //Garbage collection maybe
475 
477  return 0;
478 }
479 
480 int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n)
481 {
482  lb_main_t *lbm = &lb_main;
483  u32 now = (u32) vlib_time_now(vlib_get_main());
484  u32 *ip = 0;
485 
486  lb_vip_t *vip;
487  if (!(vip = lb_vip_get_by_index(vip_index))) {
488  return VNET_API_ERROR_NO_SUCH_ENTRY;
489  }
490 
491  u32 *indexes = NULL;
492  while (n--) {
493  u32 i;
494  if (lb_as_find_index_vip(vip, &addresses[n], &i)) {
495  vec_free(indexes);
496  return VNET_API_ERROR_NO_SUCH_ENTRY;
497  }
498 
499  if (n) { //Check for duplicates
500  u32 n2 = n - 1;
501  while(n2--) {
502  if (addresses[n2].as_u64[0] == addresses[n].as_u64[0] &&
503  addresses[n2].as_u64[1] == addresses[n].as_u64[1])
504  goto next;
505  }
506  }
507 
508  vec_add1(indexes, i);
509 next:
510  continue;
511  }
512 
513  //Garbage collection maybe
515 
516  if (indexes != NULL) {
517  vec_foreach(ip, indexes) {
518  lbm->ass[*ip].flags &= ~LB_AS_FLAGS_USED;
519  lbm->ass[*ip].last_used = now;
520  }
521 
522  //Recompute flows
524  }
525 
526  vec_free(indexes);
527  return 0;
528 }
529 
530 int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
531 {
533  int ret = lb_vip_del_ass_withlock(vip_index, addresses, n);
535  return ret;
536 }
537 
538 int lb_as_lookup_bypass(u32 vip_index, ip46_address_t *address, u8 is_disable)
539 {
541  lb_main_t *lbm = &lb_main;
542  u32 as_index;
543  lb_as_t *as;
544  lb_vip_t *vip;
545 
546  if (!(vip = lb_vip_get_by_index(vip_index)) ||
547  lb_as_find_index_vip(vip, address, &as_index)) {
549  return VNET_API_ERROR_NO_SUCH_ENTRY;
550  }
551 
552  as = &lbm->ass[as_index];
553 
554  if (is_disable) {
555  as->adj_index = ~0;
556  } else if (lb_vip_is_gre4(vip)) {
557  uword *p = ip4_get_route (&ip4_main, 0, 0, as->address.ip4.as_u8, 32);
558  if (p == 0) {
560  return VNET_API_ERROR_NO_SUCH_ENTRY;
561  }
562  u32 ai = (u32)p[0];
564  ip_adjacency_t *adj4 = ip_get_adjacency (lm4, ai);
567  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
568  }
569 
570  as->adj_index = ai;
571  } else {
572  u32 ai = ip6_get_route (&ip6_main, 0, 0, &as->address.ip6, 128);
573  if (ai == 0) {
575  return VNET_API_ERROR_NO_SUCH_ENTRY;
576  }
577 
579  ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
582  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
583  }
584 
585  as->adj_index = ai;
586  }
588  return 0;
589 }
590 
591 
592 /**
593  * Add the VIP adjacency to the ip4 or ip6 fib
594  */
595 static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip)
596 {
597  ip_adjacency_t adj;
598  //Adjacency
599  memset (&adj, 0, sizeof (adj));
600  adj.explicit_fib_index = ~0;
601  lb_adj_data_t *ad = (lb_adj_data_t *) &adj.opaque;
602  ad->vip_index = vip - lbm->vips;
603 
604  ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
605  u32 lookup_next_index = lbm->ip_lookup_next_index[vip->type];
606 
607  if (lb_vip_is_ip4(vip)) {
608  adj.lookup_next_index = lookup_next_index;
609  ip4_add_del_route_args_t route_args = {};
610  ip4_main_t *im4 = &ip4_main;
611  route_args.table_index_or_table_id = 0;
612  route_args.flags = IP4_ROUTE_FLAG_ADD;
613  route_args.dst_address = vip->prefix.ip4;
614  route_args.dst_address_length = vip->plen - 96;
615  route_args.adj_index = ~0;
616  route_args.add_adj = &adj;
617  route_args.n_add_adj = 1;
618  ip4_add_del_route (im4, &route_args);
619  } else {
620  adj.lookup_next_index = lookup_next_index;
621  ip6_add_del_route_args_t route_args = {};
622  ip6_main_t *im6 = &ip6_main;
623  route_args.table_index_or_table_id = 0;
624  route_args.flags = IP6_ROUTE_FLAG_ADD;
625  route_args.dst_address = vip->prefix.ip6;
626  route_args.dst_address_length = vip->plen;
627  route_args.adj_index = ~0;
628  route_args.add_adj = &adj;
629  route_args.n_add_adj = 1;
630  ip6_add_del_route (im6, &route_args);
631  }
632 }
633 
634 /**
635  * Deletes the adjacency associated with the VIP
636  */
637 static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip)
638 {
639  ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
640  if (lb_vip_is_ip4(vip)) {
641  ip4_main_t *im4 = &ip4_main;
642  ip4_add_del_route_args_t route_args = {};
643  route_args.table_index_or_table_id = 0;
644  route_args.flags = IP4_ROUTE_FLAG_DEL;
645  route_args.dst_address = vip->prefix.ip4;
646  route_args.dst_address_length = vip->plen - 96;
647  route_args.adj_index = ~0;
648  route_args.add_adj = NULL;
649  route_args.n_add_adj = 0;
650  ip4_add_del_route (im4, &route_args);
651  } else {
652  ip6_main_t *im6 = &ip6_main;
653  ip6_add_del_route_args_t route_args = {};
654  route_args.table_index_or_table_id = 0;
655  route_args.flags = IP6_ROUTE_FLAG_DEL;
656  route_args.dst_address = vip->prefix.ip6;
657  route_args.dst_address_length = vip->plen;
658  route_args.adj_index = ~0;
659  route_args.add_adj = NULL;
660  route_args.n_add_adj = 0;
661  ip6_add_del_route (im6, &route_args);
662  }
663 }
664 
665 int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u32 new_length, u32 *vip_index)
666 {
667  lb_main_t *lbm = &lb_main;
668  lb_vip_t *vip;
670  ip46_prefix_normalize(prefix, plen);
671 
672  if (!lb_vip_find_index_with_lock(prefix, plen, vip_index)) {
674  return VNET_API_ERROR_VALUE_EXIST;
675  }
676 
677  if (!is_pow2(new_length)) {
679  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
680  }
681 
682  if (ip46_prefix_is_ip4(prefix, plen) &&
683  (type != LB_VIP_TYPE_IP4_GRE4) &&
684  (type != LB_VIP_TYPE_IP4_GRE6))
685  return VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
686 
687 
688  //Allocate
689  pool_get(lbm->vips, vip);
690 
691  //Init
692  vip->prefix = *prefix;
693  vip->plen = plen;
695  vip->type = type;
696  vip->flags = LB_VIP_FLAGS_USED;
697  vip->as_indexes = 0;
698 
699  //Validate counters
700  u32 i;
701  for (i = 0; i < LB_N_VIP_COUNTERS; i++) {
702  vlib_validate_simple_counter(&lbm->vip_counters[i], vip - lbm->vips);
703  vlib_zero_simple_counter(&lbm->vip_counters[i], vip - lbm->vips);
704  }
705 
706  //Configure new flow table
707  vip->new_flow_table_mask = new_length - 1;
708  vip->new_flow_table = 0;
709 
710  //Create a new flow hash table full of the default entry
712 
713  //Create adjacency to direct traffic
714  lb_vip_add_adjacency(lbm, vip);
715 
716  //Return result
717  *vip_index = vip - lbm->vips;
718 
720  return 0;
721 }
722 
723 int lb_vip_del(u32 vip_index)
724 {
725  lb_main_t *lbm = &lb_main;
726  lb_vip_t *vip;
728  if (!(vip = lb_vip_get_by_index(vip_index))) {
730  return VNET_API_ERROR_NO_SUCH_ENTRY;
731  }
732 
733  //FIXME: This operation is actually not working
734  //We will need to remove state before performing this.
735 
736  {
737  //Remove all ASs
738  ip46_address_t *ass = 0;
739  lb_as_t *as;
740  u32 *as_index;
741  pool_foreach(as_index, vip->as_indexes, {
742  as = &lbm->ass[*as_index];
743  vec_add1(ass, as->address);
744  });
745  if (vec_len(ass))
746  lb_vip_del_ass_withlock(vip_index, ass, vec_len(ass));
747  vec_free(ass);
748  }
749 
750  //Delete adjacency
751  lb_vip_del_adjacency(lbm, vip);
752 
753  //Set the VIP as unused
754  vip->flags &= ~LB_VIP_FLAGS_USED;
755 
757  return 0;
758 }
759 
760 clib_error_t *
763  int from_early_init)
764 {
765  clib_error_t *error = 0;
766  return error;
767 }
768 
769 clib_error_t *
771 {
773  lb_main_t *lbm = &lb_main;
774  lb_as_t *default_as;
775  lbm->vips = 0;
776  lbm->per_cpu = 0;
777  vec_validate(lbm->per_cpu, tm->n_vlib_mains - 1);
779  lbm->writer_lock[0] = 0;
782  lbm->ip4_src_address.as_u32 = 0xffffffff;
783  lbm->ip6_src_address.as_u64[0] = 0xffffffffffffffffL;
784  lbm->ip6_src_address.as_u64[1] = 0xffffffffffffffffL;
785 
786  //Init AS reference counters
788 
789  //Allocate and init default AS.
790  lbm->ass = 0;
791  pool_get(lbm->ass, default_as);
792  default_as->flags = 0;
793  default_as->adj_index = ~0;
794  default_as->vip_index = ~0;
795  default_as->address.ip6.as_u64[0] = 0xffffffffffffffffL;
796  default_as->address.ip6.as_u64[1] = 0xffffffffffffffffL;
797 
798 #define _(a,b,c) lbm->vip_counters[c].name = b;
800 #undef _
801  return NULL;
802 }
803 
u32 skip
Definition: lb.c:171
format_function_t format_ip46_address
Definition: format.h:54
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
u32 ip_lookup_next_index[LB_VIP_N_TYPES]
Node next index for IP adjacencies, for each of the traffic types.
Definition: lb.h:236
u32 lb_hash_time_now(vlib_main_t *vm)
Definition: lb.c:31
static int lb_pseudorand_compare(void *a, void *b)
Definition: lb.c:174
Each VIP is configured with a set of application server.
Definition: lb.h:48
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define LB_GARBAGE_RUN
Definition: lb.c:21
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
void ip46_prefix_normalize(ip46_address_t *prefix, u8 plen)
Definition: util.c:18
a
Definition: bitmap.h:516
format_function_t format_ip6_address
Definition: format.h:87
u32 last
Definition: lb.c:170
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
u32 per_cpu_sticky_buckets
Number of buckets in the per-cpu sticky hash table.
Definition: lb.h:251
clib_error_t * lb_init(vlib_main_t *vm)
Definition: lb.c:770
clib_error_t * vlib_plugin_register(vlib_main_t *vm, vnet_plugin_handoff_t *h, int from_early_init)
Definition: lb.c:761
u64 as_u64
Definition: bihash_doc.h:63
ip_lookup_next_t lookup_next_index
Definition: lookup.h:180
u64 as_u64[2]
Definition: ip6_packet.h:50
static void lb_vip_update_new_flow_table(lb_vip_t *vip)
Definition: lb.c:231
IP unicast adjacency.
Definition: lookup.h:164
static int lb_as_find_index_vip(lb_vip_t *vip, ip46_address_t *address, u32 *as_index)
Definition: lb.c:380
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
u8 * format_ip46_prefix(u8 *s, va_list *args)
Definition: util.c:54
static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip)
Deletes the adjacency associated with the VIP.
Definition: lb.c:637
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:335
#define lb_get_writer_lock()
Definition: lb.c:28
int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:398
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
ip46_address_t prefix
A Virtual IP represents a given service delivered by a set of application servers.
Definition: lb.h:161
#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
static_always_inline void vlib_refcount_init(vlib_refcount_t *r)
Definition: refcount.h:60
ip_lookup_main_t lookup_main
Definition: ip4.h:115
u8 opaque[IP_ADJACENCY_OPAQUE_SZ]
Definition: lookup.h:204
u32 adj_index
Second ip lookup can be avoided by sending directly the packet to ip-rewrite with a configured adjace...
Definition: lb.h:62
#define lb_vip_get_by_index(index)
Definition: lb.h:300
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
u32 vip_index
ASs are indexed by address and VIP Index.
Definition: lb.h:69
format_function_t format_ip4_address
Definition: format.h:71
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:239
lb_hash_t * sticky_ht
Each CPU has its own sticky flow hash table.
Definition: lb.h:204
#define pool_len(p)
Number of elements in pool vector.
Definition: pool.h:121
#define LB_VIP_FLAGS_USED
Definition: lb.h:190
#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:55
int lb_vip_del_ass_withlock(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:480
u32 timeout
Definition: lbhash.h:46
#define LB_AS_FLAGS_USED
Definition: lb.h:77
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
#define LB_DEFAULT_PER_CPU_STICKY_BUCKETS
lb-plugin implements a MagLev-like load balancer.
Definition: lb.h:41
lb_main_t lb_main
Definition: lb.c:26
u32 flow_timeout
Flow timeout in seconds.
Definition: lb.h:256
Definition: lb.h:207
static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip)
Add the VIP adjacency to the ip4 or ip6 fib.
Definition: lb.c:595
vlib_refcount_t as_refcount
Each AS has an associated reference counter.
Definition: lb.h:226
u32 table_index_or_table_id
Definition: ip6.h:367
unsigned long u64
Definition: types.h:89
static void lb_vip_garbage_collection(lb_vip_t *vip)
Definition: lb.c:183
u8 * format_lb_main(u8 *s, va_list *args)
Definition: lb.c:36
u8 * format_lb_vip(u8 *s, va_list *args)
Definition: lb.c:88
#define lb_vip_is_ip4(vip)
Definition: lb.h:194
void ip6_add_del_route(ip6_main_t *im, ip6_add_del_route_args_t *args)
Definition: ip6_forward.c:208
lb_vip_t * vips
Pool of all Virtual IPs.
Definition: lb.h:211
u32 last_used
Rotating timestamp of when LB_AS_FLAGS_USED flag was last set.
Definition: lb.h:88
ip4_address_t ip4_src_address
Source address used for IPv4 encapsulated traffic.
Definition: lb.h:246
char * name
The counter collection&#39;s name.
Definition: counter.h:68
u8 plen
The VIP prefix length.
Definition: lb.h:167
ip6_address_t dst_address
Definition: ip6.h:370
#define lb_vip_is_gre4(vip)
Definition: lb.h:195
static uword format_get_indent(u8 *s)
Definition: format.h:72
int lb_vip_del(u32 vip_index)
Definition: lb.c:723
void * ip4_get_route(ip4_main_t *im, u32 fib_index_or_table_id, u32 flags, u8 *address, u32 address_length)
Definition: ip4_forward.c:537
u8 * format_lb_vip_type(u8 *s, va_list *args)
Definition: lb.c:66
ip_adjacency_t * add_adj
Definition: ip6.h:379
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
uword unformat_lb_vip_type(unformat_input_t *input, va_list *args)
Definition: lb.c:76
#define LB_DEFAULT_FLOW_TIMEOUT
Definition: lb.h:42
u32 ip6_get_route(ip6_main_t *im, u32 fib_index_or_table_id, u32 flags, ip6_address_t *address, u32 address_length)
Definition: ip6_forward.c:572
Definition: lb.h:93
ip46_type_t
Definition: format.h:56
ip_adjacency_t * add_adj
Definition: ip4.h:337
#define ip46_prefix_is_ip4(ip46, len)
Definition: util.h:27
#define pool_free(p)
Free a pool.
Definition: pool.h:263
int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u32 new_length, u32 *vip_index)
Definition: lb.c:665
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
volatile u32 * writer_lock
Definition: lb.h:268
#define lb_foreach_vip_counter
Definition: lb.h:97
u32 vip_index
Index of the VIP associated with that IP adjacency.
Definition: lb.h:278
int lb_as_lookup_bypass(u32 vip_index, ip46_address_t *address, u8 is_disable)
Updates the adjacency index stored in the AS such that the second IP lookup (after encap) can be bypa...
Definition: lb.c:538
#define IP6_ROUTE_FLAG_DEL
Definition: ip6.h:352
u32 as_index
Definition: lb.h:94
int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:530
u32 last_garbage_collection
Last time garbage collection was run to free the ASs.
Definition: lb.h:150
#define IP4_ROUTE_FLAG_DEL
Definition: ip4.h:309
lb_as_t * ass
Pool of ASs.
Definition: lb.h:219
lb_vip_type_t type
The type of traffic for this.
Definition: lb.h:173
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:98
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
lb_vip_type_t
The load balancer supports IPv4 and IPv6 traffic and GRE4 and GRE6 encap.
Definition: lb.h:112
struct stored in adj->opaque data.
Definition: lb.h:274
ip4_address_t dst_address
Definition: ip4.h:328
#define IP4_ROUTE_FLAG_ADD
Definition: ip4.h:308
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index)
Definition: lb.c:371
u8 * format_lb_as(u8 *s, va_list *args)
Definition: lb.c:99
IPv4 main type.
Definition: ip4.h:114
u32 new_flow_table_mask
New flows table length - 1 (length MUST be a power of 2)
Definition: lb.h:145
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:143
lb_per_cpu_t * per_cpu
Some global data is per-cpu.
Definition: lb.h:231
static uword is_pow2(uword x)
Definition: clib.h:266
u32 as_index
Definition: lb.c:169
u64 uword
Definition: types.h:112
vlib_simple_counter_main_t vip_counters[LB_N_VIP_COUNTERS]
Per VIP counter.
Definition: lb.h:261
ip6_address_t ip6_src_address
Source address used in IPv6 encapsulated traffic.
Definition: lb.h:241
u8 * format_lb_vip_detailed(u8 *s, va_list *args)
Definition: lb.c:105
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:900
void lb_garbage_collection()
Definition: lb.c:206
u32 table_index_or_table_id
Definition: ip4.h:325
static int lb_vip_find_index_with_lock(ip46_address_t *prefix, u8 plen, u32 *vip_index)
Definition: lb.c:353
static u64 vlib_get_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Get the value of a simple counter Scrapes the entire set of mini counters.
Definition: counter.h:108
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:114
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
This packet is to be rewritten and forwarded to the next processing node.
Definition: lookup.h:78
#define IP6_ROUTE_FLAG_ADD
Definition: ip6.h:351
#define vec_foreach(var, vec)
Vector iterator.
i16 explicit_fib_index
Force re-lookup in a different FIB.
Definition: lookup.h:185
u8 flags
Some per-AS flags.
Definition: lb.h:75
struct _unformat_input_t unformat_input_t
lb_new_flow_entry_t * new_flow_table
Vector mapping (flow-hash & new_connect_table_mask) to AS index.
Definition: lb.h:139
void ip4_add_del_route(ip4_main_t *im, ip4_add_del_route_args_t *args)
Definition: ip4_forward.c:228
u8 flags
Flags related to this VIP.
Definition: lb.h:182
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
static char * lb_vip_type_strings[]
Definition: lb.c:59
Load balancing service is provided per VIP.
Definition: lb.h:131
u32 * as_indexes
Pool of AS indexes used for this VIP.
Definition: lb.h:188
#define lb_hash_size(h)
Definition: lbhash.h:51
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480
#define lb_put_writer_lock()
Definition: lb.c:29
static_always_inline u32 lb_hash_elts(lb_hash_t *h, u32 time_now)
Definition: lbhash.h:172
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109