FD.io VPP  v18.07.1-19-g511ce25
Vector Packet Processing
cli.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 <lb/util.h>
18 
19 static clib_error_t *
21  unformat_input_t * input, vlib_cli_command_t * cmd)
22 {
23  unformat_input_t _line_input, *line_input = &_line_input;
24  lb_vip_add_args_t args;
25  u8 del = 0;
26  int ret;
27  u32 encap = 0;
28  u32 dscp = ~0;
29  u32 srv_type = LB_SRV_TYPE_CLUSTERIP;
30  u32 port = 0;
31  u32 target_port = 0;
32  u32 node_port = 0;
33  clib_error_t *error = 0;
34 
35  args.new_length = 1024;
36 
37  if (!unformat_user (input, unformat_line_input, line_input))
38  return 0;
39 
40  if (!unformat(line_input, "%U", unformat_ip46_prefix, &(args.prefix),
41  &(args.plen), IP46_TYPE_ANY, &(args.plen))) {
42  error = clib_error_return (0, "invalid vip prefix: '%U'",
43  format_unformat_error, line_input);
44  goto done;
45  }
46 
47  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
48  {
49  if (unformat(line_input, "new_len %d", &(args.new_length)))
50  ;
51  else if (unformat(line_input, "del"))
52  del = 1;
53  else if (unformat(line_input, "encap gre4"))
54  encap = LB_ENCAP_TYPE_GRE4;
55  else if (unformat(line_input, "encap gre6"))
56  encap = LB_ENCAP_TYPE_GRE6;
57  else if (unformat(line_input, "encap l3dsr"))
58  encap = LB_ENCAP_TYPE_L3DSR;
59  else if (unformat(line_input, "encap nat4"))
60  encap = LB_ENCAP_TYPE_NAT4;
61  else if (unformat(line_input, "encap nat6"))
62  encap = LB_ENCAP_TYPE_NAT6;
63  else if (unformat(line_input, "dscp %d", &dscp))
64  ;
65  else if (unformat(line_input, "type clusterip"))
66  srv_type = LB_SRV_TYPE_CLUSTERIP;
67  else if (unformat(line_input, "type nodeport"))
68  srv_type = LB_SRV_TYPE_NODEPORT;
69  else if (unformat(line_input, "port %d", &port))
70  ;
71  else if (unformat(line_input, "target_port %d", &target_port))
72  ;
73  else if (unformat(line_input, "node_port %d", &node_port))
74  ;
75  else {
76  error = clib_error_return (0, "parse error: '%U'",
77  format_unformat_error, line_input);
78  goto done;
79  }
80  }
81 
82  if ((encap != LB_ENCAP_TYPE_L3DSR) && (dscp != ~0))
83  {
84  error = clib_error_return(0, "lb_vip_add error: "
85  "should not configure dscp for none L3DSR.");
86  goto done;
87  }
88 
89  if ((encap == LB_ENCAP_TYPE_L3DSR) && (dscp >= 64))
90  {
91  error = clib_error_return(0, "lb_vip_add error: "
92  "dscp for L3DSR should be less than 64.");
93  goto done;
94  }
95 
96  if (ip46_prefix_is_ip4(&(args.prefix), (args.plen)))
97  {
98  if (encap == LB_ENCAP_TYPE_GRE4)
100  else if (encap == LB_ENCAP_TYPE_GRE6)
101  args.type = LB_VIP_TYPE_IP4_GRE6;
102  else if (encap == LB_ENCAP_TYPE_L3DSR)
104  else if (encap == LB_ENCAP_TYPE_NAT4)
105  args.type = LB_VIP_TYPE_IP4_NAT4;
106  else if (encap == LB_ENCAP_TYPE_NAT6)
107  {
108  error = clib_error_return(0, "currently does not support NAT46");
109  goto done;
110  }
111  }
112  else
113  {
114  if (encap == LB_ENCAP_TYPE_GRE4)
115  args.type = LB_VIP_TYPE_IP6_GRE4;
116  else if (encap == LB_ENCAP_TYPE_GRE6)
117  args.type = LB_VIP_TYPE_IP6_GRE6;
118  else if (encap == LB_ENCAP_TYPE_NAT6)
119  args.type = LB_VIP_TYPE_IP6_NAT6;
120  else if (encap == LB_ENCAP_TYPE_NAT4)
121  {
122  error = clib_error_return(0, "currently does not support NAT64");
123  goto done;
124  }
125  }
126 
128 
129  u32 index;
130  if (!del) {
131  if (encap == LB_ENCAP_TYPE_L3DSR) {
132  args.encap_args.dscp = (u8)(dscp & 0x3F);
133  }
134  else if ((encap == LB_ENCAP_TYPE_NAT4)
135  || (encap == LB_ENCAP_TYPE_NAT6))
136  {
137  args.encap_args.srv_type = (u8) srv_type;
138  args.encap_args.port = (u16) port;
139  args.encap_args.target_port = (u16) target_port;
140  args.encap_args.node_port = (u16) node_port;
141  }
142 
143  if ((ret = lb_vip_add(args, &index))) {
144  error = clib_error_return (0, "lb_vip_add error %d", ret);
145  goto done;
146  } else {
147  vlib_cli_output(vm, "lb_vip_add ok %d", index);
148  }
149  } else {
150  if ((ret = lb_vip_find_index(&(args.prefix), args.plen, &index))) {
151  error = clib_error_return (0, "lb_vip_find_index error %d", ret);
152  goto done;
153  } else if ((ret = lb_vip_del(index))) {
154  error = clib_error_return (0, "lb_vip_del error %d", ret);
155  goto done;
156  }
157  }
158 
159 done:
160  unformat_free (line_input);
161 
162  return error;
163 }
164 
165 VLIB_CLI_COMMAND (lb_vip_command, static) =
166 {
167  .path = "lb vip",
168  .short_help = "lb vip <prefix> [encap (gre6|gre4|l3dsr|nat4|nat6)] "
169  "[dscp <n>] "
170  "[type (nodeport|clusterip) port <n> target_port <n> node_port <n>] "
171  "[new_len <n>] [del]",
172  .function = lb_vip_command_fn,
173 };
174 
175 static clib_error_t *
177  unformat_input_t * input, vlib_cli_command_t * cmd)
178 {
179  unformat_input_t _line_input, *line_input = &_line_input;
180  ip46_address_t vip_prefix, as_addr;
181  u8 vip_plen;
182  ip46_address_t *as_array = 0;
183  u32 vip_index;
184  u8 del = 0;
185  int ret;
186  clib_error_t *error = 0;
187 
188  if (!unformat_user (input, unformat_line_input, line_input))
189  return 0;
190 
191  if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) {
192  error = clib_error_return (0, "invalid as address: '%U'",
193  format_unformat_error, line_input);
194  goto done;
195  }
196 
197  if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) {
198  error = clib_error_return (0, "lb_vip_find_index error %d", ret);
199  goto done;
200  }
201 
202  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
203  {
204  if (unformat(line_input, "%U", unformat_ip46_address, &as_addr, IP46_TYPE_ANY)) {
205  vec_add1(as_array, as_addr);
206  } else if (unformat(line_input, "del")) {
207  del = 1;
208  } else {
209  error = clib_error_return (0, "parse error: '%U'",
210  format_unformat_error, line_input);
211  goto done;
212  }
213  }
214 
215  if (!vec_len(as_array)) {
216  error = clib_error_return (0, "No AS address provided");
217  goto done;
218  }
219 
221  clib_warning("vip index is %d", vip_index);
222 
223  if (del) {
224  if ((ret = lb_vip_del_ass(vip_index, as_array, vec_len(as_array)))) {
225  error = clib_error_return (0, "lb_vip_del_ass error %d", ret);
226  goto done;
227  }
228  } else {
229  if ((ret = lb_vip_add_ass(vip_index, as_array, vec_len(as_array)))) {
230  error = clib_error_return (0, "lb_vip_add_ass error %d", ret);
231  goto done;
232  }
233  }
234 
235 done:
236  unformat_free (line_input);
237  vec_free(as_array);
238 
239  return error;
240 }
241 
242 VLIB_CLI_COMMAND (lb_as_command, static) =
243 {
244  .path = "lb as",
245  .short_help = "lb as <vip-prefix> [<address> [<address> [...]]] [del]",
246  .function = lb_as_command_fn,
247 };
248 
249 static clib_error_t *
251  unformat_input_t * input, vlib_cli_command_t * cmd)
252 {
253  lb_main_t *lbm = &lb_main;
254  unformat_input_t _line_input, *line_input = &_line_input;
255  ip4_address_t ip4 = lbm->ip4_src_address;
256  ip6_address_t ip6 = lbm->ip6_src_address;
257  u32 per_cpu_sticky_buckets = lbm->per_cpu_sticky_buckets;
258  u32 per_cpu_sticky_buckets_log2 = 0;
259  u32 flow_timeout = lbm->flow_timeout;
260  int ret;
261  clib_error_t *error = 0;
262 
263  if (!unformat_user (input, unformat_line_input, line_input))
264  return 0;
265 
266  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
267  {
268  if (unformat(line_input, "ip4-src-address %U", unformat_ip4_address, &ip4))
269  ;
270  else if (unformat(line_input, "ip6-src-address %U", unformat_ip6_address, &ip6))
271  ;
272  else if (unformat(line_input, "buckets %d", &per_cpu_sticky_buckets))
273  ;
274  else if (unformat(line_input, "buckets-log2 %d", &per_cpu_sticky_buckets_log2)) {
275  if (per_cpu_sticky_buckets_log2 >= 32)
276  return clib_error_return (0, "buckets-log2 value is too high");
277  per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2;
278  } else if (unformat(line_input, "timeout %d", &flow_timeout))
279  ;
280  else {
281  error = clib_error_return (0, "parse error: '%U'",
282  format_unformat_error, line_input);
283  goto done;
284  }
285  }
286 
288 
289  if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) {
290  error = clib_error_return (0, "lb_conf error %d", ret);
291  goto done;
292  }
293 
294 done:
295  unformat_free (line_input);
296 
297  return error;
298 }
299 
300 VLIB_CLI_COMMAND (lb_conf_command, static) =
301 {
302  .path = "lb conf",
303  .short_help = "lb conf [ip4-src-address <addr>] [ip6-src-address <addr>] [buckets <n>] [timeout <s>]",
304  .function = lb_conf_command_fn,
305 };
306 
307 static clib_error_t *
309  unformat_input_t * input, vlib_cli_command_t * cmd)
310 {
311  vlib_cli_output(vm, "%U", format_lb_main);
312  return NULL;
313 }
314 
315 
316 VLIB_CLI_COMMAND (lb_show_command, static) =
317 {
318  .path = "show lb",
319  .short_help = "show lb",
320  .function = lb_show_command_fn,
321 };
322 
323 static clib_error_t *
325  unformat_input_t * input, vlib_cli_command_t * cmd)
326 {
327  unformat_input_t line_input;
328  lb_main_t *lbm = &lb_main;
329  lb_vip_t *vip;
330  u8 verbose = 0;
331 
332  if (!unformat_user (input, unformat_line_input, &line_input))
333  return 0;
334 
335  if (unformat(&line_input, "verbose"))
336  verbose = 1;
337 
338  pool_foreach(vip, lbm->vips, {
339  vlib_cli_output(vm, "%U\n", verbose?format_lb_vip_detailed:format_lb_vip, vip);
340  });
341 
342  unformat_free (&line_input);
343  return NULL;
344 }
345 
346 VLIB_CLI_COMMAND (lb_show_vips_command, static) =
347 {
348  .path = "show lb vips",
349  .short_help = "show lb vips [verbose]",
350  .function = lb_show_vips_command_fn,
351 };
352 
353 static clib_error_t *
355  unformat_input_t * input,
356  vlib_cli_command_t * cmd,
357  u8 is_nat6)
358 {
359  unformat_input_t _line_input, *line_input = &_line_input;
360  vnet_main_t * vnm = vnet_get_main();
361  clib_error_t * error = 0;
362  u32 _sw_if_index, *sw_if_index = &_sw_if_index;
363  u32 * inside_sw_if_indices = 0;
364  int is_del = 0;
365 
366  /* Get a line of input. */
367  if (!unformat_user (input, unformat_line_input, line_input))
368  return 0;
369 
370  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
371  {
372  if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
373  vnm, sw_if_index))
374  vec_add1 (inside_sw_if_indices, *sw_if_index);
375  else if (unformat (line_input, "del"))
376  is_del = 1;
377  else
378  {
379  error = clib_error_return (0, "unknown input '%U'",
380  format_unformat_error, line_input);
381  goto done;
382  }
383  }
384 
385  vec_foreach (sw_if_index, inside_sw_if_indices)
386  {
387  if (!is_nat6)
388  {
389  if (lb_nat4_interface_add_del (*sw_if_index, is_del))
390  {
391  error = clib_error_return(
392  0, "%s %U failed", is_del ? "del" : "add",
394  vnet_get_sw_interface (vnm, *sw_if_index));
395  goto done;
396  }
397  }
398  else
399  {
400  if (lb_nat6_interface_add_del (*sw_if_index, is_del))
401  {
402  error = clib_error_return(
403  0, "%s %U failed", is_del ? "del" : "add",
405  vnet_get_sw_interface (vnm, *sw_if_index));
406  goto done;
407  }
408  }
409  }
410 
411 done:
412  unformat_free (line_input);
413  vec_free (inside_sw_if_indices);
414 
415  return error;
416 }
417 
418 static clib_error_t *
420  unformat_input_t * input,
421  vlib_cli_command_t * cmd)
422 {
423  return lb_set_interface_nat_command_fn(vm, input, cmd, 0);
424 }
425 
426 VLIB_CLI_COMMAND (lb_set_interface_nat4_command, static) = {
427  .path = "lb set interface nat4",
429  .short_help = "lb set interface nat4 in <intfc> [del]",
430 };
431 
432 static clib_error_t *
434  unformat_input_t * input,
435  vlib_cli_command_t * cmd)
436 {
437  return lb_set_interface_nat_command_fn(vm, input, cmd, 1);
438 }
439 
440 VLIB_CLI_COMMAND (lb_set_interface_nat6_command, static) = {
441  .path = "lb set interface nat6",
443  .short_help = "lb set interface nat6 in <intfc> [del]",
444 };
445 
446 static clib_error_t *
448  unformat_input_t * input, vlib_cli_command_t * cmd)
449 {
450  u32 thread_index;
452  lb_main_t *lbm = &lb_main;
453 
454  for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) {
455  lb_hash_t *h = lbm->per_cpu[thread_index].sticky_ht;
456  if (h != NULL) {
457  u32 i;
458  lb_hash_bucket_t *b;
459 
460  lb_hash_foreach_entry(h, b, i) {
461  vlib_refcount_add(&lbm->as_refcount, thread_index, b->value[i], -1);
462  vlib_refcount_add(&lbm->as_refcount, thread_index, 0, 1);
463  }
464 
465  lb_hash_free(h);
466  lbm->per_cpu[thread_index].sticky_ht = 0;
467  }
468  }
469 
470  return NULL;
471 }
472 
473 /*
474  * flush all lb flowtables
475  * This is indented for debug and unit-tests purposes only
476  */
477 VLIB_CLI_COMMAND (lb_flowtable_flush_command, static) =
478 {
479  .path = "test lb flowtable flush",
480  .short_help = "test lb flowtable flush",
481  .function = lb_flowtable_flush_command_fn,
482 };
static clib_error_t * lb_flowtable_flush_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:447
int lb_nat4_interface_add_del(u32 sw_if_index, int is_del)
Definition: lb.c:1045
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static clib_error_t * lb_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:308
u32 per_cpu_sticky_buckets
Number of buckets in the per-cpu sticky hash table.
Definition: lb.h:465
#define NULL
Definition: clib.h:55
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:464
int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:527
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
int i
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
unformat_function_t unformat_vnet_sw_interface
static clib_error_t * lb_conf_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:250
lb_hash_t * sticky_ht
Each CPU has its own sticky flow hash table.
Definition: lb.h:415
unsigned char u8
Definition: types.h:56
static clib_error_t * lb_show_vips_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:324
static clib_error_t * lb_set_interface_nat4_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:419
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:443
unformat_function_t unformat_ip4_address
Definition: format.h:76
lb_main_t lb_main
Definition: lb.c:28
u32 flow_timeout
Flow timeout in seconds.
Definition: lb.h:470
Definition: lb.h:418
vlib_refcount_t as_refcount
Each AS has an associated reference counter.
Definition: lb.h:437
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
lb_vip_t * vips
Pool of all Virtual IPs.
Definition: lb.h:422
ip4_address_t ip4_src_address
Source address used for IPv4 encapsulated traffic.
Definition: lb.h:460
unformat_function_t unformat_line_input
Definition: format.h:282
format_function_t format_vnet_sw_interface_name
u32 value[LBHASH_ENTRY_PER_BUCKET]
Definition: lbhash.h:55
int lb_vip_del(u32 vip_index)
Definition: lb.c:936
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
format_function_t format_lb_main
Definition: lb.h:554
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
u32 new_length
Definition: lb.h:515
unformat_function_t unformat_ip6_address
Definition: format.h:97
#define ip46_prefix_is_ip4(ip46, len)
Definition: util.h:27
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
#define clib_warning(format, args...)
Definition: error.h:59
int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:755
static_always_inline void lb_hash_free(lb_hash_t *h)
Definition: lbhash.h:99
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index)
Definition: lb.c:500
static clib_error_t * lb_set_interface_nat_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd, u8 is_nat6)
Definition: cli.c:354
ip46_address_t prefix
Definition: lb.h:512
lb_vip_encap_args_t encap_args
Definition: lb.h:516
unformat_function_t unformat_ip46_address
Definition: format.h:71
lb_per_cpu_t * per_cpu
Some global data is per-cpu.
Definition: lb.h:445
u16 target_port
Definition: lb.h:221
int lb_nat6_interface_add_del(u32 sw_if_index, int is_del)
Definition: lb.c:1061
int lb_vip_add(lb_vip_add_args_t args, u32 *vip_index)
Definition: lb.c:823
ip6_address_t ip6_src_address
Source address used in IPv6 encapsulated traffic.
Definition: lb.h:455
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
uword unformat_ip46_prefix(unformat_input_t *input, va_list *args)
Definition: util.c:32
static clib_error_t * lb_as_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:176
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
static clib_error_t * lb_vip_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:20
void lb_garbage_collection()
Definition: lb.c:335
static clib_error_t * lb_set_interface_nat6_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:433
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define vec_foreach(var, vec)
Vector iterator.
lb_vip_type_t type
Definition: lb.h:514
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:681
Load balancing service is provided per VIP.
Definition: lb.h:240
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170