summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c27
-rw-r--r--bgpd/bgp_aspath.h1
-rw-r--r--bgpd/bgp_evpn_vty.c4
-rw-r--r--bgpd/bgp_fsm.c280
-rw-r--r--bgpd/bgp_network.c6
-rw-r--r--bgpd/bgp_route.c17
-rw-r--r--bgpd/bgp_vty.c9
-rw-r--r--bgpd/bgpd.c107
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--doc/user/basic.rst4
-rw-r--r--doc/user/vrrp.rst23
-rw-r--r--lib/if.c9
-rw-r--r--tests/topotests/bgp_confed1/__init__.py0
-rw-r--r--tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json63
-rw-r--r--tests/topotests/bgp_confed1/r1/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_confed1/r1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_confed1/r1/isisd.conf0
-rw-r--r--tests/topotests/bgp_confed1/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json63
-rw-r--r--tests/topotests/bgp_confed1/r2/bgp_summary.json18
-rw-r--r--tests/topotests/bgp_confed1/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_confed1/r2/isisd.conf8
-rw-r--r--tests/topotests/bgp_confed1/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json77
-rw-r--r--tests/topotests/bgp_confed1/r3/bgp_summary.json18
-rw-r--r--tests/topotests/bgp_confed1/r3/bgpd.conf17
-rw-r--r--tests/topotests/bgp_confed1/r3/isisd.conf8
-rw-r--r--tests/topotests/bgp_confed1/r3/zebra.conf10
-rw-r--r--tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json77
-rw-r--r--tests/topotests/bgp_confed1/r4/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_confed1/r4/bgpd.conf14
-rw-r--r--tests/topotests/bgp_confed1/r4/isisd.conf0
-rw-r--r--tests/topotests/bgp_confed1/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_confed1/test_bgp_confed1.py129
-rwxr-xr-xtools/frrcommon.sh.in12
-rw-r--r--vrrpd/vrrp.c19
-rw-r--r--vrrpd/vrrp.h10
-rw-r--r--vrrpd/vrrp_northbound.c27
-rw-r--r--vrrpd/vrrp_packet.c33
-rw-r--r--vrrpd/vrrp_packet.h10
-rw-r--r--vrrpd/vrrp_vty.c40
-rw-r--r--vrrpd/vrrp_vty.h3
-rw-r--r--vtysh/vtysh.c7
-rw-r--r--yang/frr-vrrpd.yang7
-rw-r--r--zebra/if_netlink.c8
-rw-r--r--zebra/interface.c3
-rw-r--r--zebra/interface.h3
-rw-r--r--zebra/irdp_interface.c4
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_gr.c19
-rw-r--r--zebra/zebra_pbr.c27
-rw-r--r--zebra/zebra_pbr.h3
-rw-r--r--zebra/zserv.c14
-rw-r--r--zebra/zserv.h7
54 files changed, 1084 insertions, 247 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 06f6073781..85f09ccf0b 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1187,6 +1187,33 @@ int aspath_loop_check(struct aspath *aspath, as_t asno)
return count;
}
+/* AS path loop check. If aspath contains asno
+ * that is a confed id then return >= 1.
+ */
+int aspath_loop_check_confed(struct aspath *aspath, as_t asno)
+{
+ struct assegment *seg;
+ int count = 0;
+
+ if (aspath == NULL || aspath->segments == NULL)
+ return 0;
+
+ seg = aspath->segments;
+
+ while (seg) {
+ unsigned int i;
+
+ for (i = 0; i < seg->length; i++)
+ if (seg->type != AS_CONFED_SEQUENCE &&
+ seg->type != AS_CONFED_SET && seg->as[i] == asno)
+ count++;
+
+ seg = seg->next;
+ }
+ return count;
+}
+
+
/* When all of AS path is private AS return 1. */
bool aspath_private_as_check(struct aspath *aspath)
{
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 0b58e1adc4..97bc7c0aca 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -111,6 +111,7 @@ extern unsigned int aspath_key_make(const void *p);
extern unsigned int aspath_get_first_as(struct aspath *aspath);
extern unsigned int aspath_get_last_as(struct aspath *aspath);
extern int aspath_loop_check(struct aspath *aspath, as_t asno);
+extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno);
extern bool aspath_private_as_check(struct aspath *aspath);
extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 00545c96ae..c3f648b720 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -2535,6 +2535,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
safi_t safi;
json_object *json_paths = NULL;
struct ethaddr empty_mac = {};
+ struct ipaddr empty_ip = {};
const struct prefix_evpn *evp;
afi = AFI_L2VPN;
@@ -2548,7 +2549,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
return;
}
- build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip);
+ build_evpn_type2_prefix(&p, mac ? mac : &empty_mac,
+ ip ? ip : &empty_ip);
/* See if route exists. Look for both non-sticky and sticky. */
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index fcb7275c34..65de35cbdb 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -61,6 +61,13 @@
DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer));
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer));
+enum bgp_fsm_state_progress {
+ BGP_FSM_FAILURE_AND_DELETE = -2,
+ BGP_FSM_FAILURE = -1,
+ BGP_FSM_SUCCESS = 0,
+ BGP_FSM_SUCCESS_STATE_TRANSFER = 1,
+};
+
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
@@ -99,7 +106,7 @@ static void bgp_holdtime_timer(struct thread *);
static void bgp_delayopen_timer(struct thread *);
/* BGP FSM functions. */
-static int bgp_start(struct peer *);
+static enum bgp_fsm_state_progress bgp_start(struct peer *);
/* Register peer with NHT */
int bgp_peer_reg_with_nht(struct peer *peer)
@@ -1293,7 +1300,8 @@ void bgp_fsm_change_status(struct peer *peer, int status)
* Clearing
* (or Deleted).
*/
- if (!work_queue_is_scheduled(peer->clear_node_queue))
+ if (!work_queue_is_scheduled(peer->clear_node_queue) &&
+ status != Deleted)
BGP_EVENT_ADD(peer, Clearing_Completed);
}
@@ -1341,11 +1349,11 @@ void bgp_fsm_change_status(struct peer *peer, int status)
}
/* Flush the event queue and ensure the peer is shut down */
-static int bgp_clearing_completed(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer)
{
- int rc = bgp_stop(peer);
+ enum bgp_fsm_state_progress rc = bgp_stop(peer);
- if (rc >= 0)
+ if (rc >= BGP_FSM_SUCCESS)
BGP_EVENT_FLUSH(peer);
return rc;
@@ -1353,12 +1361,12 @@ static int bgp_clearing_completed(struct peer *peer)
/* Administrative BGP peer stop event. */
/* May be called multiple times for the same peer */
-int bgp_stop(struct peer *peer)
+enum bgp_fsm_state_progress bgp_stop(struct peer *peer)
{
afi_t afi;
safi_t safi;
char orf_name[BUFSIZ];
- int ret = 0;
+ enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
struct bgp *bgp = peer->bgp;
struct graceful_restart_info *gr_info = NULL;
@@ -1375,7 +1383,7 @@ int bgp_stop(struct peer *peer)
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE_AND_DELETE;
}
/* Can't do this in Clearing; events are used for state transitions */
@@ -1584,7 +1592,7 @@ int bgp_stop(struct peer *peer)
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
peer_delete(peer);
- ret = -1;
+ ret = BGP_FSM_FAILURE_AND_DELETE;
} else {
bgp_peer_conf_if_to_su_update(peer);
}
@@ -1592,7 +1600,7 @@ int bgp_stop(struct peer *peer)
}
/* BGP peer is stoped by the error. */
-static int bgp_stop_with_error(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer)
{
/* Double start timer. */
peer->v_start *= 2;
@@ -1606,16 +1614,16 @@ static int bgp_stop_with_error(struct peer *peer)
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/* something went wrong, send notify and tear down */
-static int bgp_stop_with_notify(struct peer *peer, uint8_t code,
- uint8_t sub_code)
+static enum bgp_fsm_state_progress
+bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code)
{
/* Send notify to remote peer */
bgp_notify_send(peer, code, sub_code);
@@ -1625,13 +1633,13 @@ static int bgp_stop_with_notify(struct peer *peer, uint8_t code,
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Clear start timer value to default. */
peer->v_start = BGP_INIT_START_TIMER;
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/**
@@ -1696,13 +1704,12 @@ static void bgp_connect_check(struct thread *thread)
/* TCP connection open. Next we send open message to remote peer. And
add read thread for reading open message. */
-static int bgp_connect_success(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer)
{
if (peer->fd < 0) {
flog_err(EC_BGP_CONNECT, "%s peer's fd is negative value %d",
__func__, peer->fd);
- bgp_stop(peer);
- return -1;
+ return bgp_stop(peer);
}
if (bgp_getsockname(peer) < 0) {
@@ -1712,7 +1719,7 @@ static int bgp_connect_success(struct peer *peer)
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
bgp_fsm_error_subcode(peer->status));
bgp_writes_on(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
@@ -1734,19 +1741,19 @@ static int bgp_connect_success(struct peer *peer)
/* Send an open message */
bgp_open_send(peer);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* TCP connection open with RFC 4271 optional session attribute DelayOpen flag
* set.
*/
-static int bgp_connect_success_w_delayopen(struct peer *peer)
+static enum bgp_fsm_state_progress
+bgp_connect_success_w_delayopen(struct peer *peer)
{
if (peer->fd < 0) {
flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d",
__func__, peer->fd);
- bgp_stop(peer);
- return -1;
+ return bgp_stop(peer);
}
if (bgp_getsockname(peer) < 0) {
@@ -1756,7 +1763,7 @@ static int bgp_connect_success_w_delayopen(struct peer *peer)
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
bgp_fsm_error_subcode(peer->status));
bgp_writes_on(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
@@ -1787,18 +1794,18 @@ static int bgp_connect_success_w_delayopen(struct peer *peer)
zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds",
peer->host, peer->delayopen);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* TCP connect fail */
-static int bgp_connect_fail(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer)
{
if (peer_dynamic_neighbor_no_nsf(peer)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE_AND_DELETE;
}
/*
@@ -1807,13 +1814,13 @@ static int bgp_connect_fail(struct peer *peer)
*/
bgp_nht_interface_events(peer);
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/* This function is the first starting point of all BGP connection. It
* try to connect to remote peer with non-blocking IO.
*/
-int bgp_start(struct peer *peer)
+enum bgp_fsm_state_progress bgp_start(struct peer *peer)
{
int status;
@@ -1825,7 +1832,7 @@ int bgp_start(struct peer *peer)
"%s [FSM] Unable to get neighbor's IP address, waiting...",
peer->host);
peer->last_reset = PEER_DOWN_NBR_ADDR;
- return -1;
+ return BGP_FSM_FAILURE;
}
if (BGP_PEER_START_SUPPRESSED(peer)) {
@@ -1841,7 +1848,7 @@ int bgp_start(struct peer *peer)
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
peer->last_reset = PEER_DOWN_PFX_COUNT;
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Scrub some information that might be left over from a previous,
@@ -1867,7 +1874,7 @@ int bgp_start(struct peer *peer)
/* If the peer is passive mode, force to move to Active mode. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
BGP_EVENT_ADD(peer, TCP_connection_open_failed);
- return 0;
+ return BGP_FSM_SUCCESS;
}
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
@@ -1877,7 +1884,7 @@ int bgp_start(struct peer *peer)
"%s [FSM] In a VRF that is not initialised yet",
peer->host);
peer->last_reset = PEER_DOWN_VRF_UNINIT;
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Register peer for NHT. If next hop is already resolved, proceed
@@ -1891,7 +1898,7 @@ int bgp_start(struct peer *peer)
peer->host);
peer->last_reset = PEER_DOWN_WAITING_NHT;
BGP_EVENT_ADD(peer, TCP_connection_open_failed);
- return 0;
+ return BGP_FSM_SUCCESS;
}
}
@@ -1926,7 +1933,7 @@ int bgp_start(struct peer *peer)
flog_err(EC_BGP_FSM,
"%s peer's fd is negative value %d", __func__,
peer->fd);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
* - when the socket becomes ready, poll() will signify POLLOUT
@@ -1943,24 +1950,26 @@ int bgp_start(struct peer *peer)
&peer->t_connect_check_w);
break;
}
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Connect retry timer is expired when the peer status is Connect. */
-static int bgp_reconnect(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer)
{
- if (bgp_stop(peer) < 0)
- return -1;
+ enum bgp_fsm_state_progress ret;
+
+ ret = bgp_stop(peer);
+ if (ret < BGP_FSM_SUCCESS)
+ return ret;
/* Send graceful restart capabilty */
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
peer->bgp->peer);
- bgp_start(peer);
- return 0;
+ return bgp_start(peer);
}
-static int bgp_fsm_open(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer)
{
/* If DelayOpen is active, we may still need to send an open message */
if ((peer->status == Connect) || (peer->status == Active))
@@ -1969,12 +1978,12 @@ static int bgp_fsm_open(struct peer *peer)
/* Send keepalive and make keepalive timer */
bgp_keepalive_send(peer);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* FSM error, unexpected event. This is error of BGP connection. So cut the
peer and change to Idle status. */
-static int bgp_fsm_event_error(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_event_error(struct peer *peer)
{
flog_err(EC_BGP_FSM, "%s [FSM] unexpected packet received in state %s",
peer->host, lookup_msg(bgp_status_msg, peer->status, NULL));
@@ -1985,7 +1994,7 @@ static int bgp_fsm_event_error(struct peer *peer)
/* Hold timer expire. This is error of BGP connection. So cut the
peer and change to Idle status. */
-static int bgp_fsm_holdtime_expire(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer)
{
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [FSM] Hold timer expire", peer->host);
@@ -2003,7 +2012,8 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
}
/* RFC 4271 DelayOpenTimer_Expires event */
-static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
+static enum bgp_fsm_state_progress
+bgp_fsm_delayopen_timer_expire(struct peer *peer)
{
/* Stop the DelayOpenTimer */
THREAD_OFF(peer->t_delayopen);
@@ -2014,7 +2024,7 @@ static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
/* Set the HoldTimer to a large value (4 minutes) */
peer->v_holdtime = 245;
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Start the selection deferral timer thread for the specified AFI, SAFI */
@@ -2095,25 +2105,28 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
* Convert peer from stub to full fledged peer, set some timers, and generate
* initial updates.
*/
-static int bgp_establish(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_establish(struct peer *peer)
{
afi_t afi;
safi_t safi;
int nsf_af_count = 0;
- int ret = 0;
+ enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
struct peer *other;
int status;
other = peer->doppelganger;
+ hash_release(peer->bgp->peerhash, peer);
+ if (other)
+ hash_release(peer->bgp->peerhash, other);
+
peer = peer_xfer_conn(peer);
if (!peer) {
flog_err(EC_BGP_CONNECT, "%%Neighbor failed in xfer_conn");
- return -1;
+ return BGP_FSM_FAILURE;
}
if (other == peer)
- ret = 1; /* bgp_establish specific code when xfer_conn
- happens. */
+ ret = BGP_FSM_SUCCESS_STATE_TRANSFER;
/* Reset capability open status flag. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
@@ -2309,7 +2322,6 @@ static int bgp_establish(struct peer *peer)
* the doppelgangers su and this peer's su are the same
* so the hash_release is the same for either.
*/
- hash_release(peer->bgp->peerhash, peer);
(void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
/* Start BFD peer if not already running. */
@@ -2320,21 +2332,21 @@ static int bgp_establish(struct peer *peer)
}
/* Keepalive packet is received. */
-static int bgp_fsm_keepalive(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer *peer)
{
THREAD_OFF(peer->t_holdtime);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Update packet is received. */
-static int bgp_fsm_update(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_update(struct peer *peer)
{
THREAD_OFF(peer->t_holdtime);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* This is empty event. */
-static int bgp_ignore(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_ignore(struct peer *peer)
{
flog_err(
EC_BGP_FSM,
@@ -2343,11 +2355,11 @@ static int bgp_ignore(struct peer *peer)
lookup_msg(bgp_status_msg, peer->status, NULL),
bgp_event_str[peer->last_event],
bgp_event_str[peer->last_major_event], peer->fd);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* This is to handle unexpected events.. */
-static int bgp_fsm_exeption(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_exception(struct peer *peer)
{
flog_err(
EC_BGP_FSM,
@@ -2356,7 +2368,7 @@ static int bgp_fsm_exeption(struct peer *peer)
lookup_msg(bgp_status_msg, peer->status, NULL),
bgp_event_str[peer->last_event],
bgp_event_str[peer->last_major_event], peer->fd);
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops)
@@ -2397,7 +2409,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops)
/* Finite State Machine structure */
static const struct {
- int (*func)(struct peer *);
+ enum bgp_fsm_state_progress (*func)(struct peer *);
enum bgp_fsm_status next_state;
} FSM[BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = {
{
@@ -2428,19 +2440,19 @@ static const struct {
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
{bgp_connect_success_w_delayopen,
Connect}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_connect_fail, Active}, /* TCP_connection_open_failed */
{bgp_connect_fail, Idle}, /* TCP_fatal_error */
{bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_delayopen_timer_expire,
OpenSent}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
+ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Active, */
@@ -2448,97 +2460,97 @@ static const struct {
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
{bgp_connect_success_w_delayopen,
- Active}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
- {bgp_ignore, Active}, /* TCP_connection_open_failed */
- {bgp_fsm_exeption, Idle}, /* TCP_fatal_error */
- {bgp_start, Connect}, /* ConnectRetry_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
+ Active}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_ignore, Active}, /* TCP_connection_open_failed */
+ {bgp_fsm_exception, Idle}, /* TCP_fatal_error */
+ {bgp_start, Connect}, /* ConnectRetry_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_delayopen_timer_expire,
OpenSent}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* OpenSent, */
- {bgp_ignore, OpenSent}, /* BGP_Start */
- {bgp_stop, Idle}, /* BGP_Stop */
- {bgp_stop, Active}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Active}, /* TCP_connection_closed */
- {bgp_stop, Active}, /* TCP_connection_open_failed */
- {bgp_stop, Active}, /* TCP_fatal_error */
- {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
+ {bgp_ignore, OpenSent}, /* BGP_Start */
+ {bgp_stop, Idle}, /* BGP_Stop */
+ {bgp_stop, Active}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Active}, /* TCP_connection_closed */
+ {bgp_stop, Active}, /* TCP_connection_open_failed */
+ {bgp_stop, Active}, /* TCP_fatal_error */
+ {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
{bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */
{bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */
{bgp_fsm_event_error, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* OpenConfirm, */
{bgp_ignore, OpenConfirm}, /* BGP_Start */
- {bgp_stop, Idle}, /* BGP_Stop */
- {bgp_stop, Idle}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
- {bgp_stop, Idle}, /* TCP_connection_open_failed */
- {bgp_stop, Idle}, /* TCP_fatal_error */
- {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Idle}, /* BGP_Stop */
+ {bgp_stop, Idle}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_stop, Idle}, /* TCP_connection_open_failed */
+ {bgp_stop, Idle}, /* TCP_fatal_error */
+ {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Receive_OPEN_message */
{bgp_establish, Established}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
{bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Established, */
{bgp_ignore, Established}, /* BGP_Start */
- {bgp_stop, Clearing}, /* BGP_Stop */
- {bgp_stop, Clearing}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Clearing}, /* TCP_connection_closed */
- {bgp_stop, Clearing}, /* TCP_connection_open_failed */
- {bgp_stop, Clearing}, /* TCP_fatal_error */
- {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Clearing}, /* BGP_Stop */
+ {bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Clearing}, /* TCP_connection_closed */
+ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
+ {bgp_stop, Clearing}, /* TCP_fatal_error */
+ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
{bgp_ignore, Established}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
- {bgp_stop, Clearing}, /* Receive_OPEN_message */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
+ {bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_fsm_keepalive,
Established}, /* Receive_KEEPALIVE_message */
{bgp_fsm_update, Established}, /* Receive_UPDATE_message */
{bgp_stop_with_error,
- Clearing}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ Clearing}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Clearing, */
{bgp_ignore, Clearing}, /* BGP_Start */
- {bgp_stop, Clearing}, /* BGP_Stop */
- {bgp_stop, Clearing}, /* TCP_connection_open */
- {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */
- {bgp_stop, Clearing}, /* TCP_connection_closed */
- {bgp_stop, Clearing}, /* TCP_connection_open_failed */
- {bgp_stop, Clearing}, /* TCP_fatal_error */
- {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
- {bgp_stop, Clearing}, /* Hold_Timer_expired */
- {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
- {bgp_stop, Clearing}, /* DelayOpen_timer_expired */
- {bgp_stop, Clearing}, /* Receive_OPEN_message */
- {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
- {bgp_stop, Clearing}, /* Receive_UPDATE_message */
- {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */
+ {bgp_stop, Clearing}, /* BGP_Stop */
+ {bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Clearing}, /* TCP_connection_closed */
+ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
+ {bgp_stop, Clearing}, /* TCP_fatal_error */
+ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Clearing}, /* Hold_Timer_expired */
+ {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
+ {bgp_stop, Clearing}, /* DelayOpen_timer_expired */
+ {bgp_stop, Clearing}, /* Receive_OPEN_message */
+ {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
+ {bgp_stop, Clearing}, /* Receive_UPDATE_message */
+ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */
{bgp_clearing_completed, Idle}, /* Clearing_Completed */
},
{
@@ -2571,13 +2583,15 @@ void bgp_event(struct thread *thread)
peer = THREAD_ARG(thread);
event = THREAD_VAL(thread);
+ peer_lock(peer);
bgp_event_update(peer, event);
+ peer_unlock(peer);
}
int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
{
enum bgp_fsm_status next;
- int ret = 0;
+ enum bgp_fsm_state_progress ret = 0;
struct peer *other;
int passive_conn = 0;
int dyn_nbr;
@@ -2606,8 +2620,9 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
if (FSM[peer->status - 1][event - 1].func)
ret = (*(FSM[peer->status - 1][event - 1].func))(peer);
- if (ret >= 0) {
- if (ret == 1 && next == Established) {
+ if (ret >= BGP_FSM_SUCCESS) {
+ if (ret == BGP_FSM_SUCCESS_STATE_TRANSFER &&
+ next == Established) {
/* The case when doppelganger swap accurred in
bgp_establish.
Update the peer pointer accordingly */
@@ -2641,7 +2656,8 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
* we need to indicate that the peer was stopped in the return
* code.
*/
- if (!dyn_nbr && !passive_conn && peer->bgp) {
+ if (!dyn_nbr && !passive_conn && peer->bgp &&
+ ret != BGP_FSM_FAILURE_AND_DELETE) {
flog_err(
EC_BGP_FSM,
"%s [FSM] Failure handling event %s in state %s, prior events %s, %s, fd %d",
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index b43f8c8664..7186a50711 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -553,9 +553,7 @@ static void bgp_accept(struct thread *thread)
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
- peer1->as, peer1->as_type, NULL);
- hash_release(peer->bgp->peerhash, peer);
- (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
+ peer1->as, peer1->as_type, NULL, false);
peer_xfer_config(peer, peer1);
bgp_peer_gr_flags_update(peer);
@@ -572,8 +570,6 @@ static void bgp_accept(struct thread *thread)
}
}
- UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
peer->doppelganger = peer1;
peer1->doppelganger = peer;
peer->fd = bgp_sock;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1cf84909ee..427997fe21 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2195,7 +2195,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
/* If we're a CONFED we need to loop check the CONFED ID too */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
- if (aspath_loop_check(piattr->aspath, bgp->confed_id)) {
+ if (aspath_loop_check_confed(piattr->aspath, bgp->confed_id)) {
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
zlog_debug(
"%pBP [Update:SEND] suppress announcement to peer AS %u is AS path.",
@@ -4112,16 +4112,23 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* AS path loop check. */
if (do_loop_check) {
- if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
- (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) &&
- (aspath_loop_check(attr->aspath, bgp->confed_id) >
- allowas_in))) {
+ if (aspath_loop_check(attr->aspath, bgp->as) >
+ peer->allowas_in[afi][safi]) {
peer->stat_pfx_aspath_loop++;
reason = "as-path contains our own AS;";
goto filtered;
}
}
+ /* If we're a CONFED we need to loop check the CONFED ID too */
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && do_loop_check)
+ if (aspath_loop_check_confed(attr->aspath, bgp->confed_id) >
+ peer->allowas_in[afi][safi]) {
+ peer->stat_pfx_aspath_loop++;
+ reason = "as-path contains our own confed AS;";
+ goto filtered;
+ }
+
/* Route reflector originator ID check. If ACCEPT_OWN mechanism is
* enabled, then take care of that too.
*/
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 1f532d4990..7b9400118b 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1960,13 +1960,6 @@ DEFUN (bgp_confederation_peers,
for (i = idx_asn; i < argc; i++) {
as = strtoul(argv[i]->arg, NULL, 10);
-
- if (bgp->as == as) {
- vty_out(vty,
- "%% Local member-AS not allowed in confed peer list\n");
- continue;
- }
-
bgp_confederation_peers_add(bgp, as);
}
return CMD_SUCCESS;
@@ -4685,7 +4678,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
} else {
peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
- NULL);
+ NULL, true);
if (!peer) {
vty_out(vty, "%% BGP failed to create peer\n");
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 12ee96ff45..734e44f252 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -671,7 +671,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
struct peer *peer;
struct listnode *node, *nnode;
- if (bgp->as == as)
+ if (!bgp)
return;
if (bgp_confederation_peers_check(bgp, as))
@@ -687,8 +687,8 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as == as) {
- (void)peer_sort(peer);
peer->local_as = bgp->as;
+ (void)peer_sort(peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(
peer->status)) {
peer->last_reset =
@@ -738,8 +738,8 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as == as) {
- (void)peer_sort(peer);
peer->local_as = bgp->confed_id;
+ (void)peer_sort(peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(
peer->status)) {
peer->last_reset =
@@ -950,6 +950,7 @@ static bool peer_hash_same(const void *p1, const void *p2)
{
const struct peer *peer1 = p1;
const struct peer *peer2 = p2;
+
return (sockunion_same(&peer1->su, &peer2->su)
&& CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE)
== CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE));
@@ -1127,6 +1128,7 @@ static void peer_free(struct peer *peer)
bgp_timer_set(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ thread_cancel_event_ready(bm->master, peer);
FOREACH_AFI_SAFI (afi, safi)
THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!peer->t_write);
@@ -1457,7 +1459,10 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
/* peer flags apply */
peer_dst->flags = peer_src->flags;
-
+ /*
+ * The doppelganger *must* not have a config node stored
+ */
+ UNSET_FLAG(peer_dst->flags, PEER_FLAG_CONFIG_NODE);
peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state;
peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag;
@@ -1613,15 +1618,18 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
struct interface *ifp;
int prev_family;
int peer_addr_updated = 0;
+ struct listnode *node;
+ union sockunion old_su;
+ /*
+ * This function is only ever needed when FRR an interface
+ * based peering, so this simple test will tell us if
+ * we are in an interface based configuration or not
+ */
if (!peer->conf_if)
return;
- /*
- * Our peer structure is stored in the bgp->peerhash
- * release it before we modify anything.
- */
- hash_release(peer->bgp->peerhash, peer);
+ old_su = peer->su;
prev_family = peer->su.sa.sa_family;
if ((ifp = if_lookup_by_name(peer->conf_if, peer->bgp->vrf_id))) {
@@ -1664,9 +1672,48 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
}
/*
- * Since our su changed we need to del/add peer to the peerhash
+ * If they are the same, nothing to do here, move along
*/
- (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
+ if (!sockunion_same(&old_su, &peer->su)) {
+ union sockunion new_su = peer->su;
+ struct bgp *bgp = peer->bgp;
+
+ /*
+ * Our peer structure is stored in the bgp->peerhash
+ * release it before we modify anything in both the
+ * hash and the list. But *only* if the peer
+ * is in the bgp->peerhash as that on deletion
+ * we call bgp_stop which calls this function :(
+ * so on deletion let's remove from the list first
+ * and then do the deletion preventing this from
+ * being added back on the list below when we
+ * fail to remove it up here.
+ */
+
+ /*
+ * listnode_lookup just scans the list
+ * for the peer structure so it's safe
+ * to use without modifying the su
+ */
+ node = listnode_lookup(bgp->peer, peer);
+ if (node) {
+ /*
+ * Let's reset the peer->su release and
+ * reset it and put it back. We have to
+ * do this because hash_release will
+ * scan through looking for a matching
+ * su if needed.
+ */
+ peer->su = old_su;
+ hash_release(peer->bgp->peerhash, peer);
+ listnode_delete(peer->bgp->peer, peer);
+
+ peer->su = new_su;
+ (void)hash_get(peer->bgp->peerhash, peer,
+ hash_alloc_intern);
+ listnode_add_sort(peer->bgp->peer, peer);
+ }
+ }
}
void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi)
@@ -1715,7 +1762,8 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
*/
struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
- int as_type, struct peer_group *group)
+ int as_type, struct peer_group *group,
+ bool config_node)
{
int active;
struct peer *peer;
@@ -1753,6 +1801,10 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
peer = peer_lock(peer); /* bgp peer list reference */
peer->group = group;
listnode_add_sort(bgp->peer, peer);
+
+ if (config_node)
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
(void)hash_get(bgp->peerhash, peer, hash_alloc_intern);
/* Adjust update-group coalesce timer heuristics for # peers. */
@@ -1780,8 +1832,6 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
/* Default configured keepalives count for shutdown rtt command */
peer->rtt_keepalive_conf = 1;
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
/* If 'bgp default <afi>-<safi>' is configured, then activate the
* neighbor for the corresponding address family. IPv4 Unicast is
* the only address family enabled by default without expliict
@@ -1816,6 +1866,7 @@ struct peer *peer_create_accept(struct bgp *bgp)
peer = peer_lock(peer); /* bgp peer list reference */
listnode_add_sort(bgp->peer, peer);
+ (void)hash_get(bgp->peerhash, peer, hash_alloc_intern);
return peer;
}
@@ -1987,7 +2038,8 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
else
local_as = bgp->as;
- peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL);
+ peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL,
+ true);
}
return 0;
@@ -2446,6 +2498,7 @@ int peer_delete(struct peer *peer)
bgp_keepalives_off(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ thread_cancel_event_ready(bm->master, peer);
FOREACH_AFI_SAFI (afi, safi)
THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
@@ -2509,9 +2562,16 @@ int peer_delete(struct peer *peer)
/* Delete from all peer list. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
&& (pn = listnode_lookup(bgp->peer, peer))) {
- peer_unlock(peer); /* bgp peer list reference */
+ /*
+ * Removing from the list node first because
+ * peer_unlock *can* call peer_delete( I know,
+ * I know ). So let's remove it and in
+ * the su recalculate function we'll ensure
+ * it's in there or not.
+ */
list_delete_node(bgp->peer, pn);
hash_release(bgp->peerhash, peer);
+ peer_unlock(peer); /* bgp peer list reference */
}
/* Buffers. */
@@ -2649,6 +2709,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
{
uint32_t flags_tmp;
struct peer *conf;
+ bool config_node = !!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
conf = group->conf;
@@ -2676,6 +2737,9 @@ static void peer_group2peer_config_copy(struct peer_group *group,
SET_FLAG(peer->flags, flags_tmp);
SET_FLAG(peer->flags_invert, conf->flags_invert);
+ if (config_node)
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
/* peer timers apply */
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER)) {
PEER_ATTR_INHERIT(peer, group, holdtime);
@@ -3077,7 +3141,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
}
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, group);
+ group->conf->as_type, group, true);
peer = peer_lock(peer); /* group->peer list reference */
listnode_add(group->peer, peer);
@@ -3099,8 +3163,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
peer_deactivate(peer, afi, safi);
}
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
/* Set up peer's events and timers. */
if (peer_active(peer))
bgp_timer_set(peer);
@@ -3723,8 +3785,10 @@ int bgp_delete(struct bgp *bgp)
for (ALL_LIST_ELEMENTS(bgp->group, node, next, group))
peer_group_delete(group);
- for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer))
+ while (listcount(bgp->peer)) {
+ peer = listnode_head(bgp->peer);
peer_delete(peer);
+ }
if (bgp->peer_self) {
peer_delete(bgp->peer_self);
@@ -3971,7 +4035,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
/* Create peer first; we've already checked group config is valid. */
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, group);
+ group->conf->as_type, group, true);
if (!peer)
return NULL;
@@ -4000,7 +4064,6 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
/* Mark as dynamic, but also as a "config node" for other things to
* work. */
SET_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR);
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
return peer;
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index b7a329fdcd..a75bfdf746 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -2177,8 +2177,10 @@ extern bool peer_active_nego(struct peer *);
extern bool peer_afc_received(struct peer *peer);
extern bool peer_afc_advertised(struct peer *peer);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
-extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
- as_t, as_t, int, struct peer_group *);
+extern struct peer *peer_create(union sockunion *su, const char *conf_if,
+ struct bgp *bgp, as_t local_as, as_t remote_as,
+ int as_type, struct peer_group *group,
+ bool config_node);
extern struct peer *peer_create_accept(struct bgp *);
extern void peer_xfer_config(struct peer *dst, struct peer *src);
extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 7679a377eb..4a64d8f949 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -617,6 +617,10 @@ Terminal Mode Commands
usage is printed sequentially. You can specify the daemon's name to print
only its memory usage.
+.. clicmd:: show motd
+
+ Show current motd banner.
+
.. clicmd:: show history
Dump the vtysh cli history.
diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst
index 44a56f2fca..ef3aebeafa 100644
--- a/doc/user/vrrp.rst
+++ b/doc/user/vrrp.rst
@@ -393,6 +393,11 @@ All interface configuration commands are documented below.
higher priority to take over Master status from the existing Master. Enabled
by default.
+.. clicmd:: vrrp (1-255) checksum-with-ipv4-pseudoheader
+
+ Specify whether VRRPv3 checksum should involve IPv4 pseudoheader. This
+ command should not affect VRRPv2 and IPv6. Enabled by default.
+
.. clicmd:: vrrp (1-255) priority (1-254)
Set the router priority. The router with the highest priority is elected as
@@ -448,7 +453,7 @@ Show commands, global defaults and debugging configuration commands.
zebra
Logs communications with Zebra.
-.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown>
+.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|checksum-with-ipv4-pseudoheader|shutdown>
Configure defaults for new VRRP routers. These values will not affect
already configured VRRP routers, but will be applied to newly configured
@@ -550,3 +555,19 @@ feature instead, explained `here
<https://www.virtuallyghetto.com/2018/04/native-mac-learning-in-vsphere-6-7-removes-the-need-for-promiscuous-mode-for-nested-esxi.html>`_.
Issue reference: https://github.com/FRRouting/frr/issues/5386
+
+
+My router cannot interoperate with branded routers / L3 switches
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FRR includes a pseudoheader when calculating VRRPv3 checksums by default,
+regardless of whether it's IPv4 or IPv6.
+
+Some vendors have different interpretations of `VRRPv3 RFC 5798 #5.2.8
+<https://www.rfc-editor.org/rfc/rfc5798.html#section-5.2.8>`_. In such cases,
+their checksums are calculated with a pseudoheader only when it comes to IPv6.
+
+You need to disable ``checksum-with-ipv4-pseudoheader`` so that FRR computes and
+accepts such checksums.
+
+Issue reference: https://github.com/FRRouting/frr/issues/9951
diff --git a/lib/if.c b/lib/if.c
index 76568071ef..70c0c18141 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -38,6 +38,7 @@
#include "lib/if_clippy.c"
DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
+DEFINE_MTYPE_STATIC(LIB, IFDESC, "Intf Desc");
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
@@ -288,7 +289,7 @@ void if_delete(struct interface **ifp)
if_link_params_free(ptr);
- XFREE(MTYPE_TMP, ptr->desc);
+ XFREE(MTYPE_IFDESC, ptr->desc);
XFREE(MTYPE_IF, ptr);
*ifp = NULL;
@@ -1612,9 +1613,9 @@ static int lib_interface_description_modify(struct nb_cb_modify_args *args)
return NB_OK;
ifp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_IFDESC, ifp->desc);
description = yang_dnode_get_string(args->dnode, NULL);
- ifp->desc = XSTRDUP(MTYPE_TMP, description);
+ ifp->desc = XSTRDUP(MTYPE_IFDESC, description);
return NB_OK;
}
@@ -1627,7 +1628,7 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
ifp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_IFDESC, ifp->desc);
return NB_OK;
}
diff --git a/tests/topotests/bgp_confed1/__init__.py b/tests/topotests/bgp_confed1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/__init__.py
diff --git a/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..d3988eb0e7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json
@@ -0,0 +1,63 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.1",
+ "defaultLocPrf":100,
+ "localAS":100,
+ "routes":{"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.2",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.2",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.2",
+ "path":"300 400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r1/bgp_summary.json b/tests/topotests/bgp_confed1/r1/bgp_summary.json
new file mode 100644
index 0000000000..f999021a20
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgp_summary.json
@@ -0,0 +1,13 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.1",
+ "as":100,
+ "peers":{
+ "192.0.2.2":{
+ "remoteAs": 300,
+ "state": "Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r1/bgpd.conf b/tests/topotests/bgp_confed1/r1/bgpd.conf
new file mode 100644
index 0000000000..8413ef7fc3
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgpd.conf
@@ -0,0 +1,13 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 100
+ no bgp ebgp-requires-policy
+!
+ neighbor 192.0.2.2 remote-as 300
+ address-family ipv4 unicast
+ network 203.0.113.0/28
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confed1/r1/isisd.conf b/tests/topotests/bgp_confed1/r1/isisd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/isisd.conf
diff --git a/tests/topotests/bgp_confed1/r1/zebra.conf b/tests/topotests/bgp_confed1/r1/zebra.conf
new file mode 100644
index 0000000000..5f76e74493
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/zebra.conf
@@ -0,0 +1,6 @@
+interface r1-eth0
+ ip address 192.0.2.1/28
+!
+interface lo
+ ip address 203.0.113.1/28
+!
diff --git a/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..b4a0946072
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json
@@ -0,0 +1,63 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.17",
+ "defaultLocPrf":100,
+ "localAS":200,
+ "routes":{"203.0.113.0/28": [
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.1",
+ "path":"100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.18",
+ "path":"(300)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.18",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.18",
+ "path":"(300) 400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.50",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r2/bgp_summary.json b/tests/topotests/bgp_confed1/r2/bgp_summary.json
new file mode 100644
index 0000000000..c2690a145a
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgp_summary.json
@@ -0,0 +1,18 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.17",
+ "as":200,
+ "peers":{
+ "192.0.2.1":{
+ "remoteAs":100,
+ "state":"Established",
+ "peerState":"OK"
+ },
+ "192.0.2.18":{
+ "remoteAs":300,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf
new file mode 100644
index 0000000000..9f6a9852de
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgpd.conf
@@ -0,0 +1,18 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 200
+ no bgp ebgp-requires-policy
+ bgp confederation identifier 300
+ bgp confederation peers 300
+ neighbor 192.0.2.1 remote-as 100
+ neighbor 192.0.2.18 remote-as 300
+ !
+ address-family ipv4 unicast
+ network 203.0.113.16/28
+ neighbor 192.0.2.18 default-originate
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_confed1/r2/isisd.conf b/tests/topotests/bgp_confed1/r2/isisd.conf
new file mode 100644
index 0000000000..135bb00a83
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/isisd.conf
@@ -0,0 +1,8 @@
+interface r2-eth1
+ ip router isis 1
+ isis circuit-type level-2-only
+
+router isis 1
+ is-type level-2-only
+ net 49.0001.0002.0002.0002.00
+ redistribute ipv4 connected level-2
diff --git a/tests/topotests/bgp_confed1/r2/zebra.conf b/tests/topotests/bgp_confed1/r2/zebra.conf
new file mode 100644
index 0000000000..85ebe9ee02
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/zebra.conf
@@ -0,0 +1,9 @@
+interface r2-eth0
+ ip address 192.0.2.2/28
+!
+interface r2-eth1
+ ip address 192.0.2.17/28
+!
+interface lo
+ ip address 203.0.113.17/28
+!
diff --git a/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..a263a9f4a7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json
@@ -0,0 +1,77 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.33",
+ "defaultLocPrf":100,
+ "localAS":300,
+ "routes":{"0.0.0.0/0":[
+ {
+ "network":"0.0.0.0\/0",
+ "peerId":"192.0.2.17",
+ "path":"(200)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.17",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.17",
+ "path":"(200) 100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.17",
+ "path":"(200)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.17",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.50",
+ "path":"400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.50",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r3/bgp_summary.json b/tests/topotests/bgp_confed1/r3/bgp_summary.json
new file mode 100644
index 0000000000..0cc0d53895
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgp_summary.json
@@ -0,0 +1,18 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.33",
+ "as":300,
+ "peers":{
+ "192.0.2.17":{
+ "remoteAs":200,
+ "state":"Established",
+ "peerState":"OK"
+ },
+ "192.0.2.50":{
+ "remoteAs":400,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r3/bgpd.conf b/tests/topotests/bgp_confed1/r3/bgpd.conf
new file mode 100644
index 0000000000..3a018a42b3
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgpd.conf
@@ -0,0 +1,17 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 300
+ no bgp ebgp-requires-policy
+ bgp confederation identifier 300
+ bgp confederation peers 200
+ neighbor 192.0.2.17 remote-as 200
+ neighbor 192.0.2.50 remote-as 400
+!
+ address-family ipv4 unicast
+ network 203.0.113.32/28
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_confed1/r3/isisd.conf b/tests/topotests/bgp_confed1/r3/isisd.conf
new file mode 100644
index 0000000000..a0b120019b
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/isisd.conf
@@ -0,0 +1,8 @@
+interface r3-eth1
+ ip router isis 1
+ isis circuit-type level-2-only
+
+router isis 1
+ is-type level-2-only
+ net 49.0001.0003.0003.0003.00
+ redistribute ipv4 connected level-2
diff --git a/tests/topotests/bgp_confed1/r3/zebra.conf b/tests/topotests/bgp_confed1/r3/zebra.conf
new file mode 100644
index 0000000000..555c8ed3cf
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface r3-eth0
+ ip address 192.0.2.49/28
+!
+interface r3-eth1
+ ip address 192.0.2.18/28
+!
+interface lo
+ ip address 203.0.113.33/28
+!
diff --git a/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..8a1f0b6762
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json
@@ -0,0 +1,77 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.49",
+ "defaultLocPrf":100,
+ "localAS":400,
+ "routes":{"0.0.0.0/0":[
+ {
+ "network":"0.0.0.0\/0",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.49",
+ "path":"300 100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r4/bgp_summary.json b/tests/topotests/bgp_confed1/r4/bgp_summary.json
new file mode 100644
index 0000000000..11a0c45cc7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgp_summary.json
@@ -0,0 +1,13 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.49",
+ "as":400,
+ "peers":{
+ "192.0.2.49":{
+ "remoteAs":300,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r4/bgpd.conf b/tests/topotests/bgp_confed1/r4/bgpd.conf
new file mode 100644
index 0000000000..134f221543
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgpd.conf
@@ -0,0 +1,14 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 400
+ no bgp ebgp-requires-policy
+ bgp disable-ebgp-connected-route-check
+!
+ neighbor 192.0.2.49 remote-as 300
+ address-family ipv4 unicast
+ network 203.0.113.48/28
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confed1/r4/isisd.conf b/tests/topotests/bgp_confed1/r4/isisd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/isisd.conf
diff --git a/tests/topotests/bgp_confed1/r4/zebra.conf b/tests/topotests/bgp_confed1/r4/zebra.conf
new file mode 100644
index 0000000000..28c448eef8
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/zebra.conf
@@ -0,0 +1,6 @@
+interface r4-eth0
+ ip address 192.0.2.50/28
+!
+interface lo
+ ip address 203.0.113.49/28
+!
diff --git a/tests/topotests/bgp_confed1/test_bgp_confed1.py b/tests/topotests/bgp_confed1/test_bgp_confed1.py
new file mode 100644
index 0000000000..7a35a10852
--- /dev/null
+++ b/tests/topotests/bgp_confed1/test_bgp_confed1.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_confed1.py
+#
+# Copyright 2022 6WIND S.A.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND 6WIND DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 6WIND BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_confed1.py: Test the FRR BGP confederations with AS member
+same as confederation Id, verify BGP prefixes and path distribution
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+def setup_module(mod):
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_convergence():
+ "Assert that BGP is converging."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for bgp peers to go up")
+
+ for router in tgen.routers().values():
+ ref_file = "{}/{}/bgp_summary.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=125, wait=2.0)
+ assertmsg = "{}: bgp did not converge".format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_confed_ipv4_unicast():
+ "Assert that BGP is exchanging BGP route."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for bgp peers exchanging UPDATES")
+
+ for router in tgen.routers().values():
+ ref_file = "{}/{}/bgp_ipv4_unicast.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5)
+ assertmsg = "{}: BGP UPDATE exchange failure".format(router.name)
+ assert res is None, assertmsg
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 4f095a176e..f1db3a73d5 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -266,7 +266,7 @@ all_start() {
}
all_stop() {
- local pids reversed need_zebra
+ local pids reversed
daemon_list enabled_daemons disabled_daemons
[ "$1" = "--reallyall" ] && enabled_daemons="$enabled_daemons $disabled_daemons"
@@ -276,23 +276,13 @@ all_stop() {
reversed="$dmninst $reversed"
done
- # Stop zebra last, after trying to stop the other daemons
for dmninst in $reversed; do
- if [ "$dmninst" = "zebra" ]; then
- need_zebra="yes"
- continue
- fi
-
daemon_stop "$dmninst" "$1" &
pids="$pids $!"
done
for pid in $pids; do
wait $pid
done
-
- if [ -n "$need_zebra" ]; then
- daemon_stop "zebra"
- fi
}
all_status() {
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 4a0356411f..e1bb40c28d 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -647,6 +647,8 @@ struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid,
vr->priority = vd.priority;
vr->preempt_mode = vd.preempt_mode;
vr->accept_mode = vd.accept_mode;
+ vr->checksum_with_ipv4_pseudoheader =
+ vd.checksum_with_ipv4_pseudoheader;
vr->shutdown = vd.shutdown;
vr->v4 = vrrp_router_create(vr, AF_INET);
@@ -789,7 +791,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r)
pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid,
r->priority, r->vr->advertisement_interval,
- r->addrs->count, (struct ipaddr **)&addrs);
+ r->addrs->count, (struct ipaddr **)&addrs,
+ r->vr->checksum_with_ipv4_pseudoheader);
if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL))
zlog_hexdump(pkt, (size_t)pktsz);
@@ -1027,8 +1030,10 @@ static void vrrp_read(struct thread *thread)
zlog_hexdump(r->ibuf, nbytes);
}
- pktsize = vrrp_pkt_parse_datagram(r->family, r->vr->version, &m, nbytes,
- &src, &pkt, errbuf, sizeof(errbuf));
+ pktsize = vrrp_pkt_parse_datagram(
+ r->family, r->vr->version,
+ r->vr->checksum_with_ipv4_pseudoheader, &m, nbytes, &src, &pkt,
+ errbuf, sizeof(errbuf));
if (pktsize < 0)
DEBUGD(&vrrp_dbg_pkt,
@@ -2347,6 +2352,12 @@ int vrrp_config_write_global(struct vty *vty)
vty_out(vty, "%svrrp default accept\n",
!vd.accept_mode ? "no " : "");
+ if (vd.checksum_with_ipv4_pseudoheader !=
+ VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER &&
+ ++writes)
+ vty_out(vty, "%svrrp default checksum-with-ipv4-pseudoheader\n",
+ !vd.checksum_with_ipv4_pseudoheader ? "no " : "");
+
if (vd.shutdown != VRRP_DEFAULT_SHUTDOWN && ++writes)
vty_out(vty, "%svrrp default shutdown\n",
!vd.shutdown ? "no " : "");
@@ -2387,6 +2398,8 @@ void vrrp_init(void)
vd.preempt_mode = yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL);
vd.accept_mode =
yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL);
+ vd.checksum_with_ipv4_pseudoheader = yang_get_default_bool(
+ "%s/checksum-with-ipv4-pseudoheader", VRRP_XPATH_FULL);
vd.shutdown = VRRP_DEFAULT_SHUTDOWN;
vrrp_autoconfig_version = 3;
diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h
index c181c2159b..b3141ef318 100644
--- a/vrrpd/vrrp.h
+++ b/vrrpd/vrrp.h
@@ -53,6 +53,7 @@
#define VRRP_DEFAULT_ADVINT 100
#define VRRP_DEFAULT_PREEMPT true
#define VRRP_DEFAULT_ACCEPT true
+#define VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER true
#define VRRP_DEFAULT_SHUTDOWN false
/* User compatibility constant */
@@ -70,6 +71,7 @@ struct vrrp_defaults {
uint16_t advertisement_interval;
bool preempt_mode;
bool accept_mode;
+ bool checksum_with_ipv4_pseudoheader;
bool shutdown;
};
@@ -266,6 +268,14 @@ struct vrrp_vrouter {
*/
bool accept_mode;
+ /*
+ * Indicates whether this router computes and accepts VRRPv3 checksums
+ * without pseudoheader, for device interoperability.
+ *
+ * This option should only affect IPv4 virtual routers.
+ */
+ bool checksum_with_ipv4_pseudoheader;
+
struct vrrp_router *v4;
struct vrrp_router *v6;
};
diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c
index d25dc0a197..76d0ad3b1b 100644
--- a/vrrpd/vrrp_northbound.c
+++ b/vrrpd/vrrp_northbound.c
@@ -602,6 +602,26 @@ lib_interface_vrrp_vrrp_group_shutdown_modify(struct nb_cb_modify_args *args)
return NB_OK;
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-
+ * ipv4-pseudoheader
+ */
+static int lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify(
+ struct nb_cb_modify_args *args)
+{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ bool checksum_with_ipv4_ph;
+
+ vr = nb_running_get_entry(args->dnode, NULL, true);
+ checksum_with_ipv4_ph = yang_dnode_get_bool(args->dnode, NULL);
+ vr->checksum_with_ipv4_pseudoheader = checksum_with_ipv4_ph;
+
+ return NB_OK;
+}
+
/* clang-format off */
const struct frr_yang_module_info frr_vrrpd_info = {
.name = "frr-vrrpd",
@@ -644,6 +664,13 @@ const struct frr_yang_module_info frr_vrrpd_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-ipv4-pseudoheader",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify,
+ .cli_show = cli_show_checksum_with_ipv4_pseudoheader,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval",
.cbs = {
.modify = lib_interface_vrrp_vrrp_group_advertisement_interval_modify,
diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c
index 991c030196..96a19da88c 100644
--- a/vrrpd/vrrp_packet.c
+++ b/vrrpd/vrrp_packet.c
@@ -71,7 +71,7 @@ static const char *const vrrp_packet_names[16] = {
* VRRP checksum in network byte order.
*/
static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
- struct ipaddr *src)
+ struct ipaddr *src, bool ipv4_ph)
{
uint16_t chksum;
bool v6 = (src->ipa_type == IPADDR_V6);
@@ -89,13 +89,16 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
ph.next_hdr = IPPROTO_VRRP;
chksum = in_cksum_with_ph6(&ph, pkt, pktsize);
} else if (!v6 && ((pkt->hdr.vertype >> 4) == 3)) {
- struct ipv4_ph ph = {};
-
- ph.src = src->ipaddr_v4;
- inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst);
- ph.proto = IPPROTO_VRRP;
- ph.len = htons(pktsize);
- chksum = in_cksum_with_ph4(&ph, pkt, pktsize);
+ if (ipv4_ph) {
+ struct ipv4_ph ph = {};
+
+ ph.src = src->ipaddr_v4;
+ inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst);
+ ph.proto = IPPROTO_VRRP;
+ ph.len = htons(pktsize);
+ chksum = in_cksum_with_ph4(&ph, pkt, pktsize);
+ } else
+ chksum = in_cksum(pkt, pktsize);
} else if (!v6 && ((pkt->hdr.vertype >> 4) == 2)) {
chksum = in_cksum(pkt, pktsize);
} else {
@@ -110,7 +113,7 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
uint8_t version, uint8_t vrid, uint8_t prio,
uint16_t max_adver_int, uint8_t numip,
- struct ipaddr **ips)
+ struct ipaddr **ips, bool ipv4_ph)
{
bool v6 = false;
size_t addrsz = 0;
@@ -147,7 +150,7 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
aptr += addrsz;
}
- (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src);
+ (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph);
return pktsize;
}
@@ -188,10 +191,10 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt)
return rs;
}
-ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
- size_t read, struct ipaddr *src,
- struct vrrp_pkt **pkt, char *errmsg,
- size_t errmsg_len)
+ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
+ struct msghdr *m, size_t read,
+ struct ipaddr *src, struct vrrp_pkt **pkt,
+ char *errmsg, size_t errmsg_len)
{
/* Source (MAC & IP), Dest (MAC & IP) TTL validation done by kernel */
size_t addrsz = (family == AF_INET) ? sizeof(struct in_addr)
@@ -289,7 +292,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
VRRP_PKT_VCHECK(pktver == version, "Bad version %u", pktver);
/* Checksum check */
- uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src);
+ uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph);
VRRP_PKT_VCHECK((*pkt)->hdr.chksum == chksum,
"Bad VRRP checksum %hx; should be %hx",
diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h
index 082935f080..eec709593e 100644
--- a/vrrpd/vrrp_packet.h
+++ b/vrrpd/vrrp_packet.h
@@ -131,7 +131,7 @@ struct vrrp_pkt {
ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
uint8_t version, uint8_t vrid, uint8_t prio,
uint16_t max_adver_int, uint8_t numip,
- struct ipaddr **ips);
+ struct ipaddr **ips, bool ipv4_ph);
/* free memory allocated by vrrp_pkt_adver_build's pkt arg */
void vrrp_pkt_free(struct vrrp_pkt *pkt);
@@ -195,9 +195,9 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt);
* Returns:
* Size of VRRP packet, or -1 upon error
*/
-ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
- size_t read, struct ipaddr *src,
- struct vrrp_pkt **pkt, char *errmsg,
- size_t errmsg_len);
+ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
+ struct msghdr *m, size_t read,
+ struct ipaddr *src, struct vrrp_pkt **pkt,
+ char *errmsg, size_t errmsg_len);
#endif /* __VRRP_PACKET_H__ */
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index f822b89854..1e1edb8212 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -281,6 +281,35 @@ void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode,
vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid);
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-
+ * ipv4-pseudoheader
+ */
+DEFPY_YANG(vrrp_checksum_with_ipv4_pseudoheader,
+ vrrp_checksum_with_ipv4_pseudoheader_cmd,
+ "[no] vrrp (1-255)$vrid checksum-with-ipv4-pseudoheader",
+ NO_STR
+ VRRP_STR
+ VRRP_VRID_STR
+ "Checksum mode in VRRPv3\n")
+{
+ nb_cli_enqueue_change(vty, "./checksum-with-ipv4-pseudoheader",
+ NB_OP_MODIFY, no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
+
+void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ const bool pre = yang_dnode_get_bool(dnode, NULL);
+
+ vty_out(vty, " %svrrp %s checksum-with-ipv4-pseudoheader\n",
+ pre ? "" : "no ", vrid);
+}
+
/* XXX: yang conversion */
DEFPY_YANG(vrrp_autoconfigure,
vrrp_autoconfigure_cmd,
@@ -304,7 +333,7 @@ DEFPY_YANG(vrrp_autoconfigure,
/* XXX: yang conversion */
DEFPY_YANG(vrrp_default,
vrrp_default_cmd,
- "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
+ "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|checksum-with-ipv4-pseudoheader$ipv4ph|shutdown$s>",
NO_STR
VRRP_STR
"Configure defaults for new VRRP instances\n"
@@ -313,6 +342,7 @@ DEFPY_YANG(vrrp_default,
"Preempt mode\n"
VRRP_PRIORITY_STR
"Priority value\n"
+ "Checksum mode in VRRPv3\n"
"Force VRRP router into administrative shutdown\n")
{
if (adv) {
@@ -329,6 +359,8 @@ DEFPY_YANG(vrrp_default,
vd.preempt_mode = !no;
if (prio)
vd.priority = no ? VRRP_DEFAULT_PRIORITY : prioval;
+ if (ipv4ph)
+ vd.checksum_with_ipv4_pseudoheader = !no;
if (s)
vd.shutdown = !no;
@@ -374,6 +406,8 @@ static struct json_object *vrrp_build_json(struct vrrp_vrouter *vr)
json_object_boolean_add(j, "shutdown", vr->shutdown);
json_object_boolean_add(j, "preemptMode", vr->preempt_mode);
json_object_boolean_add(j, "acceptMode", vr->accept_mode);
+ json_object_boolean_add(j, "checksumWithIpv4Pseudoheader",
+ vr->checksum_with_ipv4_pseudoheader);
json_object_string_add(j, "interface", vr->ifp->name);
json_object_int_add(j, "advertisementInterval",
vr->advertisement_interval * CS2MS);
@@ -499,6 +533,8 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
vr->preempt_mode ? "Yes" : "No");
ttable_add_row(tt, "%s|%s", "Accept Mode",
vr->accept_mode ? "Yes" : "No");
+ ttable_add_row(tt, "%s|%s", "Checksum with IPv4 Pseudoheader",
+ vr->checksum_with_ipv4_pseudoheader ? "Yes" : "No");
ttable_add_row(tt, "%s|%d ms", "Advertisement Interval",
vr->advertisement_interval * CS2MS);
ttable_add_row(tt, "%s|%d ms (stale)",
@@ -752,4 +788,6 @@ void vrrp_vty_init(void)
install_element(INTERFACE_NODE, &vrrp_ip_cmd);
install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
+ install_element(INTERFACE_NODE,
+ &vrrp_checksum_with_ipv4_pseudoheader_cmd);
}
diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h
index 587537a6f3..be88349e78 100644
--- a/vrrpd/vrrp_vty.h
+++ b/vrrpd/vrrp_vty.h
@@ -40,5 +40,8 @@ void cli_show_ipv6(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
#endif /* __VRRP_VTY_H__ */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 30f117505a..dea09fa151 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3939,6 +3939,12 @@ DEFUN (vtysh_ping,
return CMD_SUCCESS;
}
+DEFUN(vtysh_motd, vtysh_motd_cmd, "show motd", SHOW_STR "Show motd\n")
+{
+ vty_hello(vty);
+ return CMD_SUCCESS;
+}
+
ALIAS(vtysh_ping, vtysh_ping_ip_cmd, "ping ip WORD",
"Send echo messages\n"
"IP echo\n"
@@ -4907,6 +4913,7 @@ void vtysh_init_vty(void)
install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd);
install_element(VIEW_NODE, &vtysh_ping_cmd);
+ install_element(VIEW_NODE, &vtysh_motd_cmd);
install_element(VIEW_NODE, &vtysh_ping_ip_cmd);
install_element(VIEW_NODE, &vtysh_traceroute_cmd);
install_element(VIEW_NODE, &vtysh_traceroute_ip_cmd);
diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang
index 200eaeb0b5..cd04df2670 100644
--- a/yang/frr-vrrpd.yang
+++ b/yang/frr-vrrpd.yang
@@ -110,6 +110,13 @@ module frr-vrrpd {
address is not owned by the router interface";
}
+ leaf checksum-with-ipv4-pseudoheader {
+ type boolean;
+ default "true";
+ description
+ "Enabled if VRRPv3 checksum for IPv4 involves pseudoheader";
+ }
+
leaf advertisement-interval {
type uint16 {
range "1..4095";
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index b28c468a96..d628e47492 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1081,8 +1081,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zif->link_ifindex = link_ifindex;
if (desc) {
- XFREE(MTYPE_TMP, zif->desc);
- zif->desc = XSTRDUP(MTYPE_TMP, desc);
+ XFREE(MTYPE_ZIF_DESC, zif->desc);
+ zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc);
}
/* Hardware type and address. */
@@ -2136,9 +2136,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zif = ifp->info;
if (zif) {
- XFREE(MTYPE_TMP, zif->desc);
+ XFREE(MTYPE_ZIF_DESC, zif->desc);
if (desc)
- zif->desc = XSTRDUP(MTYPE_TMP, desc);
+ zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc);
}
} else {
/* Delete interface notification from kernel */
diff --git a/zebra/interface.c b/zebra/interface.c
index 81ee995dd7..87bb49042a 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -61,6 +61,7 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
(vty, ifp));
+DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc");
static void if_down_del_nbr_connected(struct interface *ifp);
@@ -233,7 +234,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
if_nhg_dependents_release(ifp);
zebra_if_nhg_dependents_free(zebra_if);
- XFREE(MTYPE_TMP, zebra_if->desc);
+ XFREE(MTYPE_ZIF_DESC, zebra_if->desc);
THREAD_OFF(zebra_if->speed_update);
diff --git a/zebra/interface.h b/zebra/interface.h
index 801078e83d..0242438dc2 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -109,6 +109,9 @@ enum zebra_if_flags {
#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \
((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL)
+/* Mem type for zif desc */
+DECLARE_MTYPE(ZIF_DESC);
+
/* `zebra' daemon local interface structure. */
struct zebra_if {
/* back pointer to the interface */
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index 28db2ad87d..36852b65b6 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -200,12 +200,12 @@ static void if_set_defaults(struct irdp_interface *irdp)
static struct Adv *Adv_new(void)
{
- return XCALLOC(MTYPE_TMP, sizeof(struct Adv));
+ return XCALLOC(MTYPE_IRDP_IF, sizeof(struct Adv));
}
static void Adv_free(struct Adv *adv)
{
- XFREE(MTYPE_TMP, adv);
+ XFREE(MTYPE_IRDP_IF, adv);
}
static void irdp_if_start(struct interface *ifp, int multicast,
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index d594512b36..a2233a6667 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -3698,7 +3698,7 @@ static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS)
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
{
struct zebra_pbr_iptable *zpi =
- XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+ XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
struct stream *s;
s = msg;
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
index 56d0df569c..d3c104cc80 100644
--- a/zebra/zebra_gr.c
+++ b/zebra/zebra_gr.c
@@ -46,6 +46,7 @@
#include "zebra/debug.h"
#include "zebra/zapi_msg.h"
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_GR, "GR");
/*
* Forward declaration.
@@ -111,7 +112,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
{
struct client_gr_info *info;
- info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info));
+ info = XCALLOC(MTYPE_ZEBRA_GR, sizeof(struct client_gr_info));
TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info);
return info;
@@ -127,7 +128,7 @@ static void zebra_gr_client_info_delte(struct zserv *client,
THREAD_OFF(info->t_stale_removal);
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
LOG_GR("%s: Instance info is being deleted for client %s", __func__,
zebra_route_string(client->proto));
@@ -136,7 +137,7 @@ static void zebra_gr_client_info_delte(struct zserv *client,
info->do_delete = true;
zebra_gr_delete_stale_routes(info);
- XFREE(MTYPE_TMP, info);
+ XFREE(MTYPE_ZEBRA_GR, info);
}
/*
@@ -222,8 +223,8 @@ static void zebra_gr_delete_stale_client(struct client_gr_info *info)
TAILQ_INIT(&(s_client->gr_info_queue));
listnode_delete(zrouter.stale_client_list, s_client);
if (info->stale_client)
- XFREE(MTYPE_TMP, s_client);
- XFREE(MTYPE_TMP, info);
+ zserv_client_delete(s_client);
+ XFREE(MTYPE_ZEBRA_GR, info);
}
/*
@@ -288,7 +289,7 @@ void zebra_gr_client_reconnect(struct zserv *client)
/* Delete the stale client */
listnode_delete(zrouter.stale_client_list, old_client);
/* Delete old client */
- XFREE(MTYPE_TMP, old_client);
+ zserv_client_delete(old_client);
}
/*
@@ -474,7 +475,7 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
LOG_GR("%s: Client %s all stale routes processed", __func__,
zebra_route_string(client->proto));
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
info->current_afi = 0;
zebra_gr_delete_stale_client(info);
}
@@ -579,7 +580,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
&& (info->do_delete == false)) {
info->current_afi = afi;
info->current_prefix = XCALLOC(
- MTYPE_TMP,
+ MTYPE_ZEBRA_GR,
sizeof(struct prefix));
prefix_copy(
info->current_prefix,
@@ -593,7 +594,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
* Reset the current prefix to indicate processing completion
* of the current AFI
*/
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
}
return 0;
}
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 43e21a6d34..405241fc22 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -36,6 +36,7 @@
/* definitions */
DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
+DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
/* definitions */
static const struct message ipset_type_msg[] = {
@@ -163,7 +164,7 @@ void zebra_pbr_rules_free(void *arg)
rule = (struct zebra_pbr_rule *)arg;
(void)dplane_pbr_rule_delete(rule);
- XFREE(MTYPE_TMP, rule);
+ XFREE(MTYPE_PBR_OBJ, rule);
}
uint32_t zebra_pbr_rules_hash_key(const void *arg)
@@ -275,7 +276,7 @@ void zebra_pbr_ipset_free(void *arg)
ipset = (struct zebra_pbr_ipset *)arg;
hook_call(zebra_pbr_ipset_update, 0, ipset);
- XFREE(MTYPE_TMP, ipset);
+ XFREE(MTYPE_PBR_OBJ, ipset);
}
uint32_t zebra_pbr_ipset_hash_key(const void *arg)
@@ -319,7 +320,7 @@ void zebra_pbr_ipset_entry_free(void *arg)
hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
- XFREE(MTYPE_TMP, ipset);
+ XFREE(MTYPE_PBR_OBJ, ipset);
}
uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
@@ -396,7 +397,7 @@ static void _zebra_pbr_iptable_free_all(void *arg, bool all)
}
list_delete(&iptable->interface_name_list);
}
- XFREE(MTYPE_TMP, iptable);
+ XFREE(MTYPE_PBR_OBJ, iptable);
}
void zebra_pbr_iptable_free(void *arg)
@@ -478,7 +479,7 @@ static void *pbr_rule_alloc_intern(void *arg)
zpr = (struct zebra_pbr_rule *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(*new));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
memcpy(new, zpr, sizeof(*zpr));
@@ -492,7 +493,7 @@ static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
zebra_neigh_deref(hash_data);
hash_release(zrouter.rules_hash, hash_data);
if (free_data) {
- XFREE(MTYPE_TMP, hash_data);
+ XFREE(MTYPE_PBR_OBJ, hash_data);
return NULL;
}
@@ -688,7 +689,7 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
(void)dplane_pbr_rule_update(found, new);
/* release the old hash data */
if (old)
- XFREE(MTYPE_TMP, old);
+ XFREE(MTYPE_PBR_OBJ, old);
} else {
if (IS_ZEBRA_DEBUG_PBR)
zlog_debug(
@@ -856,7 +857,7 @@ static void *pbr_ipset_alloc_intern(void *arg)
zpi = (struct zebra_pbr_ipset *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
memcpy(new, zpi, sizeof(*zpi));
@@ -877,7 +878,7 @@ void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
(void)dplane_pbr_ipset_delete(ipset);
if (lookup) {
hash_release(zrouter.ipset_hash, lookup);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug(
"%s: IPSet Entry being deleted we know nothing about",
@@ -930,7 +931,7 @@ static void *pbr_ipset_entry_alloc_intern(void *arg)
zpi = (struct zebra_pbr_ipset_entry *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
memcpy(new, zpi, sizeof(*zpi));
@@ -952,7 +953,7 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
(void)dplane_pbr_ipset_entry_delete(ipset);
if (lookup) {
hash_release(zrouter.ipset_entry_hash, lookup);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug("%s: IPSet being deleted we know nothing about",
__func__);
@@ -967,7 +968,7 @@ static void *pbr_iptable_alloc_intern(void *arg)
zpi = (struct zebra_pbr_iptable *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
/* Deep structure copy */
memcpy(new, zpi, sizeof(*zpi));
@@ -1009,7 +1010,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
node);
}
list_delete(&iptable->interface_name_list);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug("%s: IPTable being deleted we know nothing about",
__func__);
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index baa8755fa5..60457914cc 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -36,6 +36,9 @@
extern "C" {
#endif
+/* Memory type for PBR objects. */
+DECLARE_MTYPE(PBR_OBJ);
+
struct zebra_pbr_action {
afi_t afi;
diff --git a/zebra/zserv.c b/zebra/zserv.c
index ebe246ffbc..d788811d3d 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -78,6 +78,8 @@ static struct zserv *find_client_internal(uint8_t proto,
unsigned short instance,
uint32_t session_id);
+/* Mem type for zclients. */
+DEFINE_MTYPE_STATIC(ZEBRA, ZSERV_CLIENT, "ZClients");
/*
* Client thread events.
@@ -146,6 +148,14 @@ static void zserv_event(struct zserv *client, enum zserv_event event);
/* Client thread lifecycle -------------------------------------------------- */
/*
+ * Free a zserv client object.
+ */
+void zserv_client_delete(struct zserv *client)
+{
+ XFREE(MTYPE_ZSERV_CLIENT, client);
+}
+
+/*
* Log zapi message to zlog.
*
* errmsg (optional)
@@ -644,7 +654,7 @@ static void zserv_client_free(struct zserv *client)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Deleting client %s", __func__,
zebra_route_string(client->proto));
- XFREE(MTYPE_TMP, client);
+ zserv_client_delete(client);
} else {
/* Handle cases where client has GR instance. */
if (IS_ZEBRA_DEBUG_EVENT)
@@ -733,7 +743,7 @@ static struct zserv *zserv_client_create(int sock)
int i;
afi_t afi;
- client = XCALLOC(MTYPE_TMP, sizeof(struct zserv));
+ client = XCALLOC(MTYPE_ZSERV_CLIENT, sizeof(struct zserv));
/* Make client input/output buffer. */
client->sock = sock;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index db7b70d7c4..de784e382a 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -364,6 +364,13 @@ extern void zserv_release_client(struct zserv *client);
extern void zserv_close_client(struct zserv *client);
/*
+ * Free memory for a zserv client object - note that this does not
+ * clean up the internal allocations associated with the zserv client,
+ * this just free the struct's memory.
+ */
+void zserv_client_delete(struct zserv *client);
+
+/*
* Log a ZAPI message hexdump.
*
* errmsg