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