From 39e9428b90bc74d1bb15fc17759c8ef6ad712418 Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Tue, 11 Feb 2020 11:25:32 -0600 Subject: vrrp: add plugin providing vrrp support Type: feature Add a new plugin to support HA using VRRPv3 (RFC 5798). Change-Id: Iaa2c37e6172f8f41e9165f178f44d481f6e247b9 Signed-off-by: Matthew Smith --- src/plugins/vrrp/vrrp_api.c | 501 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 src/plugins/vrrp/vrrp_api.c (limited to 'src/plugins/vrrp/vrrp_api.c') diff --git a/src/plugins/vrrp/vrrp_api.c b/src/plugins/vrrp/vrrp_api.c new file mode 100644 index 00000000000..3b9c256b263 --- /dev/null +++ b/src/plugins/vrrp/vrrp_api.c @@ -0,0 +1,501 @@ +/* + * vrrp.c - vpp vrrp plug-in + * + * Copyright 2019-2020 Rubicon Communications, LLC (Netgate) + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include +#include +#include + +#define REPLY_MSG_ID_BASE vmp->msg_id_base +#include + +/* API message handlers */ +static void +vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_add_del_reply_t *rmp; + vrrp_vr_config_t vr_conf; + u32 api_flags; + ip46_address_t *addrs = 0; + int rv; + + api_flags = htonl (mp->flags); + + clib_memset (&vr_conf, 0, sizeof (vr_conf)); + + vr_conf.sw_if_index = ntohl (mp->sw_if_index); + vr_conf.vr_id = mp->vr_id; + vr_conf.priority = mp->priority; + vr_conf.adv_interval = ntohs (mp->interval); + + if (api_flags & VRRP_API_VR_PREEMPT) + vr_conf.flags |= VRRP_VR_PREEMPT; + + if (api_flags & VRRP_API_VR_ACCEPT) + vr_conf.flags |= VRRP_VR_ACCEPT; + + if (api_flags & VRRP_API_VR_UNICAST) + vr_conf.flags |= VRRP_VR_UNICAST; + + if (api_flags & VRRP_API_VR_IPV6) + vr_conf.flags |= VRRP_VR_IPV6; + + if (mp->is_add) + { + int i; + + for (i = 0; i < mp->n_addrs; i++) + { + ip46_address_t *addr; + void *src, *dst; + int len; + + vec_add2 (addrs, addr, 1); + + if (ntohl (mp->addrs[i].af) == ADDRESS_IP4) + { + src = &mp->addrs[i].un.ip4; + dst = &addr->ip4; + len = sizeof (addr->ip4); + } + else + { + src = &mp->addrs[i].un.ip6; + dst = &addr->ip6; + len = sizeof (addr->ip6); + } + + clib_memcpy (dst, src, len); + } + + vr_conf.vr_addrs = addrs; + } + + if (vr_conf.priority == 0) + { + clib_warning ("VR priority must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else if (vr_conf.adv_interval == 0) + { + clib_warning ("VR advertisement interval must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else if (vr_conf.vr_id == 0) + { + clib_warning ("VR ID must be > 0"); + rv = VNET_API_ERROR_INVALID_VALUE; + } + else + rv = vrrp_vr_add_del (mp->is_add, &vr_conf); + + vec_free (addrs); + + REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY); +} + +static void +send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg, + u32 context) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_details_t *mp; + int n_addrs, msg_size; + ip46_address_t *addr; + vl_api_address_t *api_addr; + u32 api_flags = 0; + + n_addrs = vec_len (vr->config.vr_addrs); + msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr); + mp = vl_msg_api_alloc (msg_size); + if (!mp) + return; + clib_memset (mp, 0, msg_size); + mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base); + mp->context = context; + + /* config */ + mp->config.sw_if_index = htonl (vr->config.sw_if_index); + mp->config.vr_id = vr->config.vr_id; + mp->config.priority = vr->config.priority; + mp->config.interval = htons (vr->config.adv_interval); + + if (vr->config.flags & VRRP_VR_PREEMPT) + api_flags |= VRRP_API_VR_PREEMPT; + if (vr->config.flags & VRRP_VR_ACCEPT) + api_flags |= VRRP_API_VR_ACCEPT; + if (vrrp_vr_is_unicast (vr)) + api_flags |= VRRP_API_VR_UNICAST; + if (vrrp_vr_is_ipv6 (vr)) + api_flags |= VRRP_API_VR_IPV6; + + mp->config.flags = htonl (api_flags); + + /* runtime */ + switch (vr->runtime.state) + { + case VRRP_VR_STATE_INIT: + mp->runtime.state = htonl (VRRP_API_VR_STATE_INIT); + break; + case VRRP_VR_STATE_BACKUP: + mp->runtime.state = htonl (VRRP_API_VR_STATE_BACKUP); + break; + case VRRP_VR_STATE_MASTER: + mp->runtime.state = htonl (VRRP_API_VR_STATE_MASTER); + break; + case VRRP_VR_STATE_INTF_DOWN: + mp->runtime.state = htonl (VRRP_API_VR_STATE_INTF_DOWN); + break; + default: + break; + } + + mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int); + mp->runtime.skew = htons (vr->runtime.skew); + mp->runtime.master_down_int = htons (vr->runtime.master_down_int); + clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac)); + + mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec); + mp->runtime.tracking.priority = vrrp_vr_priority (vr); + + /* addrs */ + mp->n_addrs = vec_len (vr->config.vr_addrs); + api_addr = mp->addrs; + vec_foreach (addr, vr->config.vr_addrs) + { + void *src, *dst; + size_t len; + + if (vrrp_vr_is_ipv6 (vr)) + { + api_addr->af = htonl (ADDRESS_IP6); + dst = &api_addr->un.ip6; + src = &addr->ip6; + len = sizeof (addr->ip6); + } + else + { + api_addr->af = htonl (ADDRESS_IP4); + dst = &api_addr->un.ip4; + src = &addr->ip4; + len = sizeof (addr->ip4); + } + clib_memcpy (dst, src, len); + api_addr++; + } + + vl_api_send_msg (reg, (u8 *) mp); +} + +static void +vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_registration_t *reg; + vrrp_vr_t *vr; + u32 sw_if_index; + + reg = vl_api_client_index_to_registration (mp->client_index); + + sw_if_index = htonl (mp->sw_if_index); + + /* *INDENT-OFF* */ + pool_foreach (vr, vmp->vrs, ({ + + if (sw_if_index && (sw_if_index != ~0) && + (sw_if_index != vr->config.sw_if_index)) + continue; + + send_vrrp_vr_details (vr, reg, mp->context); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_start_stop_reply_t *rmp; + vrrp_vr_key_t vr_key; + int rv; + + clib_memset (&vr_key, 0, sizeof (vr_key)); + + vr_key.sw_if_index = ntohl (mp->sw_if_index); + vr_key.vr_id = mp->vr_id; + vr_key.is_ipv6 = (mp->is_ipv6 != 0); + + rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key); + + REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY); +} + +static void +vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_set_peers_reply_t *rmp; + vrrp_vr_key_t vr_key; + ip46_address_t *peer_addrs = 0; + int i; + int rv; + + clib_memset (&vr_key, 0, sizeof (vr_key)); + + vr_key.sw_if_index = ntohl (mp->sw_if_index); + vr_key.vr_id = mp->vr_id; + vr_key.is_ipv6 = (mp->is_ipv6 != 0); + + for (i = 0; i < mp->n_addrs; i++) + { + ip46_address_t *peer; + + vec_add2 (peer_addrs, peer, 1); + + if (mp->is_ipv6) + clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16); + else + clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4); + } + + rv = vrrp_vr_set_peers (&vr_key, peer_addrs); + + vec_free (peer_addrs); + REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY); +} + +static void +send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg, + u32 context) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_peer_details_t *mp; + int n_addrs, msg_size; + ip46_address_t *addr; + vl_api_address_t *api_addr; + + n_addrs = vec_len (vr->config.peer_addrs); + msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr); + mp = vl_msg_api_alloc (msg_size); + if (!mp) + return; + clib_memset (mp, 0, msg_size); + mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base); + mp->context = context; + + mp->sw_if_index = htonl (vr->config.sw_if_index); + mp->vr_id = vr->config.vr_id; + mp->is_ipv6 = vrrp_vr_is_ipv6 (vr); + + /* addrs */ + mp->n_peer_addrs = n_addrs; + api_addr = mp->peer_addrs; + vec_foreach (addr, vr->config.peer_addrs) + { + void *src, *dst; + size_t len; + + if (vrrp_vr_is_ipv6 (vr)) + { + api_addr->af = htonl (ADDRESS_IP6); + dst = &api_addr->un.ip6; + src = &addr->ip6; + len = sizeof (addr->ip6); + } + else + { + api_addr->af = htonl (ADDRESS_IP4); + dst = &api_addr->un.ip4; + src = &addr->ip4; + len = sizeof (addr->ip4); + } + clib_memcpy (dst, src, len); + api_addr++; + } + + vl_api_send_msg (reg, (u8 *) mp); +} + +static void +vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_registration_t *reg; + vrrp_vr_t *vr; + vrrp_vr_key_t vr_key; + + reg = vl_api_client_index_to_registration (mp->client_index); + + vr_key.sw_if_index = ntohl (mp->sw_if_index); + + if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0)) + { + uword *p; + u32 vr_index = ~0; + + vr_key.vr_id = mp->vr_id; + vr_key.is_ipv6 = mp->is_ipv6; + + p = mhash_get (&vmp->vr_index_by_key, &vr_key); + if (!p) + return; + + vr_index = p[0]; + vr = pool_elt_at_index (vmp->vrs, vr_index); + send_vrrp_vr_peer_details (vr, reg, mp->context); + + return; + } + + /* *INDENT-OFF* */ + pool_foreach (vr, vmp->vrs, ({ + + if (!vec_len (vr->config.peer_addrs)) + continue; + + send_vrrp_vr_details (vr, reg, mp->context); + + })); + /* *INDENT-ON* */ +} + +static void + vl_api_vrrp_vr_track_if_add_del_t_handler + (vl_api_vrrp_vr_track_if_add_del_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_track_if_add_del_reply_t *rmp; + vrrp_vr_t *vr; + vrrp_vr_tracking_if_t *track_if, *track_ifs = 0; + int rv = 0, i; + + /* lookup VR and return error if it does not exist */ + vr = + vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0)); + if (!vr) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + for (i = 0; i < mp->n_ifs; i++) + { + vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i]; + + vec_add2 (track_ifs, track_if, 1); + track_if->sw_if_index = ntohl (api_track_if->sw_if_index); + track_if->priority = api_track_if->priority; + } + + rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0); + +done: + vec_free (track_ifs); + REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY); +} + +static void +send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg, + u32 context) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_vrrp_vr_track_if_details_t *mp; + int n_ifs, msg_size; + vl_api_vrrp_vr_track_if_t *api_track_if; + vrrp_vr_tracking_if_t *track_if; + + if (!vr) + return; + + n_ifs = vec_len (vr->tracking.interfaces); + msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if); + mp = vl_msg_api_alloc (msg_size); + if (!mp) + return; + clib_memset (mp, 0, msg_size); + mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base); + mp->context = context; + + mp->sw_if_index = htonl (vr->config.sw_if_index); + mp->vr_id = vr->config.vr_id; + mp->is_ipv6 = vrrp_vr_is_ipv6 (vr); + + /* tracked interfaces */ + mp->n_ifs = n_ifs; + api_track_if = mp->ifs; + vec_foreach (track_if, vr->tracking.interfaces) + { + api_track_if->sw_if_index = htonl (track_if->sw_if_index); + api_track_if->priority = track_if->priority; + api_track_if += 1; + } + + vl_api_send_msg (reg, (u8 *) mp); +} + +static void +vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp) +{ + vrrp_main_t *vmp = &vrrp_main; + vl_api_registration_t *reg; + vrrp_vr_t *vr; + + reg = vl_api_client_index_to_registration (mp->client_index); + + if (!mp->dump_all) + { + vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6); + send_vrrp_vr_track_if_details (vr, reg, mp->context); + + return; + } + + /* *INDENT-OFF* */ + pool_foreach (vr, vmp->vrs, ({ + + if (!vec_len (vr->tracking.interfaces)) + continue; + + send_vrrp_vr_track_if_details (vr, reg, mp->context); + + })); + /* *INDENT-ON* */ +} + +/* Set up the API message handling tables */ +#include +clib_error_t * +vrrp_plugin_api_hookup (vlib_main_t * vm) +{ + vrrp_main_t *vmp = &vrrp_main; + + /* Ask for a correctly-sized block of API message decode slots */ + vmp->msg_id_base = setup_message_id_table (); + + return 0; +} + +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg