docs: Use newer Ubuntu LTS in tutorial
[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_update (vat_main_t *vam)
39 {
40   unformat_input_t *i = vam->input;
41   u32 sw_if_index = ~0;
42   u32 vr_id, priority, interval, vrrp_index;
43   u8 is_ipv6, no_preempt, accept_mode, vr_unicast;
44   u8 n_addrs4, n_addrs6;
45   vl_api_vrrp_vr_update_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   vrrp_index = INDEX_INVALID;
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, "vrrp_index %u", &vrrp_index))
68         ;
69       else if (unformat (i, "ipv6"))
70         is_ipv6 = 1;
71       else if (unformat (i, "priority %u", &priority))
72         ;
73       else if (unformat (i, "interval %u", &interval))
74         ;
75       else if (unformat (i, "no_preempt"))
76         no_preempt = 1;
77       else if (unformat (i, "accept_mode"))
78         accept_mode = 1;
79       else if (unformat (i, "unicast"))
80         vr_unicast = 1;
81       else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
82         {
83           vec_add1 (ip_addrs, addr);
84           n_addrs4++;
85           clib_memset (&addr, 0, sizeof (addr));
86         }
87       else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
88         {
89           vec_add1 (ip_addrs, addr);
90           n_addrs6++;
91           clib_memset (&addr, 0, sizeof (addr));
92         }
93       else
94         break;
95     }
96
97   if (sw_if_index == ~0)
98     {
99       errmsg ("Interface not set\n");
100       ret = -99;
101     }
102   else if (n_addrs4 && (n_addrs6 || is_ipv6))
103     {
104       errmsg ("Address family mismatch\n");
105       ret = -99;
106     }
107
108   if (ret)
109     goto done;
110
111   /* Construct the API message */
112   M2 (VRRP_VR_UPDATE, mp, vec_len (ip_addrs) * sizeof (*api_addr));
113
114   mp->vrrp_index = htonl (vrrp_index);
115   mp->sw_if_index = ntohl (sw_if_index);
116   mp->vr_id = vr_id;
117   mp->priority = priority;
118   mp->interval = htons (interval);
119   mp->flags = VRRP_API_VR_PREEMPT; /* preempt by default */
120
121   if (no_preempt)
122     mp->flags &= ~VRRP_API_VR_PREEMPT;
123
124   if (accept_mode)
125     mp->flags |= VRRP_API_VR_ACCEPT;
126
127   if (vr_unicast)
128     mp->flags |= VRRP_API_VR_UNICAST;
129
130   if (is_ipv6)
131     mp->flags |= VRRP_API_VR_IPV6;
132
133   mp->flags = htonl (mp->flags);
134
135   mp->n_addrs = n_addrs4 + n_addrs6;
136   api_addr = mp->addrs;
137
138   vec_foreach (ip_addr, ip_addrs)
139     {
140       void *src, *dst;
141       int len;
142
143       if (is_ipv6)
144         {
145           api_addr->af = ADDRESS_IP6;
146           src = &ip_addr->ip6;
147           dst = &api_addr->un.ip6;
148           len = sizeof (api_addr->un.ip6);
149         }
150       else
151         {
152           api_addr->af = ADDRESS_IP4;
153           src = &ip_addr->ip4;
154           dst = &api_addr->un.ip4;
155           len = sizeof (api_addr->un.ip4);
156         }
157       clib_memcpy (dst, src, len);
158       api_addr++;
159     }
160
161   /* send it... */
162   S (mp);
163
164   /* Wait for a reply... */
165   W (ret);
166
167 done:
168   vec_free (ip_addrs);
169
170   return ret;
171 }
172
173 static void
174 vl_api_vrrp_vr_update_reply_t_handler (vl_api_vrrp_vr_update_reply_t *mp)
175 {
176 }
177
178 static int
179 api_vrrp_vr_del (vat_main_t *vam)
180 {
181   unformat_input_t *i = vam->input;
182   vl_api_vrrp_vr_del_t *mp;
183   u32 vrrp_index = INDEX_INVALID;
184   int ret;
185
186   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
187     {
188       if (unformat (i, "vrrp_index %u", &vrrp_index))
189         ;
190       else
191         break;
192     }
193
194   /* Construct the API message */
195   M (VRRP_VR_DEL, mp);
196   mp->vrrp_index = htonl (vrrp_index);
197
198   /* send it... */
199   S (mp);
200
201   /* Wait for a reply... */
202   W (ret);
203
204   return ret;
205 }
206
207 static int
208 api_vrrp_vr_add_del (vat_main_t * vam)
209 {
210   unformat_input_t *i = vam->input;
211   u32 sw_if_index = ~0;
212   u32 vr_id, priority, interval;
213   u8 is_ipv6, no_preempt, accept_mode, vr_unicast, is_add, is_del;
214   u8 n_addrs4, n_addrs6;
215   vl_api_vrrp_vr_add_del_t *mp;
216   vl_api_address_t *api_addr;
217   ip46_address_t *ip_addr, *ip_addrs = 0;
218   ip46_address_t addr;
219   int ret = 0;
220
221   interval = priority = 100;
222   n_addrs4 = n_addrs6 = 0;
223   vr_id = is_ipv6 = no_preempt = accept_mode = vr_unicast = 0;
224   is_add = is_del = 0;
225
226   clib_memset (&addr, 0, sizeof (addr));
227
228   /* Parse args required to build the message */
229   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
230     {
231       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
232         ;
233       else if (unformat (i, "sw_if_index %u", &sw_if_index))
234         ;
235       else if (unformat (i, "vr_id %u", &vr_id))
236         ;
237       else if (unformat (i, "ipv6"))
238         is_ipv6 = 1;
239       else if (unformat (i, "priority %u", &priority))
240         ;
241       else if (unformat (i, "interval %u", &interval))
242         ;
243       else if (unformat (i, "no_preempt"))
244         no_preempt = 1;
245       else if (unformat (i, "accept_mode"))
246         accept_mode = 1;
247       else if (unformat (i, "unicast"))
248         vr_unicast = 1;
249       else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
250         {
251           vec_add1 (ip_addrs, addr);
252           n_addrs4++;
253           clib_memset (&addr, 0, sizeof (addr));
254         }
255       else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
256         {
257           vec_add1 (ip_addrs, addr);
258           n_addrs6++;
259           clib_memset (&addr, 0, sizeof (addr));
260         }
261       else if (unformat (i, "add"))
262         is_add = 1;
263       else if (unformat (i, "del"))
264         is_del = 1;
265       else
266         break;
267     }
268
269   if (is_add == is_del)
270     {
271       errmsg ("One of add or del must be specified\n");
272       ret = -99;
273     }
274   else if (sw_if_index == ~0)
275     {
276       errmsg ("Interface not set\n");
277       ret = -99;
278     }
279   else if (n_addrs4 && (n_addrs6 || is_ipv6))
280     {
281       errmsg ("Address family mismatch\n");
282       ret = -99;
283     }
284
285   if (ret)
286     goto done;
287
288   /* Construct the API message */
289   M2 (VRRP_VR_ADD_DEL, mp, vec_len (ip_addrs) * sizeof (*api_addr));
290
291   mp->is_add = is_add;
292   mp->sw_if_index = ntohl (sw_if_index);
293   mp->vr_id = vr_id;
294   mp->priority = priority;
295   mp->interval = htons (interval);
296   mp->flags = VRRP_API_VR_PREEMPT;      /* preempt by default */
297
298   if (no_preempt)
299     mp->flags &= ~VRRP_API_VR_PREEMPT;
300
301   if (accept_mode)
302     mp->flags |= VRRP_API_VR_ACCEPT;
303
304   if (vr_unicast)
305     mp->flags |= VRRP_API_VR_UNICAST;
306
307   if (is_ipv6)
308     mp->flags |= VRRP_API_VR_IPV6;
309
310   mp->flags = htonl (mp->flags);
311
312   mp->n_addrs = n_addrs4 + n_addrs6;
313   api_addr = mp->addrs;
314
315   vec_foreach (ip_addr, ip_addrs)
316   {
317     void *src, *dst;
318     int len;
319
320     if (is_ipv6)
321       {
322         api_addr->af = ADDRESS_IP6;
323         src = &ip_addr->ip6;
324         dst = &api_addr->un.ip6;
325         len = sizeof (api_addr->un.ip6);
326       }
327     else
328       {
329         api_addr->af = ADDRESS_IP4;
330         src = &ip_addr->ip4;
331         dst = &api_addr->un.ip4;
332         len = sizeof (api_addr->un.ip4);
333       }
334     clib_memcpy (dst, src, len);
335     api_addr++;
336   }
337
338   /* send it... */
339   S (mp);
340
341   /* Wait for a reply... */
342   W (ret);
343
344 done:
345   vec_free (ip_addrs);
346
347   return ret;
348 }
349
350 static int
351 api_vrrp_vr_dump (vat_main_t * vam)
352 {
353   vrrp_test_main_t *vtm = &vrrp_test_main;
354   unformat_input_t *i = vam->input;
355   vl_api_vrrp_vr_dump_t *mp;
356   vl_api_control_ping_t *mp_ping;
357   u32 sw_if_index = ~0;
358   int ret;
359
360   if (vam->json_output)
361     {
362       clib_warning ("JSON output not supported for vrrp_vr_dump");
363       return -99;
364     }
365
366   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
367     {
368       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
369         ;
370       else if (unformat (i, "sw_if_index %u", &sw_if_index))
371         ;
372       else
373         break;
374     }
375
376   M (VRRP_VR_DUMP, mp);
377
378   mp->sw_if_index = htonl (sw_if_index);
379
380   S (mp);
381
382   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
383   mp_ping->_vl_msg_id = htons (vtm->ping_id);
384   mp_ping->client_index = vam->my_client_index;
385
386   vam->result_ready = 0;
387   S (mp_ping);
388
389   W (ret);
390   return ret;
391 }
392
393 static void
394 vl_api_vrrp_vr_details_t_handler (vl_api_vrrp_vr_details_t * mp)
395 {
396   vat_main_t *vam = vrrp_test_main.vat_main;
397   u32 api_flags = ntohl (mp->config.flags);
398   int i;
399   u32 state;
400   char *states[] = {
401     "VRRP_API_VR_STATE_INIT",
402     "VRRP_API_VR_STATE_BACKUP",
403     "VRRP_API_VR_STATE_MASTER",
404     "BAD STATE!",
405   };
406
407   state = ntohl (mp->runtime.state);
408
409   if (state > ARRAY_LEN (states) - 2)
410     state = ARRAY_LEN (states) - 1;
411
412   fformat (vam->ofp, "sw_if_index %u vr_id %u IPv%d: "
413            "priority %u interval %u preempt %s accept %s unicast %s "
414            "state %s master_adv_interval %u skew %u master_down_interval %u "
415            "mac %U ",
416            ntohl (mp->config.sw_if_index), mp->config.vr_id,
417            (mp->config.flags & VRRP_API_VR_IPV6) ? 6 : 4,
418            mp->config.priority, htons (mp->config.interval),
419            (api_flags & VRRP_API_VR_PREEMPT) ? "yes" : "no",
420            (api_flags & VRRP_API_VR_ACCEPT) ? "yes" : "no",
421            (api_flags & VRRP_API_VR_UNICAST) ? "yes" : "no",
422            states[state],
423            ntohs (mp->runtime.master_adv_int), ntohs (mp->runtime.skew),
424            ntohs (mp->runtime.master_down_int),
425            format_ethernet_address, &mp->runtime.mac);
426
427   fformat (vam->ofp, "addresses: ");
428
429   for (i = 0; i < mp->n_addrs; i++)
430     {
431       vl_api_address_t *addr = mp->addrs + i;
432
433       fformat (vam->ofp, "%U ",
434                (addr->af) ? format_ip6_address : format_ip4_address,
435                (u8 *) & addr->un);
436     }
437
438   fformat (vam->ofp, "\n");
439 }
440
441 static int
442 api_vrrp_vr_start_stop (vat_main_t * vam)
443 {
444   unformat_input_t *i = vam->input;
445   vl_api_vrrp_vr_start_stop_t *mp;
446   u32 sw_if_index = ~0, vr_id;
447   u8 is_ipv6, is_start, is_stop;
448   int ret;
449
450   vr_id = is_ipv6 = is_start = is_stop = 0;
451
452   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
453     {
454       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
455         ;
456       else if (unformat (i, "sw_if_index %u", &sw_if_index))
457         ;
458       else if (unformat (i, "vr_id %u", &vr_id))
459         ;
460       else if (unformat (i, "ipv6"))
461         is_ipv6 = 1;
462       else if (unformat (i, "start"))
463         is_start = 1;
464       else if (unformat (i, "stop"))
465         is_stop = 1;
466       else
467         break;
468     }
469
470   if (is_start == is_stop)
471     {
472       errmsg ("One of add or del must be specified\n");
473       return -99;
474     }
475   else if (sw_if_index == ~0)
476     {
477       errmsg ("Interface not set\n");
478       return -99;
479     }
480   else if (!vr_id)
481     {
482       errmsg ("VR ID must be between 1 and 255");
483       return -99;
484     }
485
486   M (VRRP_VR_START_STOP, mp);
487
488   mp->sw_if_index = htonl (sw_if_index);
489   mp->vr_id = vr_id;
490   mp->is_ipv6 = (is_ipv6 != 0);
491   mp->is_start = (is_start != 0);
492
493   S (mp);
494
495   W (ret);
496   return ret;
497 }
498
499 static int
500 api_vrrp_vr_track_if_add_del (vat_main_t * vam)
501 {
502   unformat_input_t *i = vam->input;
503   vl_api_vrrp_vr_track_if_add_del_t *mp;
504   vl_api_vrrp_vr_track_if_t *track_ifs = 0, *track_if;
505   u32 sw_if_index = ~0, track_sw_if_index = ~0, vr_id, priority;
506   u8 is_ipv6, is_add, is_del;
507   int ret;
508
509   is_ipv6 = is_add = is_del = 0;
510   vr_id = priority = 0;
511
512   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
513     {
514       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
515         ;
516       else if (unformat (i, "sw_if_index %u", &sw_if_index))
517         ;
518       else if (unformat (i, "vr_id %u", &vr_id))
519         ;
520       else if (unformat (i, "ipv6"))
521         is_ipv6 = 1;
522       else if (unformat (i, "track-index %u priority %u", &track_sw_if_index,
523                          &priority))
524         {
525           vec_add2 (track_ifs, track_if, 1);
526           track_if->sw_if_index = ntohl (track_sw_if_index);
527           track_if->priority = priority;
528         }
529       else if (unformat (i, "add"))
530         is_add = 1;
531       else if (unformat (i, "del"))
532         is_del = 1;
533       else
534         break;
535     }
536
537   if (is_add == is_del)
538     {
539       errmsg ("One of add or del must be specified\n");
540       ret = -99;
541     }
542   else if (sw_if_index == ~0)
543     {
544       errmsg ("VR interface not specified\n");
545       return -99;
546     }
547   else if (!vr_id)
548     {
549       errmsg ("Invalid VR ID - must be between 1 and 255");
550       return -99;
551     }
552   else if (vec_len (track_ifs) == 0)
553     {
554       errmsg ("No tracked interfaces specified for VR\n");
555       return -99;
556     }
557
558   vec_foreach (track_if, track_ifs)
559   {
560     if (!track_if->priority)
561       {
562         errmsg ("Priority must be nonzero");
563         vec_free (track_ifs);
564         return -99;
565       }
566   }
567
568
569   M2 (VRRP_VR_TRACK_IF_ADD_DEL, mp, vec_len (track_ifs) * sizeof (*track_if));
570
571   mp->sw_if_index = htonl (sw_if_index);
572   mp->vr_id = vr_id;
573   mp->is_ipv6 = (is_ipv6 != 0);
574   mp->is_add = is_add;
575   mp->n_ifs = vec_len (track_ifs);
576   clib_memcpy (mp->ifs, track_ifs, mp->n_ifs * sizeof (*track_if));
577
578   S (mp);
579
580   W (ret);
581   return ret;
582 }
583
584 static int
585 api_vrrp_vr_track_if_dump (vat_main_t * vam)
586 {
587   vrrp_test_main_t *vtm = &vrrp_test_main;
588   unformat_input_t *i = vam->input;
589   vl_api_vrrp_vr_track_if_dump_t *mp;
590   vl_api_control_ping_t *mp_ping;
591   u32 sw_if_index = ~0, vr_id = 0;
592   u8 is_ipv6 = 0, dump_all = 0;
593   int ret;
594
595   if (vam->json_output)
596     {
597       clib_warning ("JSON output not supported for vrrp_vr_track_if_dump");
598       return -99;
599     }
600
601   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
602     {
603       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
604         ;
605       else if (unformat (i, "sw_if_index %u", &sw_if_index))
606         ;
607       else if (unformat (i, "vr_id %u", &vr_id))
608         ;
609       else if (unformat (i, "ipv6"))
610         is_ipv6 = 1;
611       else
612         break;
613     }
614
615   /* If no arguments were provided, dump all VRs */
616   if ((sw_if_index == ~0) && !vr_id && !is_ipv6)
617     dump_all = 1;
618
619   /* If any arguments provided, sw_if_index and vr_id must be valid */
620   else if (sw_if_index == ~0)
621     {
622       errmsg ("VR interface not specified\n");
623       return -99;
624     }
625   else if (!vr_id)
626     {
627       errmsg ("Invalid VR ID - must be between 1 and 255");
628       return -99;
629     }
630
631   M (VRRP_VR_TRACK_IF_DUMP, mp);
632
633   mp->dump_all = dump_all;
634   if (!dump_all)
635     {
636       mp->sw_if_index = htonl (sw_if_index);
637       mp->vr_id = vr_id;
638       mp->is_ipv6 = is_ipv6;
639     }
640
641   S (mp);
642
643   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
644   mp_ping->_vl_msg_id = htons (vtm->ping_id);
645   mp_ping->client_index = vam->my_client_index;
646
647   vam->result_ready = 0;
648   S (mp_ping);
649
650   W (ret);
651   return ret;
652 }
653
654 static void
655   vl_api_vrrp_vr_track_if_details_t_handler
656   (vl_api_vrrp_vr_track_if_details_t * mp)
657 {
658   vat_main_t *vam = vrrp_test_main.vat_main;
659   int i;
660
661   for (i = 0; i < mp->n_ifs; i++)
662     {
663       fformat (vam->ofp, "VR sw_if_index %u vr_id %u IPv%d - "
664                "track sw_if_index %u priority %u\n",
665                ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6) ? 6 : 4,
666                ntohl (mp->ifs[i].sw_if_index), mp->ifs[i].priority);
667     }
668
669   fformat (vam->ofp, "\n");
670 }
671
672 static int
673 api_vrrp_vr_set_peers (vat_main_t * vam)
674 {
675   unformat_input_t *i = vam->input;
676   u32 sw_if_index = ~0;
677   u32 vr_id;
678   u8 is_ipv6;
679   u8 n_addrs4, n_addrs6;
680   vl_api_vrrp_vr_set_peers_t *mp;
681   vl_api_address_t *api_addr;
682   ip46_address_t *ip_addr, *ip_addrs = 0;
683   ip46_address_t addr;
684   int ret = 0;
685
686   n_addrs4 = n_addrs6 = 0;
687   vr_id = is_ipv6 = 0;
688
689   clib_memset (&addr, 0, sizeof (addr));
690
691   /* Parse args required to build the message */
692   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
693     {
694       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
695         ;
696       else if (unformat (i, "sw_if_index %u", &sw_if_index))
697         ;
698       else if (unformat (i, "vr_id %u", &vr_id))
699         ;
700       else if (unformat (i, "ipv6"))
701         is_ipv6 = 1;
702       else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
703         {
704           vec_add1 (ip_addrs, addr);
705           n_addrs4++;
706           clib_memset (&addr, 0, sizeof (addr));
707         }
708       else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
709         {
710           vec_add1 (ip_addrs, addr);
711           n_addrs6++;
712           clib_memset (&addr, 0, sizeof (addr));
713         }
714       else
715         break;
716     }
717
718   if (sw_if_index == ~0)
719     {
720       errmsg ("Interface not set\n");
721       ret = -99;
722     }
723   else if (n_addrs4 && (n_addrs6 || is_ipv6))
724     {
725       errmsg ("Address family mismatch\n");
726       ret = -99;
727     }
728
729   if (ret)
730     goto done;
731
732   /* Construct the API message */
733   M2 (VRRP_VR_SET_PEERS, mp, vec_len (ip_addrs) * sizeof (*api_addr));
734
735   mp->sw_if_index = ntohl (sw_if_index);
736   mp->vr_id = vr_id;
737   mp->is_ipv6 = (is_ipv6 != 0);
738
739   mp->n_addrs = n_addrs4 + n_addrs6;
740   api_addr = mp->addrs;
741
742   vec_foreach (ip_addr, ip_addrs)
743   {
744     void *src, *dst;
745     int len;
746
747     if (is_ipv6)
748       {
749         api_addr->af = ADDRESS_IP6;
750         src = &ip_addr->ip6;
751         dst = &api_addr->un.ip6;
752         len = sizeof (api_addr->un.ip6);
753       }
754     else
755       {
756         api_addr->af = ADDRESS_IP4;
757         src = &ip_addr->ip4;
758         dst = &api_addr->un.ip4;
759         len = sizeof (api_addr->un.ip4);
760       }
761     clib_memcpy (dst, src, len);
762     api_addr++;
763   }
764
765   /* send it... */
766   S (mp);
767
768   /* Wait for a reply... */
769   W (ret);
770
771 done:
772   vec_free (ip_addrs);
773
774   return ret;
775 }
776
777 static int
778 api_vrrp_vr_peer_dump (vat_main_t * vam)
779 {
780   vrrp_test_main_t *vtm = &vrrp_test_main;
781   unformat_input_t *i = vam->input;
782   vl_api_vrrp_vr_peer_dump_t *mp;
783   vl_api_control_ping_t *mp_ping;
784   u32 sw_if_index = ~0, vr_id = 0;
785   u8 is_ipv6 = 0;
786   int ret;
787
788   if (vam->json_output)
789     {
790       clib_warning ("JSON output not supported for vrrp_vr_track_if_dump");
791       return -99;
792     }
793
794   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
795     {
796       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
797         ;
798       else if (unformat (i, "sw_if_index %u", &sw_if_index))
799         ;
800       else if (unformat (i, "vr_id %u", &vr_id))
801         ;
802       else if (unformat (i, "ipv6"))
803         is_ipv6 = 1;
804       else
805         break;
806     }
807
808   /* sw_if_index and vr_id must be valid */
809   if (sw_if_index == ~0)
810     {
811       errmsg ("VR interface not specified\n");
812       return -99;
813     }
814   else if (!vr_id)
815     {
816       errmsg ("Invalid VR ID - must be between 1 and 255");
817       return -99;
818     }
819
820   M (VRRP_VR_PEER_DUMP, mp);
821
822   mp->sw_if_index = htonl (sw_if_index);
823   mp->vr_id = vr_id;
824   mp->is_ipv6 = is_ipv6;
825
826   S (mp);
827
828   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));
829   mp_ping->_vl_msg_id = htons (vtm->ping_id);
830   mp_ping->client_index = vam->my_client_index;
831
832   vam->result_ready = 0;
833   S (mp_ping);
834
835   W (ret);
836   return ret;
837 }
838
839 static void
840 vl_api_vrrp_vr_peer_details_t_handler (vl_api_vrrp_vr_peer_details_t * mp)
841 {
842   vat_main_t *vam = vrrp_test_main.vat_main;
843   int i;
844
845   fformat (vam->ofp, "sw_if_index %u vr_id %u IPv%d ",
846            ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6) ? 6 : 4);
847
848   fformat (vam->ofp, "peer addresses: ");
849
850   for (i = 0; i < mp->n_peer_addrs; i++)
851     {
852       vl_api_address_t *addr = mp->peer_addrs + i;
853
854       fformat (vam->ofp, "%U ",
855                (addr->af) ? format_ip6_address : format_ip4_address,
856                (u8 *) & addr->un);
857     }
858
859   fformat (vam->ofp, "\n");
860 }
861
862 static int
863 api_want_vrrp_vr_events (vat_main_t * vam)
864 {
865   unformat_input_t *i = vam->input;
866   vl_api_want_vrrp_vr_events_t *mp;
867   int enable = -1;
868   int ret;
869
870   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
871     {
872       if (unformat (i, "enable"))
873         enable = 1;
874       else if (unformat (i, "disable"))
875         enable = 0;
876       else
877         break;
878     }
879
880   if (enable == -1)
881     {
882       errmsg ("missing enable|disable");
883       return -99;
884     }
885
886   M (WANT_VRRP_VR_EVENTS, mp);
887   mp->enable_disable = enable;
888   S (mp);
889   W (ret);
890
891   return ret;
892 }
893
894 #include <vrrp/vrrp.api_test.c>
895 /*
896  * fd.io coding-style-patch-verification: ON
897  *
898  * Local Variables:
899  * eval: (c-set-style "gnu")
900  * End:
901  */