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_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
30 vl_api_vrrp_vr_add_del_reply_t *rmp;
31 vrrp_vr_config_t vr_conf;
33 ip46_address_t *addrs = 0;
36 VALIDATE_SW_IF_INDEX (mp);
38 api_flags = htonl (mp->flags);
40 clib_memset (&vr_conf, 0, sizeof (vr_conf));
42 vr_conf.sw_if_index = ntohl (mp->sw_if_index);
43 vr_conf.vr_id = mp->vr_id;
44 vr_conf.priority = mp->priority;
45 vr_conf.adv_interval = ntohs (mp->interval);
47 if (api_flags & VRRP_API_VR_PREEMPT)
48 vr_conf.flags |= VRRP_VR_PREEMPT;
50 if (api_flags & VRRP_API_VR_ACCEPT)
51 vr_conf.flags |= VRRP_VR_ACCEPT;
53 if (api_flags & VRRP_API_VR_UNICAST)
54 vr_conf.flags |= VRRP_VR_UNICAST;
56 if (api_flags & VRRP_API_VR_IPV6)
57 vr_conf.flags |= VRRP_VR_IPV6;
63 for (i = 0; i < mp->n_addrs; i++)
69 vec_add2 (addrs, addr, 1);
71 if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
73 src = &mp->addrs[i].un.ip4;
75 len = sizeof (addr->ip4);
79 src = &mp->addrs[i].un.ip6;
81 len = sizeof (addr->ip6);
84 clib_memcpy (dst, src, len);
87 vr_conf.vr_addrs = addrs;
90 if (vr_conf.priority == 0)
92 clib_warning ("VR priority must be > 0");
93 rv = VNET_API_ERROR_INVALID_VALUE;
95 else if (vr_conf.adv_interval == 0)
97 clib_warning ("VR advertisement interval must be > 0");
98 rv = VNET_API_ERROR_INVALID_VALUE;
100 else if (vr_conf.vr_id == 0)
102 clib_warning ("VR ID must be > 0");
103 rv = VNET_API_ERROR_INVALID_VALUE;
106 rv = vrrp_vr_add_del (mp->is_add, &vr_conf);
110 BAD_SW_IF_INDEX_LABEL;
111 REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
114 static vl_api_vrrp_vr_state_t
115 vrrp_vr_state_encode (vrrp_vr_state_t vr_state)
117 if (vr_state == VRRP_VR_STATE_BACKUP)
118 return VRRP_API_VR_STATE_BACKUP;
119 if (vr_state == VRRP_VR_STATE_MASTER)
120 return VRRP_API_VR_STATE_MASTER;
121 if (vr_state == VRRP_VR_STATE_INTF_DOWN)
122 return VRRP_API_VR_STATE_INTF_DOWN;
124 return VRRP_API_VR_STATE_INIT;
128 send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
131 vrrp_main_t *vmp = &vrrp_main;
132 vl_api_vrrp_vr_details_t *mp;
133 int n_addrs, msg_size;
134 ip46_address_t *addr;
135 vl_api_address_t *api_addr;
138 n_addrs = vec_len (vr->config.vr_addrs);
139 msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
140 mp = vl_msg_api_alloc (msg_size);
143 clib_memset (mp, 0, msg_size);
144 mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base);
145 mp->context = context;
148 mp->config.sw_if_index = htonl (vr->config.sw_if_index);
149 mp->config.vr_id = vr->config.vr_id;
150 mp->config.priority = vr->config.priority;
151 mp->config.interval = htons (vr->config.adv_interval);
153 if (vr->config.flags & VRRP_VR_PREEMPT)
154 api_flags |= VRRP_API_VR_PREEMPT;
155 if (vr->config.flags & VRRP_VR_ACCEPT)
156 api_flags |= VRRP_API_VR_ACCEPT;
157 if (vrrp_vr_is_unicast (vr))
158 api_flags |= VRRP_API_VR_UNICAST;
159 if (vrrp_vr_is_ipv6 (vr))
160 api_flags |= VRRP_API_VR_IPV6;
162 mp->config.flags = htonl (api_flags);
165 mp->runtime.state = htonl (vrrp_vr_state_encode (vr->runtime.state));
167 mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int);
168 mp->runtime.skew = htons (vr->runtime.skew);
169 mp->runtime.master_down_int = htons (vr->runtime.master_down_int);
170 clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac));
172 mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
173 mp->runtime.tracking.priority = vrrp_vr_priority (vr);
176 mp->n_addrs = vec_len (vr->config.vr_addrs);
177 api_addr = mp->addrs;
178 vec_foreach (addr, vr->config.vr_addrs)
183 if (vrrp_vr_is_ipv6 (vr))
185 api_addr->af = ADDRESS_IP6;
186 dst = &api_addr->un.ip6;
188 len = sizeof (addr->ip6);
192 api_addr->af = ADDRESS_IP4;
193 dst = &api_addr->un.ip4;
195 len = sizeof (addr->ip4);
197 clib_memcpy (dst, src, len);
201 vl_api_send_msg (reg, (u8 *) mp);
205 vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
207 vrrp_main_t *vmp = &vrrp_main;
208 vl_api_registration_t *reg;
212 reg = vl_api_client_index_to_registration (mp->client_index);
216 sw_if_index = htonl (mp->sw_if_index);
219 pool_foreach (vr, vmp->vrs, ({
221 if (sw_if_index && (sw_if_index != ~0) &&
222 (sw_if_index != vr->config.sw_if_index))
225 send_vrrp_vr_details (vr, reg, mp->context);
231 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
233 vl_api_vrrp_vr_start_stop_reply_t *rmp;
234 vrrp_vr_key_t vr_key;
237 clib_memset (&vr_key, 0, sizeof (vr_key));
239 vr_key.sw_if_index = ntohl (mp->sw_if_index);
240 vr_key.vr_id = mp->vr_id;
241 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
243 rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
245 REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
249 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
251 vl_api_vrrp_vr_set_peers_reply_t *rmp;
252 vrrp_vr_key_t vr_key;
253 ip46_address_t *peer_addrs = 0;
257 clib_memset (&vr_key, 0, sizeof (vr_key));
259 vr_key.sw_if_index = ntohl (mp->sw_if_index);
260 vr_key.vr_id = mp->vr_id;
261 vr_key.is_ipv6 = (mp->is_ipv6 != 0);
263 for (i = 0; i < mp->n_addrs; i++)
265 ip46_address_t *peer;
267 vec_add2 (peer_addrs, peer, 1);
270 clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
272 clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
275 rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
277 vec_free (peer_addrs);
278 REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
282 send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
285 vrrp_main_t *vmp = &vrrp_main;
286 vl_api_vrrp_vr_peer_details_t *mp;
287 int n_addrs, msg_size;
288 ip46_address_t *addr;
289 vl_api_address_t *api_addr;
291 n_addrs = vec_len (vr->config.peer_addrs);
292 msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
293 mp = vl_msg_api_alloc (msg_size);
296 clib_memset (mp, 0, msg_size);
297 mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
298 mp->context = context;
300 mp->sw_if_index = htonl (vr->config.sw_if_index);
301 mp->vr_id = vr->config.vr_id;
302 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
305 mp->n_peer_addrs = n_addrs;
306 api_addr = mp->peer_addrs;
307 vec_foreach (addr, vr->config.peer_addrs)
312 if (vrrp_vr_is_ipv6 (vr))
314 api_addr->af = ADDRESS_IP6;
315 dst = &api_addr->un.ip6;
317 len = sizeof (addr->ip6);
321 api_addr->af = ADDRESS_IP4;
322 dst = &api_addr->un.ip4;
324 len = sizeof (addr->ip4);
326 clib_memcpy (dst, src, len);
330 vl_api_send_msg (reg, (u8 *) mp);
334 vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
336 vrrp_main_t *vmp = &vrrp_main;
337 vl_api_registration_t *reg;
339 vrrp_vr_key_t vr_key;
341 reg = vl_api_client_index_to_registration (mp->client_index);
345 vr_key.sw_if_index = ntohl (mp->sw_if_index);
347 if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
352 vr_key.vr_id = mp->vr_id;
353 vr_key.is_ipv6 = mp->is_ipv6;
355 p = mhash_get (&vmp->vr_index_by_key, &vr_key);
360 vr = pool_elt_at_index (vmp->vrs, vr_index);
361 send_vrrp_vr_peer_details (vr, reg, mp->context);
367 pool_foreach (vr, vmp->vrs, ({
369 if (!vec_len (vr->config.peer_addrs))
372 send_vrrp_vr_details (vr, reg, mp->context);
379 vl_api_vrrp_vr_track_if_add_del_t_handler
380 (vl_api_vrrp_vr_track_if_add_del_t * mp)
382 vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
384 vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
387 /* lookup VR and return error if it does not exist */
389 vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
392 rv = VNET_API_ERROR_INVALID_VALUE;
396 for (i = 0; i < mp->n_ifs; i++)
398 vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
400 vec_add2 (track_ifs, track_if, 1);
401 track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
402 track_if->priority = api_track_if->priority;
405 rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
408 vec_free (track_ifs);
409 REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
413 send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
416 vrrp_main_t *vmp = &vrrp_main;
417 vl_api_vrrp_vr_track_if_details_t *mp;
419 vl_api_vrrp_vr_track_if_t *api_track_if;
420 vrrp_vr_tracking_if_t *track_if;
425 n_ifs = vec_len (vr->tracking.interfaces);
426 msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
427 mp = vl_msg_api_alloc (msg_size);
430 clib_memset (mp, 0, msg_size);
431 mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
432 mp->context = context;
434 mp->sw_if_index = htonl (vr->config.sw_if_index);
435 mp->vr_id = vr->config.vr_id;
436 mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
438 /* tracked interfaces */
440 api_track_if = mp->ifs;
441 vec_foreach (track_if, vr->tracking.interfaces)
443 api_track_if->sw_if_index = htonl (track_if->sw_if_index);
444 api_track_if->priority = track_if->priority;
448 vl_api_send_msg (reg, (u8 *) mp);
452 vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
454 vrrp_main_t *vmp = &vrrp_main;
455 vl_api_registration_t *reg;
458 reg = vl_api_client_index_to_registration (mp->client_index);
464 vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
465 send_vrrp_vr_track_if_details (vr, reg, mp->context);
471 pool_foreach (vr, vmp->vrs, ({
473 if (!vec_len (vr->tracking.interfaces))
476 send_vrrp_vr_track_if_details (vr, reg, mp->context);
483 send_vrrp_vr_event (vpe_client_registration_t * reg,
484 vl_api_registration_t * vl_reg,
485 vrrp_vr_t * vr, vrrp_vr_state_t new_state)
487 vrrp_main_t *vmp = &vrrp_main;
488 vl_api_vrrp_vr_event_t *mp;
490 mp = vl_msg_api_alloc (sizeof (*mp));
492 clib_memset (mp, 0, sizeof (*mp));
493 mp->_vl_msg_id = ntohs (VL_API_VRRP_VR_EVENT + vmp->msg_id_base);
494 mp->client_index = reg->client_index;
495 mp->pid = reg->client_pid;
496 mp->vr.sw_if_index = ntohl (vr->config.sw_if_index);
497 mp->vr.vr_id = vr->config.vr_id;
498 mp->vr.is_ipv6 = ((vr->config.flags & VRRP_VR_IPV6) != 0);
500 mp->old_state = htonl (vrrp_vr_state_encode (vr->runtime.state));
501 mp->new_state = htonl (vrrp_vr_state_encode (new_state));
503 vl_api_send_msg (vl_reg, (u8 *) mp);
507 vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
509 vpe_api_main_t *vam = &vpe_api_main;
510 vpe_client_registration_t *reg;
511 vl_api_registration_t *vl_reg;
514 pool_foreach(reg, vam->vrrp_vr_events_registrations,
516 vl_reg = vl_api_client_index_to_registration (reg->client_index);
518 send_vrrp_vr_event (reg, vl_reg, vr, new_state);
523 pub_sub_handler (vrrp_vr_events, VRRP_VR_EVENTS);
525 /* Set up the API message handling tables */
526 #include <vrrp/vrrp.api.c>
528 vrrp_plugin_api_hookup (vlib_main_t * vm)
530 vrrp_main_t *vmp = &vrrp_main;
532 /* Ask for a correctly-sized block of API message decode slots */
533 vmp->msg_id_base = setup_message_id_table ();
541 * fd.io coding-style-patch-verification: ON
544 * eval: (c-set-style "gnu")