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