FD.io VPP  v18.04-17-g3a0d853
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  ip46_address_t prefix;
25  u8 plen;
26  u32 new_len = 1024;
27  u8 del = 0;
28  int ret;
29  u32 encap = 0;
30  u32 dscp = ~0;
31  lb_vip_type_t type = 0;
32  clib_error_t *error = 0;
33 
34  if (!unformat_user (input, unformat_line_input, line_input))
35  return 0;
36 
37  if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY)) {
38  error = clib_error_return (0, "invalid vip prefix: '%U'",
39  format_unformat_error, line_input);
40  goto done;
41  }
42 
43  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
44  {
45  if (unformat(line_input, "new_len %d", &new_len))
46  ;
47  else if (unformat(line_input, "del"))
48  del = 1;
49  else if (unformat(line_input, "encap gre4"))
50  encap = LB_ENCAP_TYPE_GRE4;
51  else if (unformat(line_input, "encap gre6"))
52  encap = LB_ENCAP_TYPE_GRE6;
53  else if (unformat(line_input, "encap l3dsr"))
54  encap = LB_ENCAP_TYPE_L3DSR;
55  else if (unformat(line_input, "dscp %d", &dscp))
56  ;
57  else {
58  error = clib_error_return (0, "parse error: '%U'",
59  format_unformat_error, line_input);
60  goto done;
61  }
62  }
63 
64  if ((encap != LB_ENCAP_TYPE_L3DSR) && (dscp != ~0) )
65  {
66  error = clib_error_return (0, "lb_vip_add error: "
67  "should not configure dscp for none L3DSR.");
68  goto done;
69  }
70 
71  if ((encap == LB_ENCAP_TYPE_L3DSR) && (dscp >= 64 ) )
72  {
73  error = clib_error_return (0, "lb_vip_add error: "
74  "dscp for L3DSR should be less than 64.");
75  goto done;
76  }
77 
78  if (ip46_prefix_is_ip4(&prefix, plen)) {
79  if (encap == LB_ENCAP_TYPE_GRE4)
80  type = LB_VIP_TYPE_IP4_GRE4;
81  else if (encap == LB_ENCAP_TYPE_GRE6)
82  type = LB_VIP_TYPE_IP4_GRE6;
83  else if (encap == LB_ENCAP_TYPE_L3DSR)
84  type = LB_VIP_TYPE_IP4_L3DSR;
85  } else {
86  if (encap == LB_ENCAP_TYPE_GRE4)
87  type = LB_VIP_TYPE_IP6_GRE4;
88  else if (encap == LB_ENCAP_TYPE_GRE6)
89  type = LB_VIP_TYPE_IP6_GRE6;
90  }
91 
93 
94  u32 index;
95  if (!del) {
96  if ((ret = lb_vip_add(&prefix, plen, type, (u8)(dscp & 0x3F), new_len, &index))) {
97  error = clib_error_return (0, "lb_vip_add error %d", ret);
98  goto done;
99  } else {
100  vlib_cli_output(vm, "lb_vip_add ok %d", index);
101  }
102  } else {
103  if ((ret = lb_vip_find_index(&prefix, plen, &index))) {
104  error = clib_error_return (0, "lb_vip_find_index error %d", ret);
105  goto done;
106  } else if ((ret = lb_vip_del(index))) {
107  error = clib_error_return (0, "lb_vip_del error %d", ret);
108  goto done;
109  }
110  }
111 
112 done:
113  unformat_free (line_input);
114 
115  return error;
116 }
117 
118 VLIB_CLI_COMMAND (lb_vip_command, static) =
119 {
120  .path = "lb vip",
121  .short_help = "lb vip <prefix> [encap (gre6|gre4|l3dsr)] [dscp <n>] [new_len <n>] [del]",
122  .function = lb_vip_command_fn,
123 };
124 
125 static clib_error_t *
127  unformat_input_t * input, vlib_cli_command_t * cmd)
128 {
129  unformat_input_t _line_input, *line_input = &_line_input;
130  ip46_address_t vip_prefix, as_addr;
131  u8 vip_plen;
132  ip46_address_t *as_array = 0;
133  u32 vip_index;
134  u8 del = 0;
135  int ret;
136  clib_error_t *error = 0;
137 
138  if (!unformat_user (input, unformat_line_input, line_input))
139  return 0;
140 
141  if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) {
142  error = clib_error_return (0, "invalid as address: '%U'",
143  format_unformat_error, line_input);
144  goto done;
145  }
146 
147  if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) {
148  error = clib_error_return (0, "lb_vip_find_index error %d", ret);
149  goto done;
150  }
151 
152  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
153  {
154  if (unformat(line_input, "%U", unformat_ip46_address, &as_addr, IP46_TYPE_ANY)) {
155  vec_add1(as_array, as_addr);
156  } else if (unformat(line_input, "del")) {
157  del = 1;
158  } else {
159  error = clib_error_return (0, "parse error: '%U'",
160  format_unformat_error, line_input);
161  goto done;
162  }
163  }
164 
165  if (!vec_len(as_array)) {
166  error = clib_error_return (0, "No AS address provided");
167  goto done;
168  }
169 
171  clib_warning("vip index is %d", vip_index);
172 
173  if (del) {
174  if ((ret = lb_vip_del_ass(vip_index, as_array, vec_len(as_array)))) {
175  error = clib_error_return (0, "lb_vip_del_ass error %d", ret);
176  goto done;
177  }
178  } else {
179  if ((ret = lb_vip_add_ass(vip_index, as_array, vec_len(as_array)))) {
180  error = clib_error_return (0, "lb_vip_add_ass error %d", ret);
181  goto done;
182  }
183  }
184 
185 done:
186  unformat_free (line_input);
187  vec_free(as_array);
188 
189  return error;
190 }
191 
192 VLIB_CLI_COMMAND (lb_as_command, static) =
193 {
194  .path = "lb as",
195  .short_help = "lb as <vip-prefix> [<address> [<address> [...]]] [del]",
196  .function = lb_as_command_fn,
197 };
198 
199 static clib_error_t *
201  unformat_input_t * input, vlib_cli_command_t * cmd)
202 {
203  lb_main_t *lbm = &lb_main;
204  unformat_input_t _line_input, *line_input = &_line_input;
205  ip4_address_t ip4 = lbm->ip4_src_address;
206  ip6_address_t ip6 = lbm->ip6_src_address;
207  u32 per_cpu_sticky_buckets = lbm->per_cpu_sticky_buckets;
208  u32 per_cpu_sticky_buckets_log2 = 0;
209  u32 flow_timeout = lbm->flow_timeout;
210  int ret;
211  clib_error_t *error = 0;
212 
213  if (!unformat_user (input, unformat_line_input, line_input))
214  return 0;
215 
216  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
217  {
218  if (unformat(line_input, "ip4-src-address %U", unformat_ip4_address, &ip4))
219  ;
220  else if (unformat(line_input, "ip6-src-address %U", unformat_ip6_address, &ip6))
221  ;
222  else if (unformat(line_input, "buckets %d", &per_cpu_sticky_buckets))
223  ;
224  else if (unformat(line_input, "buckets-log2 %d", &per_cpu_sticky_buckets_log2)) {
225  if (per_cpu_sticky_buckets_log2 >= 32)
226  return clib_error_return (0, "buckets-log2 value is too high");
227  per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2;
228  } else if (unformat(line_input, "timeout %d", &flow_timeout))
229  ;
230  else {
231  error = clib_error_return (0, "parse error: '%U'",
232  format_unformat_error, line_input);
233  goto done;
234  }
235  }
236 
238 
239  if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) {
240  error = clib_error_return (0, "lb_conf error %d", ret);
241  goto done;
242  }
243 
244 done:
245  unformat_free (line_input);
246 
247  return error;
248 }
249 
250 VLIB_CLI_COMMAND (lb_conf_command, static) =
251 {
252  .path = "lb conf",
253  .short_help = "lb conf [ip4-src-address <addr>] [ip6-src-address <addr>] [buckets <n>] [timeout <s>]",
254  .function = lb_conf_command_fn,
255 };
256 
257 static clib_error_t *
259  unformat_input_t * input, vlib_cli_command_t * cmd)
260 {
261  vlib_cli_output(vm, "%U", format_lb_main);
262  return NULL;
263 }
264 
265 
266 VLIB_CLI_COMMAND (lb_show_command, static) =
267 {
268  .path = "show lb",
269  .short_help = "show lb",
270  .function = lb_show_command_fn,
271 };
272 
273 static clib_error_t *
275  unformat_input_t * input, vlib_cli_command_t * cmd)
276 {
277  unformat_input_t line_input;
278  lb_main_t *lbm = &lb_main;
279  lb_vip_t *vip;
280  u8 verbose = 0;
281 
282  if (!unformat_user (input, unformat_line_input, &line_input))
283  return 0;
284 
285  if (unformat(&line_input, "verbose"))
286  verbose = 1;
287 
288  pool_foreach(vip, lbm->vips, {
289  vlib_cli_output(vm, "%U\n", verbose?format_lb_vip_detailed:format_lb_vip, vip);
290  });
291 
292  unformat_free (&line_input);
293  return NULL;
294 }
295 
296 VLIB_CLI_COMMAND (lb_show_vips_command, static) =
297 {
298  .path = "show lb vips",
299  .short_help = "show lb vips [verbose]",
300  .function = lb_show_vips_command_fn,
301 };
302 
303 static clib_error_t *
305  unformat_input_t * input, vlib_cli_command_t * cmd)
306 {
307  u32 thread_index;
309  lb_main_t *lbm = &lb_main;
310 
311  for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) {
312  lb_hash_t *h = lbm->per_cpu[thread_index].sticky_ht;
313  if (h != NULL) {
314  u32 i;
315  lb_hash_bucket_t *b;
316 
317  lb_hash_foreach_entry(h, b, i) {
318  vlib_refcount_add(&lbm->as_refcount, thread_index, b->value[i], -1);
319  vlib_refcount_add(&lbm->as_refcount, thread_index, 0, 1);
320  }
321 
322  lb_hash_free(h);
323  lbm->per_cpu[thread_index].sticky_ht = 0;
324  }
325  }
326 
327  return NULL;
328 }
329 
330 /*
331  * flush all lb flowtables
332  * This is indented for debug and unit-tests purposes only
333  */
334 VLIB_CLI_COMMAND (lb_flowtable_flush_command, static) =
335 {
336  .path = "test lb flowtable flush",
337  .short_help = "test lb flowtable flush",
338  .function = lb_flowtable_flush_command_fn,
339 };
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:304
static clib_error_t * lb_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:258
u32 per_cpu_sticky_buckets
Number of buckets in the per-cpu sticky hash table.
Definition: lb.h:299
#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:378
int lb_vip_add_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
Definition: lb.c:441
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:520
int i
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
static clib_error_t * lb_conf_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:200
lb_hash_t * sticky_ht
Each CPU has its own sticky flow hash table.
Definition: lb.h:252
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:274
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:440
unformat_function_t unformat_ip4_address
Definition: format.h:76
lb_main_t lb_main
Definition: lb.c:27
u32 flow_timeout
Flow timeout in seconds.
Definition: lb.h:304
Definition: lb.h:255
vlib_refcount_t as_refcount
Each AS has an associated reference counter.
Definition: lb.h:274
#define clib_error_return(e, args...)
Definition: error.h:99
lb_vip_t * vips
Pool of all Virtual IPs.
Definition: lb.h:259
ip4_address_t ip4_src_address
Source address used for IPv4 encapsulated traffic.
Definition: lb.h:294
unformat_function_t unformat_line_input
Definition: format.h:281
u32 value[LBHASH_ENTRY_PER_BUCKET]
Definition: lbhash.h:55
int lb_vip_del(u32 vip_index)
Definition: lb.c:733
struct _unformat_input_t unformat_input_t
format_function_t format_lb_main
Definition: lb.h:359
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
unformat_function_t unformat_ip6_address
Definition: format.h:94
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#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:598
int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u8 dscp, u32 new_length, u32 *vip_index)
Definition: lb.c:662
static_always_inline void lb_hash_free(lb_hash_t *h)
Definition: lbhash.h:99
uword unformat_ip46_prefix(unformat_input_t *input, va_list *args)
Definition: kp.c:49
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
unsigned int u32
Definition: types.h:88
lb_vip_type_t
The load balancer supports IPv4 and IPv6 traffic and GRE4, GRE6 and L3DSR encap.
Definition: lb.h:143
int lb_vip_find_index(ip46_address_t *prefix, u8 plen, u32 *vip_index)
Definition: lb.c:414
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:279
ip6_address_t ip6_src_address
Source address used in IPv6 encapsulated traffic.
Definition: lb.h:289
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static clib_error_t * lb_as_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:126
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
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:249
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 ip46_prefix_is_ip4(ip46, len)
Definition: kp.h:432
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
Load balancing service is provided per VIP.
Definition: lb.h:164
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:169