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 vmp->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 vrrp_main_t *vmp = &vrrp_main;
31 vl_api_vrrp_vr_add_del_reply_t *rmp;
32 vrrp_vr_config_t vr_conf;
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;
64 for (i = 0; i < mp->n_addrs; i++)
70 vec_add2 (addrs, addr, 1);
72 if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
74 src = &mp->addrs[i].un.ip4;
76 len = sizeof (addr->ip4);
80 src = &mp->addrs[i].un.ip6;
82 len = sizeof (addr->ip6);
85 clib_memcpy (dst, src, len);
88 vr_conf.vr_addrs = addrs;
91 if (vr_conf.priority == 0)
93 clib_warning ("VR priority must be > 0");
94 rv = VNET_API_ERROR_INVALID_VALUE;
96 else if (vr_conf.adv_interval == 0)
98 clib_warning ("VR advertisement interval must be > 0");
99 rv = VNET_API_ERROR_INVALID_VALUE;
101 else if (vr_conf.vr_id == 0)
103 clib_warning ("VR ID must be > 0");
104 rv = VNET_API_ERROR_INVALID_VALUE;
107 rv = vrrp_vr_add_del (mp->is_add, &vr_conf);
111 BAD_SW_IF_INDEX_LABEL;
112 REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
116 send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
119 vrrp_main_t *vmp = &vrrp_main;
120 vl_api_vrrp_vr_details_t *mp;
121 int n_addrs, msg_size;
122 ip46_address_t *addr;
123 vl_api_address_t *api_addr;
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);
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;
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);
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;
150 mp->config.flags = htonl (api_flags);
153 switch (vr->runtime.state)
155 case VRRP_VR_STATE_INIT:
156 mp->runtime.state = htonl (VRRP_API_VR_STATE_INIT);
158 case VRRP_VR_STATE_BACKUP:
159 mp->runtime.state = htonl (VRRP_API_VR_STATE_BACKUP);
161 case VRRP_VR_STATE_MASTER:
162 mp->runtime.state = htonl (VRRP_API_VR_STATE_MASTER);
164 case VRRP_VR_STATE_INTF_DOWN:
165 mp->runtime.state = htonl (VRRP_API_VR_STATE_INTF_DOWN);
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));
176 mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
177 mp->runtime.tracking.priority = vrrp_vr_priority (vr);
180 mp->n_addrs = vec_len (vr->config.vr_addrs);
181 api_addr = mp->addrs;
182 vec_foreach (addr, vr->config.vr_addrs)
187 if (vrrp_vr_is_ipv6 (vr))
189 api_addr->af = ADDRESS_IP6;
190 dst = &api_addr->un.ip6;
192 len = sizeof (addr->ip6);
196 api_addr->af = ADDRESS_IP4;
197 dst = &api_addr->un.ip4;
199 len = sizeof (addr->ip4);
201 clib_memcpy (dst, src, len);
205 vl_api_send_msg (reg, (u8 *) mp);
209 vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
211 vrrp_main_t *vmp = &vrrp_main;
212 vl_api_registration_t *reg;
216 reg = vl_api_client_index_to_registration (mp->client_index);
220 sw_if_index = htonl (mp->sw_if_index);
223 pool_foreach (vr, vmp->vrs, ({
225 if (sw_if_index && (sw_if_index != ~0) &&
226 (sw_if_index != vr->config.sw_if_index))
229 send_vrrp_vr_details (vr, reg, mp->context);
235 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
237 vrrp_main_t *vmp = &vrrp_main;
238 vl_api_vrrp_vr_start_stop_reply_t *rmp;
239 vrrp_vr_key_t vr_key;
242 clib_memset (&vr_key, 0, sizeof (vr_key));
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);
248 rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
250 REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
254 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
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;
263 clib_memset (&vr_key, 0, sizeof (vr_key));
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);
269 for (i = 0; i < mp->n_addrs; i++)
271 ip46_address_t *peer;
273 vec_add2 (peer_addrs, peer, 1);
276 clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
278 clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
281 rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
283 vec_free (peer_addrs);
284 REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
288 send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
291 vrrp_main_t *vmp = &vrrp_main;
292 vl_api_vrrp_vr_peer_details_t *mp;
293 int n_addrs, msg_size;
294 ip46_address_t *addr;
295 vl_api_address_t *api_addr;
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);
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;
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);
311 mp->n_peer_addrs = n_addrs;
312 api_addr = mp->peer_addrs;
313 vec_foreach (addr, vr->config.peer_addrs)
318 if (vrrp_vr_is_ipv6 (vr))
320 api_addr->af = ADDRESS_IP6;
321 dst = &api_addr->un.ip6;
323 len = sizeof (addr->ip6);
327 api_addr->af = ADDRESS_IP4;
328 dst = &api_addr->un.ip4;
330 len = sizeof (addr->ip4);
332 clib_memcpy (dst, src, len);
336 vl_api_send_msg (reg, (u8 *) mp);
340 vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
342 vrrp_main_t *vmp = &vrrp_main;
343 vl_api_registration_t *reg;
345 vrrp_vr_key_t vr_key;
347 reg = vl_api_client_index_to_registration (mp->client_index);
351 vr_key.sw_if_index = ntohl (mp->sw_if_index);
353 if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
358 vr_key.vr_id = mp->vr_id;
359 vr_key.is_ipv6 = mp->is_ipv6;
361 p = mhash_get (&vmp->vr_index_by_key, &vr_key);
366 vr = pool_elt_at_index (vmp->vrs, vr_index);
367 send_vrrp_vr_peer_details (vr, reg, mp->context);
373 pool_foreach (vr, vmp->vrs, ({
375 if (!vec_len (vr->config.peer_addrs))
378 send_vrrp_vr_details (vr, reg, mp->context);
385 vl_api_vrrp_vr_track_if_add_del_t_handler
386 (vl_api_vrrp_vr_track_if_add_del_t * mp)
388 vrrp_main_t *vmp = &vrrp_main;
389 vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
391 vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
394 /* lookup VR and return error if it does not exist */
396 vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
399 rv = VNET_API_ERROR_INVALID_VALUE;
403 for (i = 0; i < mp->n_ifs; i++)
405 vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
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;
412 rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
415 vec_free (track_ifs);
416 REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
420 send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
423 vrrp_main_t *vmp = &vrrp_main;
424 vl_api_vrrp_vr_track_if_details_t *mp;
426 vl_api_vrrp_vr_track_if_t *api_track_if;
427 vrrp_vr_tracking_if_t *track_if;
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);
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;
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);
445 /* tracked interfaces */
447 api_track_if = mp->ifs;
448 vec_foreach (track_if, vr->tracking.interfaces)
450 api_track_if->sw_if_index = htonl (track_if->sw_if_index);
451 api_track_if->priority = track_if->priority;
455 vl_api_send_msg (reg, (u8 *) mp);
459 vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
461 vrrp_main_t *vmp = &vrrp_main;
462 vl_api_registration_t *reg;
465 reg = vl_api_client_index_to_registration (mp->client_index);
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);
478 pool_foreach (vr, vmp->vrs, ({
480 if (!vec_len (vr->tracking.interfaces))
483 send_vrrp_vr_track_if_details (vr, reg, mp->context);
489 /* Set up the API message handling tables */
490 #include <vrrp/vrrp.api.c>
492 vrrp_plugin_api_hookup (vlib_main_t * vm)
494 vrrp_main_t *vmp = &vrrp_main;
496 /* Ask for a correctly-sized block of API message decode slots */
497 vmp->msg_id_base = setup_message_id_table ();
505 * fd.io coding-style-patch-verification: ON
508 * eval: (c-set-style "gnu")