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);
322 pool_foreach (vr, vmp->vrs) {
324 if (sw_if_index && (sw_if_index != ~0) &&
325 (sw_if_index != vr->config.sw_if_index))
328 send_vrrp_vr_details (vr, reg, mp->context);
334 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
336 vl_api_vrrp_vr_start_stop_reply_t *rmp;
337 vrrp_vr_key_t vr_key;
340 clib_memset (&vr_key, 0, sizeof (vr_key));
342 vr_key.sw_if_index = ntohl (mp->sw_if_index);
343 vr_key.vr_id = mp->vr_id;
344 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
346 rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
348 REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
352 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
354 vl_api_vrrp_vr_set_peers_reply_t *rmp;
355 vrrp_vr_key_t vr_key;
356 ip46_address_t *peer_addrs = 0;
360 clib_memset (&vr_key, 0, sizeof (vr_key));
362 vr_key.sw_if_index = ntohl (mp->sw_if_index);
363 vr_key.vr_id = mp->vr_id;
364 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
366 for (i = 0; i < mp->n_addrs; i++)
368 ip46_address_t *peer;
370 vec_add2 (peer_addrs, peer, 1);
373 clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
375 clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
378 rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
380 vec_free (peer_addrs);
381 REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
385 send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
388 vrrp_main_t *vmp = &vrrp_main;
389 vl_api_vrrp_vr_peer_details_t *mp;
390 int n_addrs, msg_size;
391 ip46_address_t *addr;
392 vl_api_address_t *api_addr;
394 n_addrs = vec_len (vr->config.peer_addrs);
395 msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
396 mp = vl_msg_api_alloc (msg_size);
399 clib_memset (mp, 0, msg_size);
400 mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
401 mp->context = context;
403 mp->sw_if_index = htonl (vr->config.sw_if_index);
404 mp->vr_id = vr->config.vr_id;
405 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
408 mp->n_peer_addrs = n_addrs;
409 api_addr = mp->peer_addrs;
410 vec_foreach (addr, vr->config.peer_addrs)
415 if (vrrp_vr_is_ipv6 (vr))
417 api_addr->af = ADDRESS_IP6;
418 dst = &api_addr->un.ip6;
420 len = sizeof (addr->ip6);
424 api_addr->af = ADDRESS_IP4;
425 dst = &api_addr->un.ip4;
427 len = sizeof (addr->ip4);
429 clib_memcpy (dst, src, len);
433 vl_api_send_msg (reg, (u8 *) mp);
437 vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
439 vrrp_main_t *vmp = &vrrp_main;
440 vl_api_registration_t *reg;
442 vrrp_vr_key_t vr_key;
444 reg = vl_api_client_index_to_registration (mp->client_index);
448 vr_key.sw_if_index = ntohl (mp->sw_if_index);
450 if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
455 vr_key.vr_id = mp->vr_id;
456 vr_key.is_ipv6 = mp->is_ipv6;
458 p = mhash_get (&vmp->vr_index_by_key, &vr_key);
463 vr = pool_elt_at_index (vmp->vrs, vr_index);
464 send_vrrp_vr_peer_details (vr, reg, mp->context);
470 pool_foreach (vr, vmp->vrs) {
472 if (!vec_len (vr->config.peer_addrs))
475 send_vrrp_vr_details (vr, reg, mp->context);
482 vl_api_vrrp_vr_track_if_add_del_t_handler
483 (vl_api_vrrp_vr_track_if_add_del_t * mp)
485 vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
487 vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
490 /* lookup VR and return error if it does not exist */
492 vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
495 rv = VNET_API_ERROR_INVALID_VALUE;
499 for (i = 0; i < mp->n_ifs; i++)
501 vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
503 vec_add2 (track_ifs, track_if, 1);
504 track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
505 track_if->priority = api_track_if->priority;
508 rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
511 vec_free (track_ifs);
512 REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
516 send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
519 vrrp_main_t *vmp = &vrrp_main;
520 vl_api_vrrp_vr_track_if_details_t *mp;
522 vl_api_vrrp_vr_track_if_t *api_track_if;
523 vrrp_vr_tracking_if_t *track_if;
528 n_ifs = vec_len (vr->tracking.interfaces);
529 msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
530 mp = vl_msg_api_alloc (msg_size);
533 clib_memset (mp, 0, msg_size);
534 mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
535 mp->context = context;
537 mp->sw_if_index = htonl (vr->config.sw_if_index);
538 mp->vr_id = vr->config.vr_id;
539 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
541 /* tracked interfaces */
543 api_track_if = mp->ifs;
544 vec_foreach (track_if, vr->tracking.interfaces)
546 api_track_if->sw_if_index = htonl (track_if->sw_if_index);
547 api_track_if->priority = track_if->priority;
551 vl_api_send_msg (reg, (u8 *) mp);
555 vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
557 vrrp_main_t *vmp = &vrrp_main;
558 vl_api_registration_t *reg;
561 reg = vl_api_client_index_to_registration (mp->client_index);
567 vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
568 send_vrrp_vr_track_if_details (vr, reg, mp->context);
574 pool_foreach (vr, vmp->vrs) {
576 if (!vec_len (vr->tracking.interfaces))
579 send_vrrp_vr_track_if_details (vr, reg, mp->context);
586 send_vrrp_vr_event (vpe_client_registration_t * reg,
587 vl_api_registration_t * vl_reg,
588 vrrp_vr_t * vr, vrrp_vr_state_t new_state)
590 vrrp_main_t *vmp = &vrrp_main;
591 vl_api_vrrp_vr_event_t *mp;
593 mp = vl_msg_api_alloc (sizeof (*mp));
595 clib_memset (mp, 0, sizeof (*mp));
596 mp->_vl_msg_id = ntohs (VL_API_VRRP_VR_EVENT + vmp->msg_id_base);
597 mp->client_index = reg->client_index;
598 mp->pid = reg->client_pid;
599 mp->vr.sw_if_index = ntohl (vr->config.sw_if_index);
600 mp->vr.vr_id = vr->config.vr_id;
601 mp->vr.is_ipv6 = ((vr->config.flags & VRRP_VR_IPV6) != 0);
603 mp->old_state = htonl (vrrp_vr_state_encode (vr->runtime.state));
604 mp->new_state = htonl (vrrp_vr_state_encode (new_state));
606 vl_api_send_msg (vl_reg, (u8 *) mp);
610 vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
612 vpe_api_main_t *vam = &vpe_api_main;
613 vpe_client_registration_t *reg;
614 vl_api_registration_t *vl_reg;
617 pool_foreach (reg, vam->vrrp_vr_events_registrations)
619 vl_reg = vl_api_client_index_to_registration (reg->client_index);
621 send_vrrp_vr_event (reg, vl_reg, vr, new_state);
626 pub_sub_handler (vrrp_vr_events, VRRP_VR_EVENTS);
628 /* Set up the API message handling tables */
629 #include <vrrp/vrrp.api.c>
631 vrrp_plugin_api_hookup (vlib_main_t * vm)
633 vrrp_main_t *vmp = &vrrp_main;
635 /* Ask for a correctly-sized block of API message decode slots */
636 vmp->msg_id_base = setup_message_id_table ();
644 * fd.io coding-style-patch-verification: ON
647 * eval: (c-set-style "gnu")