1edabb51f86306bb6abcd6650394f28891fba960
[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
343   print (vam->ofp, "%24U%14d%14d%18d",
344        format_ip46_address, &mp->vip.pfx.address, IP46_TYPE_ANY,
345        mp->vip.pfx.len,
346        mp->vip.protocol,
347        ntohs (mp->vip.port));
348 /*
349   lb_main_t *lbm = &lb_main;
350   u32 i = 0;
351
352   u32 vip_count = pool_len(lbm->vips);
353
354   print (vam->ofp, "%11d", vip_count);
355
356   for (i=0; i<vip_count; i--)
357     {
358       print (vam->ofp, "%24U%14d%14d%18d",
359            format_ip46_address, &mp->vip.pfx.address, IP46_TYPE_ANY,
360            mp->vip.pfx.len,
361            mp->vip.protocol,
362            ntohs (mp->vip.port));
363     }
364 */
365 }
366
367 static int api_lb_vip_dump (vat_main_t * vam)
368 {
369   vl_api_lb_vip_dump_t *mp;
370   int ret;
371
372   M(LB_VIP_DUMP, mp);
373
374   S(mp);
375   W (ret);
376   return ret;
377 }
378
379 static void vl_api_lb_as_details_t_handler
380   (vl_api_lb_as_details_t * mp)
381 {
382   vat_main_t *vam = &vat_main;
383
384   print (vam->ofp, "%24U%14d%14d%18d%d%d",
385        format_ip46_address, &mp->vip.pfx.address, IP46_TYPE_ANY,
386        mp->vip.pfx.len,
387        mp->vip.protocol,
388        ntohs (mp->vip.port),
389        mp->flags,
390        mp->in_use_since);
391
392   //u32 i = 0;
393
394 /*
395   lb_main_t *lbm = &lb_main;
396   print (vam->ofp, "%11d", pool_len(lbm->ass));
397   for (i=0; i<pool_len(lbm->ass); i--)
398     {
399       print (vam->ofp, "%24U%14d%14d%18d",
400            format_ip46_address, &mp->pfx.address, IP46_TYPE_ANY,
401            mp->pfx.len,
402            mp->pfx.protocol,
403            ntohs (mp->pfx.port),
404            ntohl(mp->app_srv),
405            mp->flags,
406            mp->in_use_;
407     }
408     */
409 }
410
411 static int api_lb_as_dump (vat_main_t * vam)
412 {
413
414   unformat_input_t *line_input = vam->input;
415   vl_api_lb_as_dump_t *mp;
416   int ret;
417   ip46_address_t vip_prefix, as_addr;
418   u8 vip_plen;
419   ip46_address_t *as_array = 0;
420   u32 port = 0;
421   u8 protocol = 0;
422
423   if (!unformat(line_input, "%U", unformat_ip46_prefix,
424                 &vip_prefix, &vip_plen, IP46_TYPE_ANY))
425   {
426       errmsg ("lb_add_del_as: invalid vip prefix\n");
427       return -99;
428   }
429
430   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
431   {
432     if (unformat(line_input, "%U", unformat_ip46_address,
433                  &as_addr, IP46_TYPE_ANY))
434       {
435         vec_add1(as_array, as_addr);
436       }
437     else if (unformat(line_input, "protocol tcp"))
438       {
439           protocol = IP_PROTOCOL_TCP;
440       }
441     else if (unformat(line_input, "protocol udp"))
442       {
443           protocol = IP_PROTOCOL_UDP;
444       }
445     else if (unformat(line_input, "port %d", &port))
446       ;
447     else {
448         errmsg ("invalid arguments\n");
449         return -99;
450     }
451   }
452
453   if (!vec_len(as_array)) {
454     errmsg ("No AS address provided \n");
455     return -99;
456   }
457
458   M(LB_AS_DUMP, mp);
459   clib_memcpy (mp->pfx.address.un.ip6, &vip_prefix.ip6, sizeof (vip_prefix.ip6));
460   mp->pfx.len = vip_plen;
461   mp->protocol = (u8)protocol;
462   mp->port = htons((u16)port);
463
464   S(mp);
465   W (ret);
466   return ret;
467 }
468
469 /*
470  * List of messages that the api test plugin sends,
471  * and that the data plane plugin processes
472  */
473 #define foreach_vpe_api_msg                             \
474 _(lb_conf, "[ip4-src-address <addr>] [ip6-src-address <addr>] " \
475            "[buckets <n>] [timeout <s>]")  \
476 _(lb_add_del_vip, "<prefix> "  \
477                   "[protocol (tcp|udp) port <n>] "  \
478                   "[encap (gre6|gre4|l3dsr|nat4|nat6)] " \
479                   "[dscp <n>] "  \
480                   "[type (nodeport|clusterip) target_port <n>] " \
481                   "[new_len <n>] [del]")  \
482 _(lb_add_del_as, "<vip-prefix> [protocol (tcp|udp) port <n>] "  \
483                  "[<address>] [del] [flush]")              \
484 _(lb_vip_dump, "")          \
485 _(lb_as_dump, "<vip-prefix> [protocol (tcp|udp) port <n>]")
486
487 static void
488 lb_api_hookup (vat_main_t *vam)
489 {
490   lb_test_main_t * lbtm = &lb_test_main;
491   /* Hook up handlers for replies from the data plane plug-in */
492 #define _(N,n)                                                  \
493   vl_msg_api_set_handlers((VL_API_##N + lbtm->msg_id_base),       \
494                           #n,                                   \
495                           vl_api_##n##_t_handler,               \
496                           vl_noop_handler,                      \
497                           vl_api_##n##_t_endian,                \
498                           vl_api_##n##_t_print,                 \
499                           sizeof(vl_api_##n##_t), 1);
500   foreach_vpe_api_reply_msg;
501 #undef _
502
503   /* API messages we can send */
504 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
505   foreach_vpe_api_msg;
506 #undef _
507
508   /* Help strings */
509 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
510   foreach_vpe_api_msg;
511 #undef _
512 }
513
514 VAT_PLUGIN_REGISTER(lb);