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 <mgsmith@netgate.com>
This commit is contained in:

committed by
Dave Barach

parent
f75defa767
commit
39e9428b90
@ -649,6 +649,11 @@ Awkward chained buffer geometry tool
|
||||
I: oddbuf
|
||||
F: src/plugins/oddbuf
|
||||
|
||||
Plugin - VRRP
|
||||
I: vrrp
|
||||
M: Matthew Smith <mgsmith@netgate.com>
|
||||
F: src/plugins/vrrp
|
||||
|
||||
VPP Config Tooling
|
||||
I: vpp_config
|
||||
M: John DeNisco <jdenisco@cisco.com>
|
||||
|
28
src/plugins/vrrp/CMakeLists.txt
Normal file
28
src/plugins/vrrp/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
add_vpp_plugin(vrrp
|
||||
SOURCES
|
||||
vrrp.c
|
||||
vrrp_api.c
|
||||
vrrp_cli.c
|
||||
vrrp_format.c
|
||||
node.c
|
||||
vrrp_packet.c
|
||||
vrrp_periodic.c
|
||||
|
||||
MULTIARCH_SOURCES
|
||||
node.c
|
||||
|
||||
API_FILES
|
||||
vrrp.api
|
||||
|
||||
INSTALL_HEADERS
|
||||
vrrp.h
|
||||
|
||||
API_TEST_SOURCES
|
||||
vrrp_test.c
|
||||
)
|
23
src/plugins/vrrp/FEATURE.yaml
Normal file
23
src/plugins/vrrp/FEATURE.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Virtual Router Redundancy Protocol
|
||||
maintainer: Matthew Smith <mgsmith@netgate.com>
|
||||
features:
|
||||
- VRRPv3 (RFC 5798) for IPv4 and IPv6:
|
||||
- Signaling/advertisements and election of a master
|
||||
- Replies to ARP, NS requests for virtual router addresses
|
||||
- VRRP virtual MAC address support:
|
||||
- DPDK interfaces with PMD support for multiple MAC addresses via the
|
||||
rte_eth_dev_mac_addr_add(), rte_eth_dev_mac_addr_del()
|
||||
- Other interfaces which are set in promiscuous mode may work
|
||||
- Support interface types for VRRP virtual routers:
|
||||
- Hardware interfaces
|
||||
- VLAN subinterfaces
|
||||
- Bond interfaces
|
||||
- Additional features not specified in RFC 5798:
|
||||
- Allows sending advertisements to unicast peers instead of multicast
|
||||
- Allows a virtual router's priority to be adjusted based on the state
|
||||
of an upstream interface. Mentioned as a configuration option to
|
||||
"track interfaces or networks" in RFC 8347.
|
||||
description: "Virtual Router Redundancy Protocol implementation (VRRPv3)"
|
||||
state: production
|
||||
properties: [API, CLI, STATS, MULTITHREAD]
|
753
src/plugins/vrrp/node.c
Normal file
753
src/plugins/vrrp/node.c
Normal file
File diff suppressed because it is too large
Load Diff
20
src/plugins/vrrp/setup.pg
Normal file
20
src/plugins/vrrp/setup.pg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
comment { simple debug CLI setup script w/ packet generator test vector }
|
||||
set term page off
|
||||
loop create
|
||||
set int ip address loop0 192.168.1.1/24
|
||||
set int state loop0 up
|
||||
|
||||
comment { Packet generator script. Src MAC 00:de:ad:be:ef:01 }
|
||||
comment { Dst mac 01:ba:db:ab:be:01 ethtype 0800 }
|
||||
packet-generator new {
|
||||
name simple
|
||||
limit 1
|
||||
size 128-128
|
||||
interface loop0
|
||||
node vrrp
|
||||
data {
|
||||
hex 0x00deadbeef0001badbabbe010800
|
||||
incrementing 30
|
||||
}
|
||||
}
|
1288
src/plugins/vrrp/test/test_vrrp.py
Normal file
1288
src/plugins/vrrp/test/test_vrrp.py
Normal file
File diff suppressed because it is too large
Load Diff
245
src/plugins/vrrp/vrrp.api
Normal file
245
src/plugins/vrrp/vrrp.api
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
option version = "1.0.0";
|
||||
|
||||
import "vnet/interface_types.api";
|
||||
import "vnet/ip/ip_types.api";
|
||||
import "vnet/ethernet/ethernet_types.api";
|
||||
|
||||
typedef vrrp_vr_key
|
||||
{
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 is_ipv6;
|
||||
};
|
||||
|
||||
enum vrrp_vr_flags
|
||||
{
|
||||
VRRP_API_VR_PREEMPT = 0x1,
|
||||
VRRP_API_VR_ACCEPT = 0x2,
|
||||
VRRP_API_VR_UNICAST = 0x4,
|
||||
VRRP_API_VR_IPV6 = 0x8,
|
||||
};
|
||||
|
||||
typedef vrrp_vr_conf
|
||||
{
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 priority;
|
||||
u16 interval;
|
||||
vl_api_vrrp_vr_flags_t flags;
|
||||
};
|
||||
|
||||
/** \brief VRRP: Add or delete a VRRP virtual router
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param is_add - 0 if deleting, != 0 if adding
|
||||
@param sw_if_index - interface backed up by this vr
|
||||
@param vr_id - the VR ID advertised by this vr
|
||||
@param priority - the priority advertised for this vr
|
||||
@param interval - interval between advertisements in centiseconds
|
||||
@param flags - bit flags for booleans - preempt, accept, unicast, ipv6
|
||||
@param n_addrs - number of addresses being backed up by this vr
|
||||
@param addrs - the addresses backed up by this vr
|
||||
*/
|
||||
autoreply define vrrp_vr_add_del {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u8 is_add;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 priority;
|
||||
u16 interval;
|
||||
vl_api_vrrp_vr_flags_t flags;
|
||||
u8 n_addrs;
|
||||
vl_api_address_t addrs[n_addrs];
|
||||
};
|
||||
|
||||
/** \brief VRRP: dump virtual router data
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface to use as filter (0,~0 == "all")
|
||||
*/
|
||||
define vrrp_vr_dump {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
enum vrrp_vr_state
|
||||
{
|
||||
VRRP_API_VR_STATE_INIT = 0,
|
||||
VRRP_API_VR_STATE_BACKUP,
|
||||
VRRP_API_VR_STATE_MASTER,
|
||||
VRRP_API_VR_STATE_INTF_DOWN,
|
||||
};
|
||||
|
||||
typedef vrrp_vr_tracking
|
||||
{
|
||||
u32 interfaces_dec;
|
||||
u8 priority;
|
||||
};
|
||||
|
||||
typedef vrrp_vr_runtime
|
||||
{
|
||||
vl_api_vrrp_vr_state_t state;
|
||||
u16 master_adv_int;
|
||||
u16 skew;
|
||||
u16 master_down_int;
|
||||
vl_api_mac_address_t mac;
|
||||
vl_api_vrrp_vr_tracking_t tracking;
|
||||
};
|
||||
|
||||
/** \brief VRRP: VR dump response
|
||||
@param context - sender context which was passed in the request
|
||||
@param conf - configuration parameters for the VR
|
||||
@param runtime - runtime state for the VR
|
||||
*/
|
||||
define vrrp_vr_details {
|
||||
u32 context;
|
||||
vl_api_vrrp_vr_conf_t config;
|
||||
vl_api_vrrp_vr_runtime_t runtime;
|
||||
u8 n_addrs;
|
||||
vl_api_address_t addrs[n_addrs];
|
||||
};
|
||||
|
||||
/** \brief VRRP: start or shutdown the VRRP protocol for a virtual router
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface ID that VR is backing up
|
||||
@param vr_id - VR ID
|
||||
@param is_ipv6 - 1 for IPv6, 0 for IPv4
|
||||
@param is_start - 1 to start VRRP proto on this VR, 0 to shutdown
|
||||
*/
|
||||
autoreply define vrrp_vr_start_stop {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 is_ipv6;
|
||||
u8 is_start;
|
||||
};
|
||||
|
||||
/** \brief VRRP: set unicast peers for a VR
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface ID that VR is backing up
|
||||
@param vr_id - VR ID
|
||||
@param is_ipv6 - 1 for IPv6, 0 for IPv4
|
||||
@param n_addrs - number of peer addresses
|
||||
@param addrs - peer addresses
|
||||
*/
|
||||
autoreply define vrrp_vr_set_peers {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 is_ipv6;
|
||||
u8 n_addrs;
|
||||
vl_api_address_t addrs[n_addrs];
|
||||
};
|
||||
|
||||
/** \brief VRRP: dump virtual router peer address data
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface (0,~0 == "all" -> ignore is_ipv6 & vr_id))
|
||||
@param is_ipv6 - 0 -> IPv4, 1 -> IPv6
|
||||
@param vr_id - ID of VR to dump
|
||||
*/
|
||||
define vrrp_vr_peer_dump {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 is_ipv6;
|
||||
u8 vr_id;
|
||||
};
|
||||
|
||||
/** \brief VRRP: VR peer dump response
|
||||
@param context - sender context which was passed in the request
|
||||
@param sw_if_index - interface index
|
||||
@param is_ipv6 - 0 -> IPv4, 1 -> IPv6
|
||||
@param vr_id - ID of VR
|
||||
@param n_peer_addrs - number of peer addresses
|
||||
@param peer_addrs - peer addresses
|
||||
*/
|
||||
autoreply define vrrp_vr_peer_details {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 is_ipv6;
|
||||
u8 n_peer_addrs;
|
||||
vl_api_address_t peer_addrs[n_peer_addrs];
|
||||
};
|
||||
|
||||
/** \brief VR interface tracking
|
||||
@param sw_if_index - the interface index to track (not the VR sw_if_index)
|
||||
@param priority - the adjustment to VR priority if intf is down
|
||||
*/
|
||||
typedef vrrp_vr_track_if
|
||||
{
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 priority;
|
||||
};
|
||||
|
||||
/** \brief VRRP: Add/delete VR priority tracking of interface status
|
||||
@param context - sender context which was passed in the request
|
||||
@param sw_if_index - interface index
|
||||
@param is_ipv6 - 0 -> IPv4, 1 -> IPv6
|
||||
@param vr_id - ID of VR
|
||||
@param is_add - 0 -> delete, 1 -> add
|
||||
@param n_ifs - number of interface tracking records
|
||||
@param ifs - array of interface tracking records
|
||||
*/
|
||||
autoreply define vrrp_vr_track_if_add_del
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 is_ipv6;
|
||||
u8 vr_id;
|
||||
u8 is_add;
|
||||
u8 n_ifs;
|
||||
vl_api_vrrp_vr_track_if_t ifs[n_ifs];
|
||||
};
|
||||
|
||||
/** \brief VRRP: dump virtual router interface tracking data
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface
|
||||
@param is_ipv6 - 0 -> IPv4, 1 -> IPv6
|
||||
@param vr_id - ID of VR to dump
|
||||
@param dump_all - dump all VR interface tracking, ignore other fields
|
||||
*/
|
||||
define vrrp_vr_track_if_dump {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 is_ipv6;
|
||||
u8 vr_id;
|
||||
u8 dump_all;
|
||||
};
|
||||
|
||||
/** \brief VRRP: VR interface tracking dump response
|
||||
@param context - sender context which was passed in the request
|
||||
@param sw_if_index - interface index
|
||||
@param is_ipv6 - 0 -> IPv4, 1 -> IPv6
|
||||
@param vr_id - ID of VR
|
||||
@param n_ifs - number of tracked interfaces
|
||||
@param ifs - array of tracked interface data
|
||||
*/
|
||||
autoreply define vrrp_vr_track_if_details {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u8 vr_id;
|
||||
u8 is_ipv6;
|
||||
u8 n_ifs;
|
||||
vl_api_vrrp_vr_track_if_t ifs[n_ifs];
|
||||
};
|
||||
|
1240
src/plugins/vrrp/vrrp.c
Normal file
1240
src/plugins/vrrp/vrrp.c
Normal file
File diff suppressed because it is too large
Load Diff
373
src/plugins/vrrp/vrrp.h
Normal file
373
src/plugins/vrrp/vrrp.h
Normal file
File diff suppressed because it is too large
Load Diff
11
src/plugins/vrrp/vrrp_all_api_h.h
Normal file
11
src/plugins/vrrp/vrrp_all_api_h.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
/*
|
||||
* vrrp_all_api_h.h - vrrp plug-in api #include file
|
||||
*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
/* Include the generated file, see BUILT_SOURCES in Makefile.am */
|
||||
#include <vrrp/vrrp.api.h>
|
501
src/plugins/vrrp/vrrp_api.c
Normal file
501
src/plugins/vrrp/vrrp_api.c
Normal file
File diff suppressed because it is too large
Load Diff
507
src/plugins/vrrp/vrrp_cli.c
Normal file
507
src/plugins/vrrp/vrrp_cli.c
Normal file
File diff suppressed because it is too large
Load Diff
146
src/plugins/vrrp/vrrp_format.c
Normal file
146
src/plugins/vrrp/vrrp_format.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/interface.h>
|
||||
|
||||
#include <plugins/vrrp/vrrp.h>
|
||||
#include <plugins/vrrp/vrrp_packet.h>
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr_flags (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_vr_flags_t flags = va_arg (*args, vrrp_vr_flags_t);
|
||||
|
||||
s = format (s, "preempt %s accept %s unicast %s",
|
||||
(flags & VRRP_VR_PREEMPT) ? "yes" : "no",
|
||||
(flags & VRRP_VR_ACCEPT) ? "yes" : "no",
|
||||
(flags & VRRP_VR_UNICAST) ? "yes" : "no");
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr_addrs (u8 * s, va_list * args)
|
||||
{
|
||||
int is_ipv6 = va_arg (*args, int);
|
||||
ip46_address_t *addrs = va_arg (*args, ip46_address_t *);
|
||||
ip46_address_t *addr;
|
||||
|
||||
vec_foreach (addr, addrs)
|
||||
{
|
||||
s = format (s, "%U ",
|
||||
(is_ipv6) ? format_ip6_address : format_ip4_address,
|
||||
(is_ipv6) ? (u8 *) & addr->ip6 : (u8 *) & addr->ip4);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr_state (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_vr_state_t state = va_arg (*args, vrrp_vr_state_t);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
#define _(v,f,n) case VRRP_VR_STATE_##f: s = format (s, n); break;
|
||||
foreach_vrrp_vr_state
|
||||
#undef _
|
||||
default:
|
||||
s = format (s, "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr_key (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
vrrp_vr_t *vr = va_arg (*args, vrrp_vr_t *);
|
||||
vrrp_vr_config_t *vrc = &vr->config;
|
||||
|
||||
s = format (s, "[%d] sw_if_index %u VR ID %u IPv%d",
|
||||
vr - vmp->vrs, vrc->sw_if_index,
|
||||
vrc->vr_id, (vrc->flags & VRRP_VR_IPV6) ? 6 : 4);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr_track_ifs (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_vr_tracking_if_t *track_ifs = va_arg (*args, vrrp_vr_tracking_if_t *);
|
||||
vrrp_vr_tracking_if_t *track_if;
|
||||
|
||||
vec_foreach (track_if, track_ifs)
|
||||
s = format (s, "sw_if_index %u priority %u ",
|
||||
track_if->sw_if_index, track_if->priority);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_vr (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_vr_t *vr = va_arg (*args, vrrp_vr_t *);
|
||||
|
||||
s = format (s, "%U\n", format_vrrp_vr_key, vr);
|
||||
|
||||
s = format (s, " state %U flags: %U\n",
|
||||
format_vrrp_vr_state, vr->runtime.state,
|
||||
format_vrrp_vr_flags, vr->config.flags);
|
||||
s = format (s, " priority: configured %u adjusted %u\n",
|
||||
vr->config.priority, vrrp_vr_priority (vr));
|
||||
s = format (s, " timers: adv interval %u "
|
||||
"master adv %u skew %u master down %u\n",
|
||||
vr->config.adv_interval, vr->runtime.master_adv_int,
|
||||
vr->runtime.skew, vr->runtime.master_down_int);
|
||||
|
||||
s = format (s, " virtual MAC %U\n", format_ethernet_address,
|
||||
&vr->runtime.mac);
|
||||
|
||||
s = format (s, " addresses %U\n", format_vrrp_vr_addrs,
|
||||
(vr->config.flags & VRRP_VR_IPV6) != 0, vr->config.vr_addrs);
|
||||
|
||||
s = format (s, " peer addresses %U\n", format_vrrp_vr_addrs,
|
||||
(vr->config.flags & VRRP_VR_IPV6) != 0, vr->config.peer_addrs);
|
||||
|
||||
s = format (s, " tracked interfaces %U\n", format_vrrp_vr_track_ifs,
|
||||
vr->tracking.interfaces);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
u8 *
|
||||
format_vrrp_packet_hdr (u8 * s, va_list * args)
|
||||
{
|
||||
vrrp_header_t *pkt = va_arg (*args, vrrp_header_t *);
|
||||
u32 version = pkt->vrrp_version_and_type >> 4;
|
||||
|
||||
s = format (s, "ver %u, type %u, VRID %u, prio %u, "
|
||||
"n_addrs %u, interval %u%ss, csum 0x%x",
|
||||
version, pkt->vrrp_version_and_type & 0xf,
|
||||
pkt->vr_id, pkt->priority, pkt->n_addrs,
|
||||
clib_net_to_host_u16 (pkt->rsvd_and_max_adv_int),
|
||||
(version == 3) ? "c" : "", pkt->checksum);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
23
src/plugins/vrrp/vrrp_msg_enum.h
Normal file
23
src/plugins/vrrp/vrrp_msg_enum.h
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
/*
|
||||
* vrrp_msg_enum.h - vrrp plug-in message enumeration
|
||||
*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
#ifndef included_vrrp_msg_enum_h
|
||||
#define included_vrrp_msg_enum_h
|
||||
|
||||
#include <vppinfra/byte_order.h>
|
||||
|
||||
#define vl_msg_id(n,h) n,
|
||||
typedef enum {
|
||||
#include <vrrp/vrrp_all_api_h.h>
|
||||
/* We'll want to know how many messages IDs we need... */
|
||||
VL_MSG_FIRST_AVAILABLE,
|
||||
} vl_msg_id_t;
|
||||
#undef vl_msg_id
|
||||
|
||||
#endif /* included_vrrp_msg_enum_h */
|
735
src/plugins/vrrp/vrrp_packet.c
Normal file
735
src/plugins/vrrp/vrrp_packet.c
Normal file
File diff suppressed because it is too large
Load Diff
58
src/plugins/vrrp/vrrp_packet.h
Normal file
58
src/plugins/vrrp/vrrp_packet.h
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
/*
|
||||
* vrrp_packet.h - vrrp protocol/packet definitions
|
||||
*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
#ifndef __included_vrrp_packet_h__
|
||||
#define __included_vrrp_packet_h__
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
|
||||
typedef CLIB_PACKED (struct
|
||||
{
|
||||
/* 4 bits for version (always 2 or 3), 4 bits for type (always 1) */
|
||||
u8 vrrp_version_and_type;
|
||||
/* VR ID */
|
||||
u8 vr_id;
|
||||
/* priority of sender on this VR. value of 0 means a master is abdicating */
|
||||
u8 priority;
|
||||
/* count of addresses being backed up by the VR */
|
||||
u8 n_addrs;
|
||||
/* max advertisement interval - first 4 bits are reserved and must be 0 */
|
||||
u16 rsvd_and_max_adv_int;
|
||||
/* checksum */
|
||||
u16 checksum;
|
||||
}) vrrp_header_t;
|
||||
|
||||
typedef CLIB_PACKED (struct
|
||||
{
|
||||
ip4_header_t ip4; vrrp_header_t vrrp;
|
||||
}) ip4_and_vrrp_header_t;
|
||||
|
||||
typedef CLIB_PACKED (struct
|
||||
{
|
||||
ip6_header_t ip6; vrrp_header_t vrrp;
|
||||
}) ip6_and_vrrp_header_t;
|
||||
|
||||
/* the high 4 bits of the advertisement interval are "reserved" and
|
||||
* should be ignored on reception. swap byte order and mask out those bits.
|
||||
*/
|
||||
always_inline u16
|
||||
vrrp_adv_int_from_packet (vrrp_header_t * pkt)
|
||||
{
|
||||
return clib_net_to_host_u16 (pkt->rsvd_and_max_adv_int) & ((u16) 0x0fff);
|
||||
}
|
||||
|
||||
#endif /* __included_vrrp_packet_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
228
src/plugins/vrrp/vrrp_periodic.c
Normal file
228
src/plugins/vrrp/vrrp_periodic.c
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* vrrp_periodic.c - vrrp plug-in periodic function
|
||||
*
|
||||
* Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vlib/vlib.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vrrp/vrrp.h>
|
||||
#include <vrrp/vrrp_packet.h>
|
||||
|
||||
static int
|
||||
vrrp_vr_timer_compare (const void *v1, const void *v2)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
const u32 *idx1, *idx2;
|
||||
vrrp_vr_timer_t *timer1, *timer2;
|
||||
|
||||
idx1 = v1;
|
||||
idx2 = v2;
|
||||
|
||||
timer1 = pool_elt_at_index (vmp->vr_timers, *idx1);
|
||||
timer2 = pool_elt_at_index (vmp->vr_timers, *idx2);
|
||||
|
||||
/* don't check equality, they are unlikely to be exactly equal and
|
||||
* if it occurs, it won't matter what order they were in.
|
||||
* sort the list in reverse so we can pick the next timer off the end */
|
||||
if (timer1->expire_time > timer2->expire_time)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32
|
||||
vrrp_vr_timer_get_next (void)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
int n_timers;
|
||||
|
||||
n_timers = vec_len (vmp->pending_timers);
|
||||
|
||||
if (!n_timers)
|
||||
return ~0;
|
||||
|
||||
return vec_elt (vmp->pending_timers, n_timers - 1);
|
||||
}
|
||||
|
||||
/* cancel an existing timer. This could happen because:
|
||||
* - adv timer expired on master. another adv should be scheduled.
|
||||
* - a shutdown event is received
|
||||
* - a master is preempted by a higher priority master
|
||||
* - adv received on backup. master down timer should be rescheduled.
|
||||
*/
|
||||
void
|
||||
vrrp_vr_timer_cancel (vrrp_vr_t * vr)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
u32 *t;
|
||||
|
||||
/* don't search for a timer that was already canceled or never set */
|
||||
if (vr->runtime.timer_index == ~0)
|
||||
return;
|
||||
|
||||
/* timers stored in descending order, start at the end of the list */
|
||||
/* vec_foreach_backwards does not deal with 0 pointers, check first */
|
||||
if (vmp->pending_timers)
|
||||
vec_foreach_backwards (t, vmp->pending_timers)
|
||||
{
|
||||
if (*t == vr->runtime.timer_index)
|
||||
{
|
||||
vec_delete (vmp->pending_timers, 1, t - vmp->pending_timers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pool_is_free_index (vmp->vr_timers, vr->runtime.timer_index))
|
||||
pool_put_index (vmp->vr_timers, vr->runtime.timer_index);
|
||||
|
||||
vr->runtime.timer_index = ~0;
|
||||
|
||||
vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
|
||||
VRRP_EVENT_VR_TIMER_UPDATE, 0);
|
||||
}
|
||||
|
||||
void
|
||||
vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
vrrp_vr_timer_t *timer;
|
||||
f64 now;
|
||||
|
||||
/* Each VR should be waiting on at most 1 timer at any given time.
|
||||
* If there is already a timer set for this VR, cancel it.
|
||||
*/
|
||||
if (vr->runtime.timer_index != ~0)
|
||||
vrrp_vr_timer_cancel (vr);
|
||||
|
||||
pool_get (vmp->vr_timers, timer);
|
||||
vr->runtime.timer_index = timer - vmp->vr_timers;
|
||||
|
||||
timer->vr_index = vr - vmp->vrs;
|
||||
timer->type = type;
|
||||
|
||||
now = vlib_time_now (vm);
|
||||
|
||||
/* RFC 5798 specifies that timers are in centiseconds, so x / 100.0 */
|
||||
switch (type)
|
||||
{
|
||||
case VRRP_VR_TIMER_ADV:
|
||||
timer->expire_time = now + (vr->config.adv_interval / 100.0);
|
||||
break;
|
||||
case VRRP_VR_TIMER_MASTER_DOWN:
|
||||
timer->expire_time = now + (vr->runtime.master_down_int / 100.0);
|
||||
break;
|
||||
default:
|
||||
/* should never reach here */
|
||||
clib_warning ("Unrecognized VRRP timer type (%d)", type);
|
||||
return;
|
||||
}
|
||||
|
||||
vec_add1 (vmp->pending_timers, vr->runtime.timer_index);
|
||||
|
||||
vec_sort_with_function (vmp->pending_timers, vrrp_vr_timer_compare);
|
||||
|
||||
vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
|
||||
VRRP_EVENT_VR_TIMER_UPDATE, 0);
|
||||
}
|
||||
|
||||
void
|
||||
vrrp_vr_timer_timeout (u32 timer_index)
|
||||
{
|
||||
vrrp_main_t *vmp = &vrrp_main;
|
||||
vrrp_vr_timer_t *timer;
|
||||
vrrp_vr_t *vr;
|
||||
|
||||
if (pool_is_free_index (vmp->vr_timers, timer_index))
|
||||
{
|
||||
clib_warning ("Timeout on free timer index %u", timer_index);
|
||||
return;
|
||||
}
|
||||
|
||||
timer = pool_elt_at_index (vmp->vr_timers, timer_index);
|
||||
vr = pool_elt_at_index (vmp->vrs, timer->vr_index);
|
||||
|
||||
switch (timer->type)
|
||||
{
|
||||
case VRRP_VR_TIMER_ADV:
|
||||
vrrp_adv_send (vr, 0);
|
||||
vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
|
||||
break;
|
||||
case VRRP_VR_TIMER_MASTER_DOWN:
|
||||
vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
|
||||
break;
|
||||
default:
|
||||
clib_warning ("Unrecognized timer type %d", timer->type);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uword
|
||||
vrrp_periodic_process (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * rt, vlib_frame_t * f)
|
||||
{
|
||||
vrrp_main_t *pm = &vrrp_main;
|
||||
f64 now;
|
||||
f64 timeout = 10.0;
|
||||
uword *event_data = 0;
|
||||
uword event_type;
|
||||
u32 next_timer = ~0;
|
||||
vrrp_vr_timer_t *timer;
|
||||
|
||||
while (1)
|
||||
{
|
||||
now = vlib_time_now (vm);
|
||||
|
||||
if (next_timer == ~0)
|
||||
{
|
||||
vlib_process_wait_for_event (vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer = pool_elt_at_index (pm->vr_timers, next_timer);
|
||||
timeout = timer->expire_time - now;
|
||||
|
||||
vlib_process_wait_for_event_or_clock (vm, timeout);
|
||||
}
|
||||
|
||||
event_type = vlib_process_get_events (vm, (uword **) & event_data);
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
/* Handle VRRP_EVENT_VR_TIMER_UPDATE */
|
||||
case VRRP_EVENT_VR_TIMER_UPDATE:
|
||||
next_timer = vrrp_vr_timer_get_next ();
|
||||
break;
|
||||
|
||||
/* Handle periodic timeouts */
|
||||
case ~0:
|
||||
vrrp_vr_timer_timeout (next_timer);
|
||||
next_timer = vrrp_vr_timer_get_next ();
|
||||
break;
|
||||
}
|
||||
vec_reset_length (event_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_REGISTER_NODE (vrrp_periodic_node) =
|
||||
{
|
||||
.function = vrrp_periodic_process,
|
||||
.type = VLIB_NODE_TYPE_PROCESS,
|
||||
.name = "vrrp-periodic-process",
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
693
src/plugins/vrrp/vrrp_test.c
Normal file
693
src/plugins/vrrp/vrrp_test.c
Normal file
File diff suppressed because it is too large
Load Diff
35
test/patches/scapy-2.4.3/vrrp.patch
Normal file
35
test/patches/scapy-2.4.3/vrrp.patch
Normal file
@ -0,0 +1,35 @@
|
||||
diff --git a/scapy/layers/vrrp.py b/scapy/layers/vrrp.py
|
||||
index 1b583653..3d6a5923 100644
|
||||
--- a/scapy/layers/vrrp.py
|
||||
+++ b/scapy/layers/vrrp.py
|
||||
@@ -10,7 +10,7 @@ VRRP (Virtual Router Redundancy Protocol).
|
||||
|
||||
from scapy.packet import Packet, bind_layers
|
||||
from scapy.fields import BitField, ByteField, FieldLenField, FieldListField, \
|
||||
- IPField, IntField, XShortField
|
||||
+ IPField, IP6Field, IntField, MultipleTypeField, StrField, XShortField
|
||||
from scapy.compat import chb, orb
|
||||
from scapy.layers.inet import IP, in4_chksum, checksum
|
||||
from scapy.layers.inet6 import IPv6, in6_chksum
|
||||
@@ -62,9 +62,18 @@ class VRRPv3(Packet):
|
||||
BitField("res", 0, 4),
|
||||
BitField("adv", 100, 12),
|
||||
XShortField("chksum", None),
|
||||
- # FIXME: addrlist should also allow IPv6 addresses :/
|
||||
- FieldListField("addrlist", [], IPField("", "0.0.0.0"),
|
||||
- count_from=lambda pkt: pkt.ipcount)]
|
||||
+ MultipleTypeField(
|
||||
+ [
|
||||
+ (FieldListField("addrlist", [], IPField("", "0.0.0.0"),
|
||||
+ count_from=lambda pkt: pkt.ipcount),
|
||||
+ lambda p: isinstance(p.underlayer, IP)),
|
||||
+ (FieldListField("addrlist", [], IP6Field("", "::"),
|
||||
+ count_from=lambda pkt: pkt.ipcount),
|
||||
+ lambda p: isinstance(p.underlayer, IPv6)),
|
||||
+ ],
|
||||
+ StrField("addrlist", "")
|
||||
+ )
|
||||
+ ]
|
||||
|
||||
def post_build(self, p, pay):
|
||||
if self.chksum is None:
|
Reference in New Issue
Block a user