lb: vip and as dump/detail api's
[vpp.git] / src / plugins / lb / lb_test.c
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 <vat/vat.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19
20 #include <vppinfra/error.h>
21 #include <lb/lb.h>
22
23 #define __plugin_msg_base lb_test_main.msg_id_base
24 #include <vlibapi/vat_helper_macros.h>
25
26 //TODO: Move that to vat/plugin_api.c
27 //////////////////////////
28 uword unformat_ip46_address (unformat_input_t * input, va_list * args)
29 {
30   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
31   ip46_type_t type = va_arg (*args, ip46_type_t);
32   if ((type != IP46_TYPE_IP6) &&
33       unformat(input, "%U", unformat_ip4_address, &ip46->ip4)) {
34     ip46_address_mask_ip4(ip46);
35     return 1;
36   } else if ((type != IP46_TYPE_IP4) &&
37       unformat(input, "%U", unformat_ip6_address, &ip46->ip6)) {
38     return 1;
39   }
40   return 0;
41 }
42 uword unformat_ip46_prefix (unformat_input_t * input, va_list * args)
43 {
44   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
45   u8 *len = va_arg (*args, u8 *);
46   ip46_type_t type = va_arg (*args, ip46_type_t);
47
48   u32 l;
49   if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) {
50     if (l > 32)
51       return 0;
52     *len = l + 96;
53     ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0;
54   } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) {
55     if (l > 128)
56       return 0;
57     *len = l;
58   } else {
59     return 0;
60   }
61   return 1;
62 }
63 /////////////////////////
64
65 #define vl_msg_id(n,h) n,
66 typedef enum {
67 #include <lb/lb.api.h>
68     /* We'll want to know how many messages IDs we need... */
69     VL_MSG_FIRST_AVAILABLE,
70 } vl_msg_id_t;
71 #undef vl_msg_id
72
73 /* define message structures */
74 #define vl_typedefs
75 #include <lb/lb.api.h>
76 #undef vl_typedefs
77
78 /* declare message handlers for each api */
79
80 #define vl_endianfun             /* define message structures */
81 #include <lb/lb.api.h>
82 #undef vl_endianfun
83
84 /* instantiate all the print functions we know about */
85 #define vl_print(handle, ...)
86 #define vl_printfun
87 #include <lb/lb.api.h>
88 #undef vl_printfun
89
90 /* Get the API version number. */
91 #define vl_api_version(n,v) static u32 api_version=(v);
92 #include <lb/lb.api.h>
93 #undef vl_api_version
94
95 typedef struct {
96     /* API message ID base */
97     u16 msg_id_base;
98     vat_main_t *vat_main;
99 } lb_test_main_t;
100
101 lb_test_main_t lb_test_main;
102
103 #define foreach_standard_reply_retval_handler   \
104 _(lb_conf_reply)                 \
105 _(lb_add_del_vip_reply)          \
106 _(lb_add_del_as_reply)
107
108 #define _(n)                                            \
109     static void vl_api_##n##_t_handler                  \
110     (vl_api_##n##_t * mp)                               \
111     {                                                   \
112         vat_main_t * vam = lb_test_main.vat_main;   \
113         i32 retval = ntohl(mp->retval);                 \
114         if (vam->async_mode) {                          \
115             vam->async_errors += (retval < 0);          \
116         } else {                                        \
117             vam->retval = retval;                       \
118             vam->result_ready = 1;                      \
119         }                                               \
120     }
121 foreach_standard_reply_retval_handler;
122 #undef _
123
124 /*
125  * Table of message reply handlers, must include boilerplate handlers
126  * we just generated
127  */
128 #define foreach_vpe_api_reply_msg                               \
129   _(LB_CONF_REPLY, lb_conf_reply)                               \
130   _(LB_ADD_DEL_VIP_REPLY, lb_add_del_vip_reply)                 \
131   _(LB_ADD_DEL_AS_REPLY, lb_add_del_as_reply)                   \
132   _(LB_VIP_DETAILS, lb_vip_details)                             \
133   _(LB_AS_DETAILS, lb_as_details)
134
135 static int api_lb_conf (vat_main_t * vam)
136 {
137   unformat_input_t *line_input = vam->input;
138   vl_api_lb_conf_t *mp;
139   u32 ip4_src_address = 0xffffffff;
140   ip46_address_t ip6_src_address;
141   u32 sticky_buckets_per_core = LB_DEFAULT_PER_CPU_STICKY_BUCKETS;
142   u32 flow_timeout = LB_DEFAULT_FLOW_TIMEOUT;
143   int ret;
144
145   ip6_src_address.as_u64[0] = 0xffffffffffffffffL;
146   ip6_src_address.as_u64[1] = 0xffffffffffffffffL;
147
148   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
149   {
150     if (unformat(line_input, "ip4-src-address %U", unformat_ip4_address, &ip4_src_address))
151       ;
152     else if (unformat(line_input, "ip6-src-address %U", unformat_ip6_address, &ip6_src_address))
153       ;
154     else if (unformat(line_input, "buckets %d", &sticky_buckets_per_core))
155       ;
156     else if (unformat(line_input, "timeout %d", &flow_timeout))
157       ;
158     else {
159         errmsg ("invalid arguments\n");
160         return -99;
161     }
162   }
163
164   M(LB_CONF, mp);
165   clib_memcpy (&(mp->ip4_src_address), &ip4_src_address, sizeof (ip4_src_address));
166   clib_memcpy (&(mp->ip6_src_address), &ip6_src_address, sizeof (ip6_src_address));
167   mp->sticky_buckets_per_core = htonl (sticky_buckets_per_core);
168   mp->flow_timeout = htonl (flow_timeout);
169
170   S(mp);
171   W (ret);
172   return ret;
173 }
174
175 static int api_lb_add_del_vip (vat_main_t * vam)
176 {
177   unformat_input_t *line_input = vam->input;
178   vl_api_lb_add_del_vip_t *mp;
179   int ret;
180   ip46_address_t ip_prefix;
181   u8 prefix_length = 0;
182   u8 protocol = 0;
183   u32 port = 0;
184   u32 encap = 0;
185   u32 dscp = ~0;
186   u32 srv_type = LB_SRV_TYPE_CLUSTERIP;
187   u32 target_port = 0;
188   u32 new_length = 1024;
189   int is_del = 0;
190
191   if (!unformat(line_input, "%U", unformat_ip46_prefix, &ip_prefix,
192                 &prefix_length, IP46_TYPE_ANY, &prefix_length)) {
193     errmsg ("lb_add_del_vip: invalid vip prefix\n");
194     return -99;
195   }
196
197   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
198   {
199     if (unformat(line_input, "new_len %d", &new_length))
200       ;
201     else if (unformat(line_input, "del"))
202       is_del = 1;
203     else if (unformat(line_input, "protocol tcp"))
204       {
205         protocol = IP_PROTOCOL_TCP;
206       }
207     else if (unformat(line_input, "protocol udp"))
208       {
209         protocol = IP_PROTOCOL_UDP;
210       }
211     else if (unformat(line_input, "port %d", &port))
212       ;
213     else if (unformat(line_input, "encap gre4"))
214       encap = LB_ENCAP_TYPE_GRE4;
215     else if (unformat(line_input, "encap gre6"))
216       encap = LB_ENCAP_TYPE_GRE6;
217     else if (unformat(line_input, "encap l3dsr"))
218       encap = LB_ENCAP_TYPE_L3DSR;
219     else if (unformat(line_input, "encap nat4"))
220       encap = LB_ENCAP_TYPE_NAT4;
221     else if (unformat(line_input, "encap nat6"))
222       encap = LB_ENCAP_TYPE_NAT6;
223     else if (unformat(line_input, "dscp %d", &dscp))
224       ;
225     else if (unformat(line_input, "type clusterip"))
226       srv_type = LB_SRV_TYPE_CLUSTERIP;
227     else if (unformat(line_input, "type nodeport"))
228       srv_type = LB_SRV_TYPE_NODEPORT;
229     else if (unformat(line_input, "target_port %d", &target_port))
230       ;
231     else {
232         errmsg ("invalid arguments\n");
233         return -99;
234     }
235   }
236
237   if ((encap != LB_ENCAP_TYPE_L3DSR) && (dscp != ~0))
238     {
239       errmsg("lb_vip_add error: should not configure dscp for none L3DSR.");
240       return -99;
241     }
242
243   if ((encap == LB_ENCAP_TYPE_L3DSR) && (dscp >= 64))
244     {
245       errmsg("lb_vip_add error: dscp for L3DSR should be less than 64.");
246       return -99;
247     }
248
249   M(LB_ADD_DEL_VIP, mp);
250   clib_memcpy (mp->pfx.address.un.ip6, &ip_prefix.ip6, sizeof (ip_prefix.ip6));
251   mp->pfx.len = prefix_length;
252   mp->protocol = (u8)protocol;
253   mp->port = htons((u16)port);
254   mp->encap = (u8)encap;
255   mp->dscp = (u8)dscp;
256   mp->type = (u8)srv_type;
257   mp->target_port = htons((u16)target_port);
258   mp->node_port = htons((u16)target_port);
259   mp->new_flows_table_length = htonl(new_length);
260   mp->is_del = is_del;
261
262   S(mp);
263   W (ret);
264   return ret;
265 }
266
267 static int api_lb_add_del_as (vat_main_t * vam)
268 {
269
270   unformat_input_t *line_input = vam->input;
271   vl_api_lb_add_del_as_t *mp;
272   int ret;
273   ip46_address_t vip_prefix, as_addr;
274   u8 vip_plen;
275   ip46_address_t *as_array = 0;
276   u32 port = 0;
277   u8 protocol = 0;
278   u8 is_del = 0;
279   u8 is_flush = 0;
280
281   if (!unformat(line_input, "%U", unformat_ip46_prefix,
282                 &vip_prefix, &vip_plen, IP46_TYPE_ANY))
283   {
284       errmsg ("lb_add_del_as: invalid vip prefix\n");
285       return -99;
286   }
287
288   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
289   {
290     if (unformat(line_input, "%U", unformat_ip46_address,
291                  &as_addr, IP46_TYPE_ANY))
292       {
293         vec_add1(as_array, as_addr);
294       }
295     else if (unformat(line_input, "del"))
296       {
297         is_del = 1;
298       }
299     else if (unformat(line_input, "flush"))
300       {
301         is_flush = 1;
302       }
303     else if (unformat(line_input, "protocol tcp"))
304       {
305           protocol = IP_PROTOCOL_TCP;
306       }
307     else if (unformat(line_input, "protocol udp"))
308       {
309           protocol = IP_PROTOCOL_UDP;
310       }
311     else if (unformat(line_input, "port %d", &port))
312       ;
313     else {
314         errmsg ("invalid arguments\n");
315         return -99;
316     }
317   }
318
319   if (!vec_len(as_array)) {
320     errmsg ("No AS address provided \n");
321     return -99;
322   }
323
324   M(LB_ADD_DEL_AS, mp);
325   clib_memcpy (mp->pfx.address.un.ip6, &vip_prefix.ip6, sizeof (vip_prefix.ip6));
326   mp->pfx.len = vip_plen;
327   mp->protocol = (u8)protocol;
328   mp->port = htons((u16)port);
329   clib_memcpy (&mp->as_address, &as_addr, sizeof (as_addr));
330   mp->is_del = is_del;
331   mp->is_flush = is_flush;
332
333   S(mp);
334   W (ret);
335   return ret;
336 }
337
338 static void vl_api_lb_vip_details_t_handler
339   (vl_api_lb_vip_details_t * mp)
340 {
341   vat_main_t *vam = &vat_main;
342   lb_main_t *lbm = &lb_main;
343   u32 i = 0;
344
345   u32 vip_count = pool_len(lbm->vips);
346
347   print (vam->ofp, "%11d", vip_count);
348
349   for (i=0; i<vip_count; i--)
350     {
351       print (vam->ofp, "%24U%14d%14d%18d",
352            format_ip46_address, &mp->vip.pfx.address, IP46_TYPE_ANY,
353            mp->vip.pfx.len,
354            mp->vip.protocol,
355            ntohs (mp->vip.port));
356     }
357 }
358
359 static int api_lb_vip_dump (vat_main_t * vam)
360 {
361   vl_api_lb_vip_dump_t *mp;
362   int ret;
363
364   M(LB_VIP_DUMP, mp);
365
366   S(mp);
367   W (ret);
368   return ret;
369 }
370
371 static void vl_api_lb_as_details_t_handler
372   (vl_api_lb_as_details_t * mp)
373 {
374   vat_main_t *vam = &vat_main;
375   lb_main_t *lbm = &lb_main;
376
377   //u32 i = 0;
378
379   print (vam->ofp, "%11d", pool_len(lbm->ass));
380 /*
381   for (i=0; i<pool_len(lbm->ass); i--)
382     {
383       print (vam->ofp, "%24U%14d%14d%18d",
384            format_ip46_address, &mp->pfx.address, IP46_TYPE_ANY,
385            mp->pfx.len,
386            mp->pfx.protocol,
387            ntohs (mp->pfx.port),
388            ntohl(mp->app_srv),
389            mp->flags,
390            mp->in_use_;
391     }
392     */
393 }
394
395 static int api_lb_as_dump (vat_main_t * vam)
396 {
397
398   unformat_input_t *line_input = vam->input;
399   vl_api_lb_as_dump_t *mp;
400   int ret;
401   ip46_address_t vip_prefix, as_addr;
402   u8 vip_plen;
403   ip46_address_t *as_array = 0;
404   u32 port = 0;
405   u8 protocol = 0;
406
407   if (!unformat(line_input, "%U", unformat_ip46_prefix,
408                 &vip_prefix, &vip_plen, IP46_TYPE_ANY))
409   {
410       errmsg ("lb_add_del_as: invalid vip prefix\n");
411       return -99;
412   }
413
414   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
415   {
416     if (unformat(line_input, "%U", unformat_ip46_address,
417                  &as_addr, IP46_TYPE_ANY))
418       {
419         vec_add1(as_array, as_addr);
420       }
421     else if (unformat(line_input, "protocol tcp"))
422       {
423           protocol = IP_PROTOCOL_TCP;
424       }
425     else if (unformat(line_input, "protocol udp"))
426       {
427           protocol = IP_PROTOCOL_UDP;
428       }
429     else if (unformat(line_input, "port %d", &port))
430       ;
431     else {
432         errmsg ("invalid arguments\n");
433         return -99;
434     }
435   }
436
437   if (!vec_len(as_array)) {
438     errmsg ("No AS address provided \n");
439     return -99;
440   }
441
442   M(LB_AS_DUMP, mp);
443   clib_memcpy (mp->pfx.address.un.ip6, &vip_prefix.ip6, sizeof (vip_prefix.ip6));
444   mp->pfx.len = vip_plen;
445   mp->protocol = (u8)protocol;
446   mp->port = htons((u16)port);
447
448   S(mp);
449   W (ret);
450   return ret;
451 }
452
453 /*
454  * List of messages that the api test plugin sends,
455  * and that the data plane plugin processes
456  */
457 #define foreach_vpe_api_msg                             \
458 _(lb_conf, "[ip4-src-address <addr>] [ip6-src-address <addr>] " \
459            "[buckets <n>] [timeout <s>]")  \
460 _(lb_add_del_vip, "<prefix> "  \
461                   "[protocol (tcp|udp) port <n>] "  \
462                   "[encap (gre6|gre4|l3dsr|nat4|nat6)] " \
463                   "[dscp <n>] "  \
464                   "[type (nodeport|clusterip) target_port <n>] " \
465                   "[new_len <n>] [del]")  \
466 _(lb_add_del_as, "<vip-prefix> [protocol (tcp|udp) port <n>] "  \
467                  "[<address>] [del] [flush]")              \
468 _(lb_vip_dump, "")          \
469 _(lb_as_dump, "<vip-prefix> [protocol (tcp|udp) port <n>]")
470
471 static void
472 lb_api_hookup (vat_main_t *vam)
473 {
474   lb_test_main_t * lbtm = &lb_test_main;
475   /* Hook up handlers for replies from the data plane plug-in */
476 #define _(N,n)                                                  \
477   vl_msg_api_set_handlers((VL_API_##N + lbtm->msg_id_base),       \
478                           #n,                                   \
479                           vl_api_##n##_t_handler,               \
480                           vl_noop_handler,                      \
481                           vl_api_##n##_t_endian,                \
482                           vl_api_##n##_t_print,                 \
483                           sizeof(vl_api_##n##_t), 1);
484   foreach_vpe_api_reply_msg;
485 #undef _
486
487   /* API messages we can send */
488 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
489   foreach_vpe_api_msg;
490 #undef _
491
492   /* Help strings */
493 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
494   foreach_vpe_api_msg;
495 #undef _
496 }
497
498 VAT_PLUGIN_REGISTER(lb);