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:
Matthew Smith
2020-02-11 11:25:32 -06:00
committed by Dave Barach
parent f75defa767
commit 39e9428b90
19 changed files with 6912 additions and 0 deletions

View File

@ -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>

View 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
)

View 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

File diff suppressed because it is too large Load Diff

20
src/plugins/vrrp/setup.pg Normal file
View 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
}
}

File diff suppressed because it is too large Load Diff

245
src/plugins/vrrp/vrrp.api Normal file
View 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

File diff suppressed because it is too large Load Diff

373
src/plugins/vrrp/vrrp.h Normal file

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

507
src/plugins/vrrp/vrrp_cli.c Normal file

File diff suppressed because it is too large Load Diff

View 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:
*/

View 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 */

File diff suppressed because it is too large Load Diff

View 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:
*/

View 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:
*/

File diff suppressed because it is too large Load Diff

View 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: