2 * vrrp.c - vpp vrrp plug-in
4 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
6 * SPDX-License-Identifier: Apache-2.0
10 #include <vnet/vnet.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vrrp/vrrp.h>
14 #include <vlibapi/api.h>
15 #include <vlibmemory/api.h>
16 #include <vpp/app/version.h>
18 /* define message IDs */
19 #include <vnet/format_fns.h>
20 #include <vrrp/vrrp.api_enum.h>
21 #include <vrrp/vrrp.api_types.h>
23 #define REPLY_MSG_ID_BASE vrrp_main.msg_id_base
24 #include <vlibapi/api_helper_macros.h>
26 /* API message handlers */
28 vl_api_vrrp_vr_update_t_handler (vl_api_vrrp_vr_update_t *mp)
30 vl_api_vrrp_vr_update_reply_t *rmp;
31 vrrp_vr_config_t vr_conf;
33 u32 vrrp_index = INDEX_INVALID;
34 ip46_address_t *addrs = 0;
37 VALIDATE_SW_IF_INDEX (mp);
39 api_flags = htonl (mp->flags);
41 clib_memset (&vr_conf, 0, sizeof (vr_conf));
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);
48 if (api_flags & VRRP_API_VR_PREEMPT)
49 vr_conf.flags |= VRRP_VR_PREEMPT;
51 if (api_flags & VRRP_API_VR_ACCEPT)
52 vr_conf.flags |= VRRP_VR_ACCEPT;
54 if (api_flags & VRRP_API_VR_UNICAST)
55 vr_conf.flags |= VRRP_VR_UNICAST;
57 if (api_flags & VRRP_API_VR_IPV6)
58 vr_conf.flags |= VRRP_VR_IPV6;
61 for (i = 0; i < mp->n_addrs; i++)
67 vec_add2 (addrs, addr, 1);
69 if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
71 src = &mp->addrs[i].un.ip4;
73 len = sizeof (addr->ip4);
77 src = &mp->addrs[i].un.ip6;
79 len = sizeof (addr->ip6);
82 clib_memcpy (dst, src, len);
85 vr_conf.vr_addrs = addrs;
87 if (vr_conf.priority == 0)
89 clib_warning ("VR priority must be > 0");
90 rv = VNET_API_ERROR_INVALID_VALUE;
92 else if (vr_conf.adv_interval == 0)
94 clib_warning ("VR advertisement interval must be > 0");
95 rv = VNET_API_ERROR_INVALID_VALUE;
97 else if (vr_conf.vr_id == 0)
99 clib_warning ("VR ID must be > 0");
100 rv = VNET_API_ERROR_INVALID_VALUE;
104 vrrp_index = ntohl (mp->vrrp_index);
105 rv = vrrp_vr_update (&vrrp_index, &vr_conf);
110 BAD_SW_IF_INDEX_LABEL;
112 REPLY_MACRO2 (VL_API_VRRP_VR_UPDATE_REPLY,
114 rmp->vrrp_index = htonl (vrrp_index);
120 vl_api_vrrp_vr_del_t_handler (vl_api_vrrp_vr_del_t *mp)
122 vl_api_vrrp_vr_del_reply_t *rmp;
125 rv = vrrp_vr_del (ntohl (mp->vrrp_index));
127 REPLY_MACRO (VL_API_VRRP_VR_DEL_REPLY);
131 vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
133 vl_api_vrrp_vr_add_del_reply_t *rmp;
134 vrrp_vr_config_t vr_conf;
136 ip46_address_t *addrs = 0;
139 VALIDATE_SW_IF_INDEX (mp);
141 api_flags = htonl (mp->flags);
143 clib_memset (&vr_conf, 0, sizeof (vr_conf));
145 vr_conf.sw_if_index = ntohl (mp->sw_if_index);
146 vr_conf.vr_id = mp->vr_id;
147 vr_conf.priority = mp->priority;
148 vr_conf.adv_interval = ntohs (mp->interval);
150 if (api_flags & VRRP_API_VR_PREEMPT)
151 vr_conf.flags |= VRRP_VR_PREEMPT;
153 if (api_flags & VRRP_API_VR_ACCEPT)
154 vr_conf.flags |= VRRP_VR_ACCEPT;
156 if (api_flags & VRRP_API_VR_UNICAST)
157 vr_conf.flags |= VRRP_VR_UNICAST;
159 if (api_flags & VRRP_API_VR_IPV6)
160 vr_conf.flags |= VRRP_VR_IPV6;
166 for (i = 0; i < mp->n_addrs; i++)
168 ip46_address_t *addr;
172 vec_add2 (addrs, addr, 1);
174 if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
176 src = &mp->addrs[i].un.ip4;
178 len = sizeof (addr->ip4);
182 src = &mp->addrs[i].un.ip6;
184 len = sizeof (addr->ip6);
187 clib_memcpy (dst, src, len);
190 vr_conf.vr_addrs = addrs;
193 if (vr_conf.priority == 0)
195 clib_warning ("VR priority must be > 0");
196 rv = VNET_API_ERROR_INVALID_VALUE;
198 else if (vr_conf.adv_interval == 0)
200 clib_warning ("VR advertisement interval must be > 0");
201 rv = VNET_API_ERROR_INVALID_VALUE;
203 else if (vr_conf.vr_id == 0)
205 clib_warning ("VR ID must be > 0");
206 rv = VNET_API_ERROR_INVALID_VALUE;
209 rv = vrrp_vr_add_del (mp->is_add, &vr_conf, NULL);
213 BAD_SW_IF_INDEX_LABEL;
214 REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
217 static vl_api_vrrp_vr_state_t
218 vrrp_vr_state_encode (vrrp_vr_state_t vr_state)
220 if (vr_state == VRRP_VR_STATE_BACKUP)
221 return VRRP_API_VR_STATE_BACKUP;
222 if (vr_state == VRRP_VR_STATE_MASTER)
223 return VRRP_API_VR_STATE_MASTER;
224 if (vr_state == VRRP_VR_STATE_INTF_DOWN)
225 return VRRP_API_VR_STATE_INTF_DOWN;
227 return VRRP_API_VR_STATE_INIT;
231 send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
234 vrrp_main_t *vmp = &vrrp_main;
235 vl_api_vrrp_vr_details_t *mp;
236 int n_addrs, msg_size;
237 ip46_address_t *addr;
238 vl_api_address_t *api_addr;
241 n_addrs = vec_len (vr->config.vr_addrs);
242 msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
243 mp = vl_msg_api_alloc (msg_size);
246 clib_memset (mp, 0, msg_size);
247 mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base);
248 mp->context = context;
251 mp->config.sw_if_index = htonl (vr->config.sw_if_index);
252 mp->config.vr_id = vr->config.vr_id;
253 mp->config.priority = vr->config.priority;
254 mp->config.interval = htons (vr->config.adv_interval);
256 if (vr->config.flags & VRRP_VR_PREEMPT)
257 api_flags |= VRRP_API_VR_PREEMPT;
258 if (vr->config.flags & VRRP_VR_ACCEPT)
259 api_flags |= VRRP_API_VR_ACCEPT;
260 if (vrrp_vr_is_unicast (vr))
261 api_flags |= VRRP_API_VR_UNICAST;
262 if (vrrp_vr_is_ipv6 (vr))
263 api_flags |= VRRP_API_VR_IPV6;
265 mp->config.flags = htonl (api_flags);
268 mp->runtime.state = htonl (vrrp_vr_state_encode (vr->runtime.state));
270 mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int);
271 mp->runtime.skew = htons (vr->runtime.skew);
272 mp->runtime.master_down_int = htons (vr->runtime.master_down_int);
273 clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac));
275 mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
276 mp->runtime.tracking.priority = vrrp_vr_priority (vr);
279 mp->n_addrs = vec_len (vr->config.vr_addrs);
280 api_addr = mp->addrs;
281 vec_foreach (addr, vr->config.vr_addrs)
286 if (vrrp_vr_is_ipv6 (vr))
288 api_addr->af = ADDRESS_IP6;
289 dst = &api_addr->un.ip6;
291 len = sizeof (addr->ip6);
295 api_addr->af = ADDRESS_IP4;
296 dst = &api_addr->un.ip4;
298 len = sizeof (addr->ip4);
300 clib_memcpy (dst, src, len);
304 vl_api_send_msg (reg, (u8 *) mp);
308 vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
310 vrrp_main_t *vmp = &vrrp_main;
311 vl_api_registration_t *reg;
315 reg = vl_api_client_index_to_registration (mp->client_index);
319 sw_if_index = htonl (mp->sw_if_index);
321 pool_foreach (vr, vmp->vrs) {
323 if (sw_if_index && (sw_if_index != ~0) &&
324 (sw_if_index != vr->config.sw_if_index))
327 send_vrrp_vr_details (vr, reg, mp->context);
332 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
334 vl_api_vrrp_vr_start_stop_reply_t *rmp;
335 vrrp_vr_key_t vr_key;
338 clib_memset (&vr_key, 0, sizeof (vr_key));
340 vr_key.sw_if_index = ntohl (mp->sw_if_index);
341 vr_key.vr_id = mp->vr_id;
342 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
344 rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
346 REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
350 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
352 vl_api_vrrp_vr_set_peers_reply_t *rmp;
353 vrrp_vr_key_t vr_key;
354 ip46_address_t *peer_addrs = 0;
358 clib_memset (&vr_key, 0, sizeof (vr_key));
360 vr_key.sw_if_index = ntohl (mp->sw_if_index);
361 vr_key.vr_id = mp->vr_id;
362 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
364 for (i = 0; i < mp->n_addrs; i++)
366 ip46_address_t *peer;
368 vec_add2 (peer_addrs, peer, 1);
371 clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
373 clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
376 rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
378 vec_free (peer_addrs);
379 REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
383 send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
386 vrrp_main_t *vmp = &vrrp_main;
387 vl_api_vrrp_vr_peer_details_t *mp;
388 int n_addrs, msg_size;
389 ip46_address_t *addr;
390 vl_api_address_t *api_addr;
392 n_addrs = vec_len (vr->config.peer_addrs);
393 msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
394 mp = vl_msg_api_alloc (msg_size);
397 clib_memset (mp, 0, msg_size);
398 mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
399 mp->context = context;
401 mp->sw_if_index = htonl (vr->config.sw_if_index);
402 mp->vr_id = vr->config.vr_id;
403 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
406 mp->n_peer_addrs = n_addrs;
407 api_addr = mp->peer_addrs;
408 vec_foreach (addr, vr->config.peer_addrs)
413 if (vrrp_vr_is_ipv6 (vr))
415 api_addr->af = ADDRESS_IP6;
416 dst = &api_addr->un.ip6;
418 len = sizeof (addr->ip6);
422 api_addr->af = ADDRESS_IP4;
423 dst = &api_addr->un.ip4;
425 len = sizeof (addr->ip4);
427 clib_memcpy (dst, src, len);
431 vl_api_send_msg (reg, (u8 *) mp);
435 vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
437 vrrp_main_t *vmp = &vrrp_main;
438 vl_api_registration_t *reg;
440 vrrp_vr_key_t vr_key;
442 reg = vl_api_client_index_to_registration (mp->client_index);
446 vr_key.sw_if_index = ntohl (mp->sw_if_index);
448 if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
453 vr_key.vr_id = mp->vr_id;
454 vr_key.is_ipv6 = mp->is_ipv6;
456 p = mhash_get (&vmp->vr_index_by_key, &vr_key);
461 vr = pool_elt_at_index (vmp->vrs, vr_index);
462 send_vrrp_vr_peer_details (vr, reg, mp->context);
467 pool_foreach (vr, vmp->vrs) {
469 if (!vec_len (vr->config.peer_addrs))
472 send_vrrp_vr_details (vr, reg, mp->context);
478 vl_api_vrrp_vr_track_if_add_del_t_handler
479 (vl_api_vrrp_vr_track_if_add_del_t * mp)
481 vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
483 vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
486 /* lookup VR and return error if it does not exist */
488 vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
491 rv = VNET_API_ERROR_INVALID_VALUE;
495 for (i = 0; i < mp->n_ifs; i++)
497 vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
499 vec_add2 (track_ifs, track_if, 1);
500 track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
501 track_if->priority = api_track_if->priority;
504 rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
507 vec_free (track_ifs);
508 REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
512 send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
515 vrrp_main_t *vmp = &vrrp_main;
516 vl_api_vrrp_vr_track_if_details_t *mp;
518 vl_api_vrrp_vr_track_if_t *api_track_if;
519 vrrp_vr_tracking_if_t *track_if;
524 n_ifs = vec_len (vr->tracking.interfaces);
525 msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
526 mp = vl_msg_api_alloc (msg_size);
529 clib_memset (mp, 0, msg_size);
530 mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
531 mp->context = context;
533 mp->sw_if_index = htonl (vr->config.sw_if_index);
534 mp->vr_id = vr->config.vr_id;
535 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
537 /* tracked interfaces */
539 api_track_if = mp->ifs;
540 vec_foreach (track_if, vr->tracking.interfaces)
542 api_track_if->sw_if_index = htonl (track_if->sw_if_index);
543 api_track_if->priority = track_if->priority;
547 vl_api_send_msg (reg, (u8 *) mp);
551 vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
553 vrrp_main_t *vmp = &vrrp_main;
554 vl_api_registration_t *reg;
557 reg = vl_api_client_index_to_registration (mp->client_index);
563 vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
564 send_vrrp_vr_track_if_details (vr, reg, mp->context);
569 pool_foreach (vr, vmp->vrs) {
571 if (!vec_len (vr->tracking.interfaces))
574 send_vrrp_vr_track_if_details (vr, reg, mp->context);
580 send_vrrp_vr_event (vpe_client_registration_t * reg,
581 vl_api_registration_t * vl_reg,
582 vrrp_vr_t * vr, vrrp_vr_state_t new_state)
584 vrrp_main_t *vmp = &vrrp_main;
585 vl_api_vrrp_vr_event_t *mp;
587 mp = vl_msg_api_alloc (sizeof (*mp));
589 clib_memset (mp, 0, sizeof (*mp));
590 mp->_vl_msg_id = ntohs (VL_API_VRRP_VR_EVENT + vmp->msg_id_base);
591 mp->client_index = reg->client_index;
592 mp->pid = reg->client_pid;
593 mp->vr.sw_if_index = ntohl (vr->config.sw_if_index);
594 mp->vr.vr_id = vr->config.vr_id;
595 mp->vr.is_ipv6 = ((vr->config.flags & VRRP_VR_IPV6) != 0);
597 mp->old_state = htonl (vrrp_vr_state_encode (vr->runtime.state));
598 mp->new_state = htonl (vrrp_vr_state_encode (new_state));
600 vl_api_send_msg (vl_reg, (u8 *) mp);
604 vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
606 vpe_api_main_t *vam = &vpe_api_main;
607 vpe_client_registration_t *reg;
608 vl_api_registration_t *vl_reg;
610 pool_foreach (reg, vam->vrrp_vr_events_registrations)
612 vl_reg = vl_api_client_index_to_registration (reg->client_index);
614 send_vrrp_vr_event (reg, vl_reg, vr, new_state);
618 pub_sub_handler (vrrp_vr_events, VRRP_VR_EVENTS);
620 /* Set up the API message handling tables */
621 #include <vrrp/vrrp.api.c>
623 vrrp_plugin_api_hookup (vlib_main_t * vm)
625 vrrp_main_t *vmp = &vrrp_main;
627 /* Ask for a correctly-sized block of API message decode slots */
628 vmp->msg_id_base = setup_message_id_table ();
635 * fd.io coding-style-patch-verification: ON
638 * eval: (c-set-style "gnu")