misc: api move continued
[vpp.git] / src / plugins / vrrp / vrrp_test.c
1 /*
2  * vrrp.c - VRRP vpp-api-test plug-in
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9 #include <vat/vat.h>
10 #include <vlibapi/api.h>
11 #include <vlibmemory/api.h>
12 #include <vppinfra/error.h>
13
14 #include <vnet/ip/ip.h>
15
16 uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
17
18 /* Declare message IDs */
19 #include <vnet/format_fns.h>
20 #include <vrrp/vrrp.api_enum.h>
21 #include <vrrp/vrrp.api_types.h>
22 #include <vlibmemory/vlib.api_types.h>
23
24 typedef struct
25 {
26   /* API message ID base */
27   u16 msg_id_base;
28   u32 ping_id;
29   vat_main_t *vat_main;
30 } vrrp_test_main_t;
31
32 vrrp_test_main_t vrrp_test_main;
33
34 #define __plugin_msg_base vrrp_test_main.msg_id_base
35 #include <vlibapi/vat_helper_macros.h>
36
37 static int
38 api_vrrp_vr_add_del (vat_main_t * vam)
39 {
40   unformat_input_t *i = vam->input;
41   u32 sw_if_index = ~0;
42   u32 vr_id, priority, interval;
43   u8 is_ipv6, no_preempt, accept_mode, vr_unicast, is_add, is_del;
44   u8 n_addrs4, n_addrs6;
45   vl_api_vrrp_vr_add_del_t *mp;
46   vl_api_address_t *api_addr;
47   ip46_address_t *ip_addr, *ip_addrs = 0;
48   ip46_address_t addr;
49   int ret = 0;
50
51   interval = priority = 100;
52   n_addrs4 = n_addrs6 = 0;
53   vr_id = is_ipv6 = no_preempt = accept_mode = vr_unicast = 0;
54   is_add = is_del = 0;
55
56   clib_memset (&addr, 0, sizeof (addr));
57
58   /* Parse args required to build the message */
59   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
60     {
61       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
62         ;
63       else if (unformat (i, "sw_if_index %u", &sw_if_index))
64         ;
65       else if (unformat (i, "vr_id %u", &vr_id))
66         ;
67       else if (unformat (i, "ipv6"))
68         is_ipv6 = 1;
69       else if (unformat (i, "priority %u", &priority))
70         ;
71       else if (unformat (i, "interval %u", &interval))
72         ;
73       else if (unformat (i, "no_preempt"))
74         no_preempt = 1;
75       else if (unformat (i, "accept_mode"))
76         accept_mode = 1;
77       else if (unformat (i, "unicast"))
78         vr_unicast = 1;
79       else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
80         {
81           vec_add1 (ip_addrs, addr);
82           n_addrs4++;
83           clib_memset (&addr, 0, sizeof (addr));
84         }
85       else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
86         {
87           vec_add1 (ip_addrs, addr);
88           n_addrs6++;
89           clib_memset (&addr, 0, sizeof (addr));
90         }
91       else if (unformat (i, "add"))
92         is_add = 1;
93       else if (unformat (i, "del"))
94         is_del = 1;
95       else
96         break;
97     }
98
99   if (is_add == is_del)
100     {
101       errmsg ("One of add or del must be specified\n");
102       ret = -99;
103     }
104   else if (sw_if_index == ~0)
105     {
106       errmsg ("Interface not set\n");
107       ret = -99;
108     }
109   else if (n_addrs4 && (n_addrs6 || is_ipv6))
110     {
111       errmsg ("Address family mismatch\n");
112       ret = -99;
113     }
114
115   if (ret)
116     goto done;
117
118   /* Construct the API message */
119   M2 (VRRP_VR_ADD_DEL, mp, vec_len (ip_addrs) * sizeof (*api_addr));
120
121   mp->is_add = is_add;
122   mp->sw_if_index = ntohl (sw_if_index);
123   mp->vr_id = vr_id;
124   mp->priority = priority;
125   mp->interval = htons (interval);
126   mp->flags = VRRP_API_VR_PREEMPT;      /* preempt by default */
127
128   if (no_preempt)
129     mp->flags &= ~VRRP_API_VR_PREEMPT;
130
131   if (accept_mode)
132     mp->flags |= VRRP_API_VR_ACCEPT;
133
134   if (vr_unicast)
135     mp->flags |= VRRP_API_VR_UNICAST;
136
137   if (is_ipv6)
138     mp->flags |= VRRP_API_VR_IPV6;
139
140   mp->flags = htonl (mp->flags);
141
142   mp->n_addrs = n_addrs4 + n_addrs6;
143   api_addr = mp->addrs;
144
145   vec_foreach (ip_addr, ip_addrs)
146   {
147     void *src, *dst;
148     int len;
149
150     if (is_ipv6)
151       {
152         api_addr->af = ADDRESS_IP6;
153         src = &ip_addr->ip6;
154         dst = &api_addr->un.ip6;
155         len = sizeof (api_addr->un.ip6);
156       }
157     else
158       {
159         api_addr->af = ADDRESS_IP4;
160         src = &ip_addr->ip4;
161         dst = &api_addr->un.ip4;
162         len = sizeof (api_addr->un.ip4);
163       }
164     clib_memcpy (dst, src, len);
165     api_addr++;
166   }
167
168   /* send it... */
169   S (mp);
170
171   /* Wait for a reply... */
172   W (ret);
173
174 done:
175   vec_free (ip_addrs);
176
177   return ret;
178 }
179
180 static int
181 api_vrrp_vr_dump (vat_main_t * vam)
182 {
183   vrrp_test_main_t *vtm = &vrrp_test_main;
184   unformat_input_t *i = vam->input;
185   vl_api_vrrp_vr_dump_t *mp;
186   vl_api_control_ping_t *mp_ping;
187   u32 sw_if_index = ~0;
188   int ret;
189
190   if (vam->json_output)
191     {
192       clib_warning ("JSON output not supported for vrrp_vr_dump");
193       return -99;
194     }
195
196   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
197     {
198       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
199         ;
200       else if (unformat (i, "sw_if_index %u", &sw_if_index))
201         ;
202       else
203         break;
204     }
205
206   M (VRRP_VR_DUMP, mp);
207
208   mp->sw_if_index = htonl (sw_if_index);
209
210   S (mp);
211
212   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
213   mp_ping->_vl_msg_id = htons (vtm->ping_id);
214   mp_ping->client_index = vam->my_client_index;
215
216   vam->result_ready = 0;
217   S (mp_ping);
218
219   W (ret);
220   return ret;
221 }
222
223 static void
224 vl_api_vrrp_vr_details_t_handler (vl_api_vrrp_vr_details_t * mp)
225 {
226   vat_main_t *vam = vrrp_test_main.vat_main;
227   u32 api_flags = ntohl (mp->config.flags);
228   int i;
229   u32 state;
230   char *states[] = {
231     "VRRP_API_VR_STATE_INIT",
232     "VRRP_API_VR_STATE_BACKUP",
233     "VRRP_API_VR_STATE_MASTER",
234     "BAD STATE!",
235   };
236
237   state = ntohl (mp->runtime.state);
238
239   if (state > ARRAY_LEN (states) - 2)
240     state = ARRAY_LEN (states) - 1;
241
242   fformat (vam->ofp, "sw_if_index %u vr_id %u IPv%d: "
243            "priority %u interval %u preempt %s accept %s unicast %s "
244            "state %s master_adv_interval %u skew %u master_down_interval %u "
245            "mac %U ",
246            ntohl (mp->config.sw_if_index), mp->config.vr_id,
247            (mp->config.flags & VRRP_API_VR_IPV6) ? 6 : 4,
248            mp->config.priority, htons (mp->config.interval),
249            (api_flags & VRRP_API_VR_PREEMPT) ? "yes" : "no",
250            (api_flags & VRRP_API_VR_ACCEPT) ? "yes" : "no",
251            (api_flags & VRRP_API_VR_UNICAST) ? "yes" : "no",
252            states[state],
253            ntohs (mp->runtime.master_adv_int), ntohs (mp->runtime.skew),
254            ntohs (mp->runtime.master_down_int),
255            format_ethernet_address, &mp->runtime.mac);
256
257   fformat (vam->ofp, "addresses: ");
258
259   for (i = 0; i < mp->n_addrs; i++)
260     {
261       vl_api_address_t *addr = mp->addrs + i;
262
263       fformat (vam->ofp, "%U ",
264                (addr->af) ? format_ip6_address : format_ip4_address,
265                (u8 *) & addr->un);
266     }
267
268   fformat (vam->ofp, "\n");
269 }
270
271 static int
272 api_vrrp_vr_start_stop (vat_main_t * vam)
273 {
274   unformat_input_t *i = vam->input;
275   vl_api_vrrp_vr_start_stop_t *mp;
276   u32 sw_if_index = ~0, vr_id;
277   u8 is_ipv6, is_start, is_stop;
278   int ret;
279
280   vr_id = is_ipv6 = is_start = is_stop = 0;
281
282   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
283     {
284       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
285         ;
286       else if (unformat (i, "sw_if_index %u", &sw_if_index))
287         ;
288       else if (unformat (i, "vr_id %u", &vr_id))
289         ;
290       else if (unformat (i, "ipv6"))
291         is_ipv6 = 1;
292       else if (unformat (i, "start"))
293         is_start = 1;
294       else if (unformat (i, "stop"))
295         is_stop = 1;
296       else
297         break;
298     }
299
300   if (is_start == is_stop)
301     {
302       errmsg ("One of add or del must be specified\n");
303       return -99;
304     }
305   else if (sw_if_index == ~0)
306     {
307       errmsg ("Interface not set\n");
308       return -99;
309     }
310   else if (!vr_id)
311     {
312       errmsg ("VR ID must be between 1 and 255");
313       return -99;
314     }
315
316   M (VRRP_VR_START_STOP, mp);
317
318   mp->sw_if_index = htonl (sw_if_index);
319   mp->vr_id = vr_id;
320   mp->is_ipv6 = (is_ipv6 != 0);
321   mp->is_start = (is_start != 0);
322
323   S (mp);
324
325   W (ret);
326   return ret;
327 }
328
329 static int
330 api_vrrp_vr_track_if_add_del (vat_main_t * vam)
331 {
332   unformat_input_t *i = vam->input;
333   vl_api_vrrp_vr_track_if_add_del_t *mp;
334   vl_api_vrrp_vr_track_if_t *track_ifs = 0, *track_if;
335   u32 sw_if_index = ~0, track_sw_if_index = ~0, vr_id, priority;
336   u8 is_ipv6, is_add, is_del;
337   int ret;
338
339   is_ipv6 = is_add = is_del = 0;
340   vr_id = priority = 0;
341
342   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
343     {
344       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
345         ;
346       else if (unformat (i, "sw_if_index %u", &sw_if_index))
347         ;
348       else if (unformat (i, "vr_id %u", &vr_id))
349         ;
350       else if (unformat (i, "ipv6"))
351         is_ipv6 = 1;
352       else if (unformat (i, "track-index %u priority %u", &track_sw_if_index,
353                          &priority))
354         {
355           vec_add2 (track_ifs, track_if, 1);
356           track_if->sw_if_index = ntohl (track_sw_if_index);
357           track_if->priority = priority;
358         }
359       else if (unformat (i, "add"))
360         is_add = 1;
361       else if (unformat (i, "del"))
362         is_del = 1;
363       else
364         break;
365     }
366
367   if (is_add == is_del)
368     {
369       errmsg ("One of add or del must be specified\n");
370       ret = -99;
371     }
372   else if (sw_if_index == ~0)
373     {
374       errmsg ("VR interface not specified\n");
375       return -99;
376     }
377   else if (!vr_id)
378     {
379       errmsg ("Invalid VR ID - must be between 1 and 255");
380       return -99;
381     }
382   else if (vec_len (track_ifs) == 0)
383     {
384       errmsg ("No tracked interfaces specified for VR\n");
385       return -99;
386     }
387
388   vec_foreach (track_if, track_ifs)
389   {
390     if (!track_if->priority)
391       {
392         errmsg ("Priority must be nonzero");
393         vec_free (track_ifs);
394         return -99;
395       }
396   }
397
398
399   M2 (VRRP_VR_TRACK_IF_ADD_DEL, mp, vec_len (track_ifs) * sizeof (*track_if));
400
401   mp->sw_if_index = htonl (sw_if_index);
402   mp->vr_id = vr_id;
403   mp->is_ipv6 = (is_ipv6 != 0);
404   mp->is_add = is_add;
405   mp->n_ifs = vec_len (track_ifs);
406   clib_memcpy (mp->ifs, track_ifs, mp->n_ifs * sizeof (*track_if));
407
408   S (mp);
409
410   W (ret);
411   return ret;
412 }
413
414 static int
415 api_vrrp_vr_track_if_dump (vat_main_t * vam)
416 {
417   vrrp_test_main_t *vtm = &vrrp_test_main;
418   unformat_input_t *i = vam->input;
419   vl_api_vrrp_vr_track_if_dump_t *mp;
420   vl_api_control_ping_t *mp_ping;
421   u32 sw_if_index = ~0, vr_id = 0;
422   u8 is_ipv6 = 0, dump_all = 0;
423   int ret;
424
425   if (vam->json_output)
426     {
427       clib_warning ("JSON output not supported for vrrp_vr_track_if_dump");
428       return -99;
429     }
430
431   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
432     {
433       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
434         ;
435       else if (unformat (i, "sw_if_index %u", &sw_if_index))
436         ;
437       else if (unformat (i, "vr_id %u", &vr_id))
438         ;
439       else if (unformat (i, "ipv6"))
440         is_ipv6 = 1;
441       else
442         break;
443     }
444
445   /* If no arguments were provided, dump all VRs */
446   if ((sw_if_index == ~0) && !vr_id && !is_ipv6)
447     dump_all = 1;
448
449   /* If any arguments provided, sw_if_index and vr_id must be valid */
450   else if (sw_if_index == ~0)
451     {
452       errmsg ("VR interface not specified\n");
453       return -99;
454     }
455   else if (!vr_id)
456     {
457       errmsg ("Invalid VR ID - must be between 1 and 255");
458       return -99;
459     }
460
461   M (VRRP_VR_TRACK_IF_DUMP, mp);
462
463   mp->dump_all = dump_all;
464   if (!dump_all)
465     {
466       mp->sw_if_index = htonl (sw_if_index);
467       mp->vr_id = vr_id;
468       mp->is_ipv6 = is_ipv6;
469     }
470
471   S (mp);
472
473   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
474   mp_ping->_vl_msg_id = htons (vtm->ping_id);
475   mp_ping->client_index = vam->my_client_index;
476
477   vam->result_ready = 0;
478   S (mp_ping);
479
480   W (ret);
481   return ret;
482 }
483
484 static void
485   vl_api_vrrp_vr_track_if_details_t_handler
486   (vl_api_vrrp_vr_track_if_details_t * mp)
487 {
488   vat_main_t *vam = vrrp_test_main.vat_main;
489   int i;
490
491   for (i = 0; i < mp->n_ifs; i++)
492     {
493       fformat (vam->ofp, "VR sw_if_index %u vr_id %u IPv%d - "
494                "track sw_if_index %u priority %u\n",
495                ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6) ? 6 : 4,
496                ntohl (mp->ifs[i].sw_if_index), mp->ifs[i].priority);
497     }
498
499   fformat (vam->ofp, "\n");
500 }
501
502 static int
503 api_vrrp_vr_set_peers (vat_main_t * vam)
504 {
505   unformat_input_t *i = vam->input;
506   u32 sw_if_index = ~0;
507   u32 vr_id;
508   u8 is_ipv6;
509   u8 n_addrs4, n_addrs6;
510   vl_api_vrrp_vr_set_peers_t *mp;
511   vl_api_address_t *api_addr;
512   ip46_address_t *ip_addr, *ip_addrs = 0;
513   ip46_address_t addr;
514   int ret = 0;
515
516   n_addrs4 = n_addrs6 = 0;
517   vr_id = is_ipv6 = 0;
518
519   clib_memset (&addr, 0, sizeof (addr));
520
521   /* Parse args required to build the message */
522   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
523     {
524       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
525         ;
526       else if (unformat (i, "sw_if_index %u", &sw_if_index))
527         ;
528       else if (unformat (i, "vr_id %u", &vr_id))
529         ;
530       else if (unformat (i, "ipv6"))
531         is_ipv6 = 1;
532       else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
533         {
534           vec_add1 (ip_addrs, addr);
535           n_addrs4++;
536           clib_memset (&addr, 0, sizeof (addr));
537         }
538       else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
539         {
540           vec_add1 (ip_addrs, addr);
541           n_addrs6++;
542           clib_memset (&addr, 0, sizeof (addr));
543         }
544       else
545         break;
546     }
547
548   if (sw_if_index == ~0)
549     {
550       errmsg ("Interface not set\n");
551       ret = -99;
552     }
553   else if (n_addrs4 && (n_addrs6 || is_ipv6))
554     {
555       errmsg ("Address family mismatch\n");
556       ret = -99;
557     }
558
559   if (ret)
560     goto done;
561
562   /* Construct the API message */
563   M2 (VRRP_VR_SET_PEERS, mp, vec_len (ip_addrs) * sizeof (*api_addr));
564
565   mp->sw_if_index = ntohl (sw_if_index);
566   mp->vr_id = vr_id;
567   mp->is_ipv6 = (is_ipv6 != 0);
568
569   mp->n_addrs = n_addrs4 + n_addrs6;
570   api_addr = mp->addrs;
571
572   vec_foreach (ip_addr, ip_addrs)
573   {
574     void *src, *dst;
575     int len;
576
577     if (is_ipv6)
578       {
579         api_addr->af = ADDRESS_IP6;
580         src = &ip_addr->ip6;
581         dst = &api_addr->un.ip6;
582         len = sizeof (api_addr->un.ip6);
583       }
584     else
585       {
586         api_addr->af = ADDRESS_IP4;
587         src = &ip_addr->ip4;
588         dst = &api_addr->un.ip4;
589         len = sizeof (api_addr->un.ip4);
590       }
591     clib_memcpy (dst, src, len);
592     api_addr++;
593   }
594
595   /* send it... */
596   S (mp);
597
598   /* Wait for a reply... */
599   W (ret);
600
601 done:
602   vec_free (ip_addrs);
603
604   return ret;
605 }
606
607 static int
608 api_vrrp_vr_peer_dump (vat_main_t * vam)
609 {
610   vrrp_test_main_t *vtm = &vrrp_test_main;
611   unformat_input_t *i = vam->input;
612   vl_api_vrrp_vr_peer_dump_t *mp;
613   vl_api_control_ping_t *mp_ping;
614   u32 sw_if_index = ~0, vr_id = 0;
615   u8 is_ipv6 = 0;
616   int ret;
617
618   if (vam->json_output)
619     {
620       clib_warning ("JSON output not supported for vrrp_vr_track_if_dump");
621       return -99;
622     }
623
624   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
625     {
626       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
627         ;
628       else if (unformat (i, "sw_if_index %u", &sw_if_index))
629         ;
630       else if (unformat (i, "vr_id %u", &vr_id))
631         ;
632       else if (unformat (i, "ipv6"))
633         is_ipv6 = 1;
634       else
635         break;
636     }
637
638   /* sw_if_index and vr_id must be valid */
639   if (sw_if_index == ~0)
640     {
641       errmsg ("VR interface not specified\n");
642       return -99;
643     }
644   else if (!vr_id)
645     {
646       errmsg ("Invalid VR ID - must be between 1 and 255");
647       return -99;
648     }
649
650   M (VRRP_VR_PEER_DUMP, mp);
651
652   mp->sw_if_index = htonl (sw_if_index);
653   mp->vr_id = vr_id;
654   mp->is_ipv6 = is_ipv6;
655
656   S (mp);
657
658   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
659   mp_ping->_vl_msg_id = htons (vtm->ping_id);
660   mp_ping->client_index = vam->my_client_index;
661
662   vam->result_ready = 0;
663   S (mp_ping);
664
665   W (ret);
666   return ret;
667 }
668
669 static void
670 vl_api_vrrp_vr_peer_details_t_handler (vl_api_vrrp_vr_peer_details_t * mp)
671 {
672   vat_main_t *vam = vrrp_test_main.vat_main;
673   int i;
674
675   fformat (vam->ofp, "sw_if_index %u vr_id %u IPv%d ",
676            ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6) ? 6 : 4);
677
678   fformat (vam->ofp, "peer addresses: ");
679
680   for (i = 0; i < mp->n_peer_addrs; i++)
681     {
682       vl_api_address_t *addr = mp->peer_addrs + i;
683
684       fformat (vam->ofp, "%U ",
685                (addr->af) ? format_ip6_address : format_ip4_address,
686                (u8 *) & addr->un);
687     }
688
689   fformat (vam->ofp, "\n");
690 }
691
692 static int
693 api_want_vrrp_vr_events (vat_main_t * vam)
694 {
695   unformat_input_t *i = vam->input;
696   vl_api_want_vrrp_vr_events_t *mp;
697   int enable = -1;
698   int ret;
699
700   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
701     {
702       if (unformat (i, "enable"))
703         enable = 1;
704       else if (unformat (i, "disable"))
705         enable = 0;
706       else
707         break;
708     }
709
710   if (enable == -1)
711     {
712       errmsg ("missing enable|disable");
713       return -99;
714     }
715
716   M (WANT_VRRP_VR_EVENTS, mp);
717   mp->enable_disable = enable;
718   S (mp);
719   W (ret);
720
721   return ret;
722 }
723
724 #include <vrrp/vrrp.api_test.c>
725 /*
726  * fd.io coding-style-patch-verification: ON
727  *
728  * Local Variables:
729  * eval: (c-set-style "gnu")
730  * End:
731  */