Add buffer pointer-to-index and index-to-pointer array functions
[vpp.git] / src / plugins / kubeproxy / kp_cli.c
1 /*
2  * Copyright (c) 2016 Intel 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 "POD IS" BPODIS,
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 <kubeproxy/kp.h>
17
18
19 static clib_error_t *
20 kp_vip_command_fn (vlib_main_t * vm,
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   u32 port = 0;
28   u32 target_port = 0;
29   u32 node_port = 0;
30   u32 del = 0;
31   int ret;
32   u32 nat4 = 0;
33   kp_vip_type_t type;
34   clib_error_t *error = 0;
35
36   if (!unformat_user (input, unformat_line_input, line_input))
37     return 0;
38
39   if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY, &plen)) {
40     error = clib_error_return (0, "invalid vip prefix: '%U'",
41                                format_unformat_error, line_input);
42     goto done;
43   }
44
45   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
46   {
47     if (unformat(line_input, "new_len %d", &new_len))
48       ;
49     else if (unformat(line_input, "port %d", &port))
50       ;
51     else if (unformat(line_input, "target_port %d", &target_port))
52       ;
53     else if (unformat(line_input, "node_port %d", &node_port))
54       ;
55     else if (unformat(line_input, "del"))
56       del = 1;
57     else if (unformat(line_input, "nat4"))
58       nat4 = 1;
59     else if (unformat(line_input, "nat6"))
60       nat4 = 0;
61     else {
62       error = clib_error_return (0, "parse error: '%U'",
63                                 format_unformat_error, line_input);
64       goto done;
65     }
66   }
67
68
69   if (ip46_prefix_is_ip4(&prefix, plen)) {
70     type = (nat4)?KP_VIP_TYPE_IP4_NAT44:KP_VIP_TYPE_IP4_NAT46;
71   } else {
72     type = (nat4)?KP_VIP_TYPE_IP6_NAT64:KP_VIP_TYPE_IP6_NAT66;
73   }
74
75   kp_garbage_collection();
76
77   u32 index;
78   if (!del) {
79     if ((ret = kp_vip_add(&prefix, plen, type, new_len, &index,
80                           (u16)port, (u16)target_port, (u16)node_port))) {
81       error = clib_error_return (0, "kp_vip_add error %d", ret);
82       goto done;
83     } else {
84       vlib_cli_output(vm, "kp_vip_add ok %d", index);
85     }
86   } else {
87     if ((ret = kp_vip_find_index(&prefix, plen, &index))) {
88       error = clib_error_return (0, "kp_vip_find_index error %d", ret);
89       goto done;
90     } else if ((ret = kp_vip_del(index))) {
91       error = clib_error_return (0, "kp_vip_del error %d", ret);
92       goto done;
93     }
94   }
95
96 done:
97   unformat_free (line_input);
98
99   return error;
100 }
101
102 VLIB_CLI_COMMAND (kp_vip_command, static) =
103 {
104   .path = "kube-proxy vip",
105   .short_help = "kube-proxy vip <prefix> port <n> target_port <n>"
106                 " node_port <n> [nat4|nat6)] [new_len <n>] [del]",
107   .function = kp_vip_command_fn,
108 };
109
110 static clib_error_t *
111 kp_pod_command_fn (vlib_main_t * vm,
112               unformat_input_t * input, vlib_cli_command_t * cmd)
113 {
114   unformat_input_t _line_input, *line_input = &_line_input;
115   ip46_address_t vip_prefix, pod_addr;
116   u8 vip_plen;
117   ip46_address_t *pod_array = 0;
118   u32 vip_index;
119   u8 del = 0;
120   int ret;
121   clib_error_t *error = 0;
122
123   if (!unformat_user (input, unformat_line_input, line_input))
124     return 0;
125
126   if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) {
127     error = clib_error_return (0, "invalid pod address: '%U'",
128                                format_unformat_error, line_input);
129     goto done;
130   }
131
132   if ((ret = kp_vip_find_index(&vip_prefix, vip_plen, &vip_index))) {
133     error = clib_error_return (0, "kp_vip_find_index error %d", ret);
134     goto done;
135   }
136
137   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
138   {
139     if (unformat(line_input, "%U", unformat_ip46_address, &pod_addr, IP46_TYPE_ANY)) {
140       vec_add1(pod_array, pod_addr);
141     } else if (unformat(line_input, "del")) {
142       del = 1;
143     } else {
144       error = clib_error_return (0, "parse error: '%U'",
145                                  format_unformat_error, line_input);
146       goto done;
147     }
148   }
149
150   if (!vec_len(pod_array)) {
151     error = clib_error_return (0, "No POD address provided");
152     goto done;
153   }
154
155   kp_garbage_collection();
156   clib_warning("vip index is %d", vip_index);
157
158   if (del) {
159     if ((ret = kp_vip_del_pods(vip_index, pod_array, vec_len(pod_array)))) {
160       error = clib_error_return (0, "kp_vip_del_pods error %d", ret);
161       goto done;
162     }
163   } else {
164     if ((ret = kp_vip_add_pods(vip_index, pod_array, vec_len(pod_array)))) {
165       error = clib_error_return (0, "kp_vip_add_pods error %d", ret);
166       goto done;
167     }
168   }
169
170 done:
171   unformat_free (line_input);
172   vec_free(pod_array);
173
174   return error;
175 }
176
177 VLIB_CLI_COMMAND (kp_pod_command, static) =
178 {
179   .path = "kube-proxy pod",
180   .short_help =
181       "kube-proxy pod <vip-prefix> [<address> [<address> [...]]] [del]",
182   .function = kp_pod_command_fn,
183 };
184
185 static clib_error_t *
186 kp_conf_command_fn (vlib_main_t * vm,
187               unformat_input_t * input, vlib_cli_command_t * cmd)
188 {
189   kp_main_t *kpm = &kp_main;
190   unformat_input_t _line_input, *line_input = &_line_input;
191   u32 per_cpu_sticky_buckets = kpm->per_cpu_sticky_buckets;
192   u32 per_cpu_sticky_buckets_log2 = 0;
193   u32 flow_timeout = kpm->flow_timeout;
194   int ret;
195   clib_error_t *error = 0;
196
197   if (!unformat_user (input, unformat_line_input, line_input))
198     return 0;
199
200   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
201   {
202     if (unformat(line_input, "buckets %d", &per_cpu_sticky_buckets))
203       ;
204     else if (unformat(line_input, "buckets-log2 %d", &per_cpu_sticky_buckets_log2)) {
205       if (per_cpu_sticky_buckets_log2 >= 32)
206         return clib_error_return (0, "buckets-log2 value is too high");
207       per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2;
208     } else if (unformat(line_input, "timeout %d", &flow_timeout))
209       ;
210     else {
211       error = clib_error_return (0, "parse error: '%U'",
212                                  format_unformat_error, line_input);
213       goto done;
214     }
215   }
216
217   kp_garbage_collection();
218
219   if ((ret = kp_conf(per_cpu_sticky_buckets, flow_timeout))) {
220     error = clib_error_return (0, "kp_conf error %d", ret);
221     goto done;
222   }
223
224 done:
225   unformat_free (line_input);
226
227   return error;
228 }
229
230 VLIB_CLI_COMMAND (kp_conf_command, static) =
231 {
232   .path = "kube-proxy conf",
233   .short_help = "kube-proxy conf [buckets <n>] [timeout <s>]",
234   .function = kp_conf_command_fn,
235 };
236
237 static clib_error_t *
238 kp_show_command_fn (vlib_main_t * vm,
239               unformat_input_t * input, vlib_cli_command_t * cmd)
240 {
241   vlib_cli_output(vm, "%U", format_kp_main);
242   return NULL;
243 }
244
245
246 VLIB_CLI_COMMAND (kp_show_command, static) =
247 {
248   .path = "show kube-proxy",
249   .short_help = "show kube-proxy",
250   .function = kp_show_command_fn,
251 };
252
253 static clib_error_t *
254 kp_show_vips_command_fn (vlib_main_t * vm,
255               unformat_input_t * input, vlib_cli_command_t * cmd)
256 {
257   unformat_input_t line_input;
258   kp_main_t *kpm = &kp_main;
259   kp_vip_t *vip;
260   u8 verbose = 0;
261
262   if (!unformat_user (input, unformat_line_input, &line_input))
263       return 0;
264
265   if (unformat(&line_input, "verbose"))
266     verbose = 1;
267
268   pool_foreach(vip, kpm->vips, {
269       vlib_cli_output(vm, "%U\n", verbose?format_kp_vip_detailed:format_kp_vip, vip);
270   });
271
272   unformat_free (&line_input);
273   return NULL;
274 }
275
276 VLIB_CLI_COMMAND (kp_show_vips_command, static) =
277 {
278   .path = "show kube-proxy vips",
279   .short_help = "show kube-proxy vips [verbose]",
280   .function = kp_show_vips_command_fn,
281 };
282
283 static clib_error_t *
284 kp_set_interface_nat4_command_fn (vlib_main_t * vm,
285                                   unformat_input_t * input,
286                                   vlib_cli_command_t * cmd)
287 {
288   unformat_input_t _line_input, *line_input = &_line_input;
289   vnet_main_t * vnm = vnet_get_main();
290   clib_error_t * error = 0;
291   u32 sw_if_index;
292   u32 * inside_sw_if_indices = 0;
293   int is_del = 0;
294   int i;
295
296   sw_if_index = ~0;
297
298   /* Get a line of input. */
299   if (!unformat_user (input, unformat_line_input, line_input))
300     return 0;
301
302   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
303     {
304       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
305                     vnm, &sw_if_index))
306         vec_add1 (inside_sw_if_indices, sw_if_index);
307       else if (unformat (line_input, "del"))
308         is_del = 1;
309       else
310         {
311           error = clib_error_return (0, "unknown input '%U'",
312             format_unformat_error, line_input);
313           goto done;
314         }
315     }
316
317   if (vec_len (inside_sw_if_indices))
318     {
319       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
320         {
321           sw_if_index = inside_sw_if_indices[i];
322
323           if (kp_nat4_interface_add_del (sw_if_index, is_del))
324             {
325               error = clib_error_return (0, "%s %U failed",
326                                          is_del ? "del" : "add",
327                                          format_vnet_sw_interface_name, vnm,
328                                          vnet_get_sw_interface (vnm,
329                                                                 sw_if_index));
330               goto done;
331             }
332         }
333     }
334
335 done:
336   unformat_free (line_input);
337   vec_free (inside_sw_if_indices);
338
339   return error;
340 }
341
342 VLIB_CLI_COMMAND (kp_set_interface_nat4_command, static) = {
343   .path = "kube-proxy set interface nat4",
344   .function = kp_set_interface_nat4_command_fn,
345   .short_help = "kube-proxy set interface nat4 in <intfc> [del]",
346 };
347
348 static clib_error_t *
349 kp_flowtable_flush_command_fn(vlib_main_t * vm,
350     unformat_input_t * input, vlib_cli_command_t * cmd)
351 {
352   u32 thread_index;
353   vlib_thread_main_t *tm = vlib_get_thread_main();
354   kp_main_t *kpm = &kp_main;
355
356   for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) {
357     kp_hash_t *h = kpm->per_cpu[thread_index].sticky_ht;
358     if (h != NULL) {
359         kp_hash_bucket_t *b;
360         u32 i;
361         kp_hash_foreach_entry(h, b, i) {
362           vlib_refcount_add(&kpm->pod_refcount, thread_index, b->value[i], -1);
363           vlib_refcount_add(&kpm->pod_refcount, thread_index, 0, 1);
364         }
365
366         kp_hash_free(h);
367         kpm->per_cpu[thread_index].sticky_ht = NULL;
368     }
369   }
370
371   return NULL;
372 }
373
374 /*
375  * flush all kube-proxy flowtables
376  * This is indented for debug and unit-tests purposes only
377  */
378 VLIB_CLI_COMMAND (kp_flowtable_flush_command, static) = {
379   .path = "test kube-proxy flowtable flush",
380   .short_help = "test kube-proxy flowtable flush",
381   .function = kp_flowtable_flush_command_fn,
382 };