FD.io VPP  v20.05-21-gb1500e9ff
Vector Packet Processing
vrrp_api.c
Go to the documentation of this file.
1 /*
2  * vrrp.c - vpp vrrp plug-in
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9 
10 #include <vnet/vnet.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vrrp/vrrp.h>
13 
14 #include <vlibapi/api.h>
15 #include <vlibmemory/api.h>
16 #include <vpp/app/version.h>
17 
18 /* define message IDs */
19 #include <vnet/format_fns.h>
20 #include <vrrp/vrrp.api_enum.h>
21 #include <vrrp/vrrp.api_types.h>
22 
23 #define REPLY_MSG_ID_BASE vmp->msg_id_base
25 
26 /* API message handlers */
27 static void
29 {
30  vrrp_main_t *vmp = &vrrp_main;
31  vl_api_vrrp_vr_add_del_reply_t *rmp;
32  vrrp_vr_config_t vr_conf;
33  u32 api_flags;
34  ip46_address_t *addrs = 0;
35  int rv;
36 
38 
39  api_flags = htonl (mp->flags);
40 
41  clib_memset (&vr_conf, 0, sizeof (vr_conf));
42 
43  vr_conf.sw_if_index = ntohl (mp->sw_if_index);
44  vr_conf.vr_id = mp->vr_id;
45  vr_conf.priority = mp->priority;
46  vr_conf.adv_interval = ntohs (mp->interval);
47 
48  if (api_flags & VRRP_API_VR_PREEMPT)
49  vr_conf.flags |= VRRP_VR_PREEMPT;
50 
51  if (api_flags & VRRP_API_VR_ACCEPT)
52  vr_conf.flags |= VRRP_VR_ACCEPT;
53 
54  if (api_flags & VRRP_API_VR_UNICAST)
55  vr_conf.flags |= VRRP_VR_UNICAST;
56 
57  if (api_flags & VRRP_API_VR_IPV6)
58  vr_conf.flags |= VRRP_VR_IPV6;
59 
60  if (mp->is_add)
61  {
62  int i;
63 
64  for (i = 0; i < mp->n_addrs; i++)
65  {
66  ip46_address_t *addr;
67  void *src, *dst;
68  int len;
69 
70  vec_add2 (addrs, addr, 1);
71 
72  if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
73  {
74  src = &mp->addrs[i].un.ip4;
75  dst = &addr->ip4;
76  len = sizeof (addr->ip4);
77  }
78  else
79  {
80  src = &mp->addrs[i].un.ip6;
81  dst = &addr->ip6;
82  len = sizeof (addr->ip6);
83  }
84 
85  clib_memcpy (dst, src, len);
86  }
87 
88  vr_conf.vr_addrs = addrs;
89  }
90 
91  if (vr_conf.priority == 0)
92  {
93  clib_warning ("VR priority must be > 0");
94  rv = VNET_API_ERROR_INVALID_VALUE;
95  }
96  else if (vr_conf.adv_interval == 0)
97  {
98  clib_warning ("VR advertisement interval must be > 0");
99  rv = VNET_API_ERROR_INVALID_VALUE;
100  }
101  else if (vr_conf.vr_id == 0)
102  {
103  clib_warning ("VR ID must be > 0");
104  rv = VNET_API_ERROR_INVALID_VALUE;
105  }
106  else
107  rv = vrrp_vr_add_del (mp->is_add, &vr_conf);
108 
109  vec_free (addrs);
110 
112  REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
113 }
114 
115 static void
117  u32 context)
118 {
119  vrrp_main_t *vmp = &vrrp_main;
121  int n_addrs, msg_size;
122  ip46_address_t *addr;
123  vl_api_address_t *api_addr;
124  u32 api_flags = 0;
125 
126  n_addrs = vec_len (vr->config.vr_addrs);
127  msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
128  mp = vl_msg_api_alloc (msg_size);
129  if (!mp)
130  return;
131  clib_memset (mp, 0, msg_size);
132  mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base);
133  mp->context = context;
134 
135  /* config */
136  mp->config.sw_if_index = htonl (vr->config.sw_if_index);
137  mp->config.vr_id = vr->config.vr_id;
138  mp->config.priority = vr->config.priority;
139  mp->config.interval = htons (vr->config.adv_interval);
140 
141  if (vr->config.flags & VRRP_VR_PREEMPT)
142  api_flags |= VRRP_API_VR_PREEMPT;
143  if (vr->config.flags & VRRP_VR_ACCEPT)
144  api_flags |= VRRP_API_VR_ACCEPT;
145  if (vrrp_vr_is_unicast (vr))
146  api_flags |= VRRP_API_VR_UNICAST;
147  if (vrrp_vr_is_ipv6 (vr))
148  api_flags |= VRRP_API_VR_IPV6;
149 
150  mp->config.flags = htonl (api_flags);
151 
152  /* runtime */
153  switch (vr->runtime.state)
154  {
155  case VRRP_VR_STATE_INIT:
156  mp->runtime.state = htonl (VRRP_API_VR_STATE_INIT);
157  break;
158  case VRRP_VR_STATE_BACKUP:
159  mp->runtime.state = htonl (VRRP_API_VR_STATE_BACKUP);
160  break;
161  case VRRP_VR_STATE_MASTER:
162  mp->runtime.state = htonl (VRRP_API_VR_STATE_MASTER);
163  break;
164  case VRRP_VR_STATE_INTF_DOWN:
165  mp->runtime.state = htonl (VRRP_API_VR_STATE_INTF_DOWN);
166  break;
167  default:
168  break;
169  }
170 
171  mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int);
172  mp->runtime.skew = htons (vr->runtime.skew);
173  mp->runtime.master_down_int = htons (vr->runtime.master_down_int);
174  clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac));
175 
176  mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
177  mp->runtime.tracking.priority = vrrp_vr_priority (vr);
178 
179  /* addrs */
180  mp->n_addrs = vec_len (vr->config.vr_addrs);
181  api_addr = mp->addrs;
182  vec_foreach (addr, vr->config.vr_addrs)
183  {
184  void *src, *dst;
185  size_t len;
186 
187  if (vrrp_vr_is_ipv6 (vr))
188  {
189  api_addr->af = ADDRESS_IP6;
190  dst = &api_addr->un.ip6;
191  src = &addr->ip6;
192  len = sizeof (addr->ip6);
193  }
194  else
195  {
196  api_addr->af = ADDRESS_IP4;
197  dst = &api_addr->un.ip4;
198  src = &addr->ip4;
199  len = sizeof (addr->ip4);
200  }
201  clib_memcpy (dst, src, len);
202  api_addr++;
203  }
204 
205  vl_api_send_msg (reg, (u8 *) mp);
206 }
207 
208 static void
210 {
211  vrrp_main_t *vmp = &vrrp_main;
213  vrrp_vr_t *vr;
215 
217  if (!reg)
218  return;
219 
220  sw_if_index = htonl (mp->sw_if_index);
221 
222  /* *INDENT-OFF* */
223  pool_foreach (vr, vmp->vrs, ({
224 
225  if (sw_if_index && (sw_if_index != ~0) &&
226  (sw_if_index != vr->config.sw_if_index))
227  continue;
228 
229  send_vrrp_vr_details (vr, reg, mp->context);
230  }));
231  /* *INDENT-ON* */
232 }
233 
234 static void
236 {
237  vrrp_main_t *vmp = &vrrp_main;
238  vl_api_vrrp_vr_start_stop_reply_t *rmp;
239  vrrp_vr_key_t vr_key;
240  int rv;
241 
242  clib_memset (&vr_key, 0, sizeof (vr_key));
243 
244  vr_key.sw_if_index = ntohl (mp->sw_if_index);
245  vr_key.vr_id = mp->vr_id;
246  vr_key.is_ipv6 = (mp->is_ipv6 != 0);
247 
248  rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
249 
250  REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
251 }
252 
253 static void
255 {
256  vrrp_main_t *vmp = &vrrp_main;
257  vl_api_vrrp_vr_set_peers_reply_t *rmp;
258  vrrp_vr_key_t vr_key;
259  ip46_address_t *peer_addrs = 0;
260  int i;
261  int rv;
262 
263  clib_memset (&vr_key, 0, sizeof (vr_key));
264 
265  vr_key.sw_if_index = ntohl (mp->sw_if_index);
266  vr_key.vr_id = mp->vr_id;
267  vr_key.is_ipv6 = (mp->is_ipv6 != 0);
268 
269  for (i = 0; i < mp->n_addrs; i++)
270  {
271  ip46_address_t *peer;
272 
273  vec_add2 (peer_addrs, peer, 1);
274 
275  if (mp->is_ipv6)
276  clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
277  else
278  clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
279  }
280 
281  rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
282 
283  vec_free (peer_addrs);
284  REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
285 }
286 
287 static void
289  u32 context)
290 {
291  vrrp_main_t *vmp = &vrrp_main;
293  int n_addrs, msg_size;
294  ip46_address_t *addr;
295  vl_api_address_t *api_addr;
296 
297  n_addrs = vec_len (vr->config.peer_addrs);
298  msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
299  mp = vl_msg_api_alloc (msg_size);
300  if (!mp)
301  return;
302  clib_memset (mp, 0, msg_size);
303  mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
304  mp->context = context;
305 
306  mp->sw_if_index = htonl (vr->config.sw_if_index);
307  mp->vr_id = vr->config.vr_id;
308  mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
309 
310  /* addrs */
311  mp->n_peer_addrs = n_addrs;
312  api_addr = mp->peer_addrs;
313  vec_foreach (addr, vr->config.peer_addrs)
314  {
315  void *src, *dst;
316  size_t len;
317 
318  if (vrrp_vr_is_ipv6 (vr))
319  {
320  api_addr->af = ADDRESS_IP6;
321  dst = &api_addr->un.ip6;
322  src = &addr->ip6;
323  len = sizeof (addr->ip6);
324  }
325  else
326  {
327  api_addr->af = ADDRESS_IP4;
328  dst = &api_addr->un.ip4;
329  src = &addr->ip4;
330  len = sizeof (addr->ip4);
331  }
332  clib_memcpy (dst, src, len);
333  api_addr++;
334  }
335 
336  vl_api_send_msg (reg, (u8 *) mp);
337 }
338 
339 static void
341 {
342  vrrp_main_t *vmp = &vrrp_main;
344  vrrp_vr_t *vr;
345  vrrp_vr_key_t vr_key;
346 
348  if (!reg)
349  return;
350 
351  vr_key.sw_if_index = ntohl (mp->sw_if_index);
352 
353  if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
354  {
355  uword *p;
356  u32 vr_index = ~0;
357 
358  vr_key.vr_id = mp->vr_id;
359  vr_key.is_ipv6 = mp->is_ipv6;
360 
361  p = mhash_get (&vmp->vr_index_by_key, &vr_key);
362  if (!p)
363  return;
364 
365  vr_index = p[0];
366  vr = pool_elt_at_index (vmp->vrs, vr_index);
367  send_vrrp_vr_peer_details (vr, reg, mp->context);
368 
369  return;
370  }
371 
372  /* *INDENT-OFF* */
373  pool_foreach (vr, vmp->vrs, ({
374 
375  if (!vec_len (vr->config.peer_addrs))
376  continue;
377 
378  send_vrrp_vr_details (vr, reg, mp->context);
379 
380  }));
381  /* *INDENT-ON* */
382 }
383 
384 static void
387 {
388  vrrp_main_t *vmp = &vrrp_main;
389  vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
390  vrrp_vr_t *vr;
391  vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
392  int rv = 0, i;
393 
394  /* lookup VR and return error if it does not exist */
395  vr =
396  vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
397  if (!vr)
398  {
399  rv = VNET_API_ERROR_INVALID_VALUE;
400  goto done;
401  }
402 
403  for (i = 0; i < mp->n_ifs; i++)
404  {
405  vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
406 
407  vec_add2 (track_ifs, track_if, 1);
408  track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
409  track_if->priority = api_track_if->priority;
410  }
411 
412  rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
413 
414 done:
415  vec_free (track_ifs);
416  REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
417 }
418 
419 static void
421  u32 context)
422 {
423  vrrp_main_t *vmp = &vrrp_main;
425  int n_ifs, msg_size;
426  vl_api_vrrp_vr_track_if_t *api_track_if;
427  vrrp_vr_tracking_if_t *track_if;
428 
429  if (!vr)
430  return;
431 
432  n_ifs = vec_len (vr->tracking.interfaces);
433  msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
434  mp = vl_msg_api_alloc (msg_size);
435  if (!mp)
436  return;
437  clib_memset (mp, 0, msg_size);
438  mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
439  mp->context = context;
440 
441  mp->sw_if_index = htonl (vr->config.sw_if_index);
442  mp->vr_id = vr->config.vr_id;
443  mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
444 
445  /* tracked interfaces */
446  mp->n_ifs = n_ifs;
447  api_track_if = mp->ifs;
448  vec_foreach (track_if, vr->tracking.interfaces)
449  {
450  api_track_if->sw_if_index = htonl (track_if->sw_if_index);
451  api_track_if->priority = track_if->priority;
452  api_track_if += 1;
453  }
454 
455  vl_api_send_msg (reg, (u8 *) mp);
456 }
457 
458 static void
460 {
461  vrrp_main_t *vmp = &vrrp_main;
463  vrrp_vr_t *vr;
464 
466  if (!reg)
467  return;
468 
469  if (!mp->dump_all)
470  {
471  vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
472  send_vrrp_vr_track_if_details (vr, reg, mp->context);
473 
474  return;
475  }
476 
477  /* *INDENT-OFF* */
478  pool_foreach (vr, vmp->vrs, ({
479 
480  if (!vec_len (vr->tracking.interfaces))
481  continue;
482 
483  send_vrrp_vr_track_if_details (vr, reg, mp->context);
484 
485  }));
486  /* *INDENT-ON* */
487 }
488 
489 /* Set up the API message handling tables */
490 #include <vrrp/vrrp.api.c>
491 clib_error_t *
493 {
494  vrrp_main_t *vmp = &vrrp_main;
495 
496  /* Ask for a correctly-sized block of API message decode slots */
498 
499  return 0;
500 }
501 
502 /* *INDENT-ON* */
503 
504 /*
505  * fd.io coding-style-patch-verification: ON
506  *
507  * Local Variables:
508  * eval: (c-set-style "gnu")
509  * End:
510  */
u8 vr_id
Definition: vrrp.h:32
static u8 vrrp_vr_is_unicast(vrrp_vr_t *vr)
Definition: vrrp.h:315
VRRP: dump virtual router interface tracking data.
Definition: vrrp.api:219
u32 sw_if_index
Definition: vrrp.h:71
vrrp_vr_tracking_t tracking
Definition: vrrp.h:110
int vrrp_vr_start_stop(u8 is_start, vrrp_vr_key_t *vr_key)
Definition: vrrp.c:661
Definition: vrrp.h:106
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:54
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static void vl_api_send_msg(vl_api_registration_t *rp, u8 *elem)
Definition: api.h:35
vrrp_vr_t * vrs
Definition: vrrp.h:151
vl_api_address_t src
Definition: gre.api:54
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:628
int vrrp_vr_set_peers(vrrp_vr_key_t *vr_key, ip46_address_t *peers)
Definition: vrrp.c:754
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:157
vrrp_vr_state_t state
Definition: vrrp.h:96
void * vl_msg_api_alloc(int nbytes)
vhost_vring_addr_t addr
Definition: vhost_user.h:254
unsigned char u8
Definition: types.h:56
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:222
static void vl_api_vrrp_vr_peer_dump_t_handler(vl_api_vrrp_vr_peer_dump_t *mp)
Definition: vrrp_api.c:340
#define clib_memcpy(d, s, n)
Definition: string.h:180
static void vl_api_vrrp_vr_track_if_dump_t_handler(vl_api_vrrp_vr_track_if_dump_t *mp)
Definition: vrrp_api.c:459
u16 master_adv_int
Definition: vrrp.h:97
static void send_vrrp_vr_track_if_details(vrrp_vr_t *vr, vl_api_registration_t *reg, u32 context)
Definition: vrrp_api.c:420
VRRP: start or shutdown the VRRP protocol for a virtual router.
Definition: vrrp.api:119
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
vl_api_interface_index_t sw_if_index
Definition: gre.api:53
VRRP: Add/delete VR priority tracking of interface status.
Definition: vrrp.api:199
vrrp_vr_config_t config
Definition: vrrp.h:108
vl_api_address_t peer_addrs[n_peer_addrs]
Definition: vrrp.api:177
static void send_vrrp_vr_details(vrrp_vr_t *vr, vl_api_registration_t *reg, u32 context)
Definition: vrrp_api.c:116
unsigned int u32
Definition: types.h:88
u16 skew
Definition: vrrp.h:98
u16 master_down_int
Definition: vrrp.h:99
mac_address_t mac
Definition: vrrp.h:100
mhash_t vr_index_by_key
Definition: vrrp.h:161
VRRP: dump virtual router peer address data.
Definition: vrrp.api:154
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:239
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:122
u8 priority
Definition: vrrp.h:73
u32 sw_if_index
Definition: vrrp.h:31
vrrp_vr_flags_t flags
Definition: vrrp.h:75
u8 vr_id
Definition: vrrp.h:72
#define REPLY_MACRO(t)
vrrp_vr_runtime_t runtime
Definition: vrrp.h:109
static void vl_api_vrrp_vr_dump_t_handler(vl_api_vrrp_vr_dump_t *mp)
Definition: vrrp_api.c:209
static void vl_api_vrrp_vr_add_del_t_handler(vl_api_vrrp_vr_add_del_t *mp)
Definition: vrrp_api.c:28
vl_api_address_t dst
Definition: gre.api:55
vlib_main_t * vm
Definition: in2out_ed.c:1599
vl_api_address_t peer
Definition: teib.api:28
static u8 vrrp_vr_is_ipv6(vrrp_vr_t *vr)
Definition: vrrp.h:309
u8 len
Definition: ip_types.api:92
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
#define BAD_SW_IF_INDEX_LABEL
u8 is_ipv6
Definition: vrrp.h:33
static void vl_api_vrrp_vr_track_if_add_del_t_handler(vl_api_vrrp_vr_track_if_add_del_t *mp)
Definition: vrrp_api.c:386
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
clib_error_t * vrrp_plugin_api_hookup(vlib_main_t *vm)
Definition: vrrp_api.c:492
vl_api_vrrp_vr_conf_t config
Definition: vrrp.api:105
#define clib_warning(format, args...)
Definition: error.h:59
static vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: api.h:57
static u8 vrrp_vr_priority(vrrp_vr_t *vr)
Definition: vrrp.h:353
VRRP: Add or delete a VRRP virtual router.
Definition: vrrp.api:50
vl_api_vrrp_vr_track_if_t ifs[n_ifs]
Definition: vrrp.api:208
vrrp_main_t vrrp_main
Definition: vrrp.c:25
VRRP: dump virtual router data.
Definition: vrrp.api:68
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:140
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
vrrp_vr_tracking_if_t * interfaces
Definition: vrrp.h:65
vl_api_address_t addrs[n_addrs]
Definition: vrrp.api:108
int vrrp_vr_add_del(u8 is_add, vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:573
vl_api_vrrp_vr_flags_t flags
Definition: vrrp.api:58
u16 msg_id_base
Definition: vrrp.h:148
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:173
VRRP: set unicast peers for a VR.
Definition: vrrp.api:137
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:203
vl_api_vrrp_vr_track_if_t ifs[n_ifs]
Definition: vrrp.api:243
static void send_vrrp_vr_peer_details(vrrp_vr_t *vr, vl_api_registration_t *reg, u32 context)
Definition: vrrp_api.c:288
u32 interfaces_dec
Definition: vrrp.h:66
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
static vrrp_vr_t * vrrp_vr_lookup(u32 sw_if_index, u8 vr_id, u8 is_ipv6)
Definition: vrrp.h:230
vl_api_address_t addrs[n_addrs]
Definition: vrrp.api:144
#define vec_foreach(var, vec)
Vector iterator.
static void setup_message_id_table(snat_main_t *sm, api_main_t *am)
Definition: nat_api.c:3256
static void vl_api_vrrp_vr_set_peers_t_handler(vl_api_vrrp_vr_set_peers_t *mp)
Definition: vrrp_api.c:254
static void vl_api_vrrp_vr_start_stop_t_handler(vl_api_vrrp_vr_start_stop_t *mp)
Definition: vrrp_api.c:235
ip46_address_t * vr_addrs
Definition: vrrp.h:76
VRRP: VR dump response.
Definition: vrrp.api:103
u16 adv_interval
Definition: vrrp.h:74
VRRP: VR peer dump response.
Definition: vrrp.api:170
ip46_address_t * peer_addrs
Definition: vrrp.h:77
vl_api_address_t addrs[n_addrs]
Definition: vrrp.api:60
int vrrp_vr_tracking_ifs_add_del(vrrp_vr_t *vr, vrrp_vr_tracking_if_t *track_ifs, u8 is_add)
Definition: vrrp.c:949
vl_api_interface_index_t sw_if_index
Definition: vrrp.api:71
VRRP: VR interface tracking dump response.
Definition: vrrp.api:236
vl_api_vrrp_vr_runtime_t runtime
Definition: vrrp.api:106
#define VALIDATE_SW_IF_INDEX(mp)