diff options
45 files changed, 926 insertions, 674 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e07af4ab03..dcf0f4d47c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -502,6 +502,7 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) uint8_t *data = pnt; uint8_t tlv_type; uint16_t tlv_length; + uint8_t *end = data + length; if (length < 3) { zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u", @@ -510,7 +511,13 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) } while (length) { + size_t data_len = end - data; + tlv_type = *data; + + if (data_len - 1 < 2) + return false; + ptr_get_be16(data + 1, &tlv_length); (void)data; @@ -3461,8 +3468,24 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT(peer) < endp) { + startp = BGP_INPUT_PNT(peer); + + /* Fewer than three octets remain (or fewer than four + * octets, if the Attribute Flags field has the Extended + * Length bit set) when beginning to parse the attribute. + * That is, this case exists if there remains unconsumed + * data in the path attributes but yet insufficient data + * to encode a single minimum-sized path attribute. + * + * An error condition exists and the "treat-as-withdraw" + * approach MUST be used (unless some other, more severe + * error is encountered dictating a stronger approach), + * and the Total Attribute Length MUST be relied upon to + * enable the beginning of the NLRI field to be located. + */ + /* Check remaining length check.*/ - if (endp - BGP_INPUT_PNT(peer) < BGP_ATTR_MIN_LEN) { + if ((endp - startp) < BGP_ATTR_MIN_LEN) { /* XXX warning: long int format, int arg (arg 5) */ flog_warn( EC_BGP_ATTRIBUTE_TOO_SMALL, @@ -3471,17 +3494,22 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, (unsigned long)(endp - stream_pnt(BGP_INPUT(peer)))); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - ret = BGP_ATTR_PARSE_ERROR; + if (peer->sort != BGP_PEER_EBGP) { + bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + ret = BGP_ATTR_PARSE_ERROR; + } else { + ret = BGP_ATTR_PARSE_WITHDRAW; + } + goto done; } - /* Fetch attribute flag and type. */ - startp = BGP_INPUT_PNT(peer); - /* "The lower-order four bits of the Attribute Flags octet are - unused. They MUST be zero when sent and MUST be ignored when - received." */ + /* Fetch attribute flag and type. + * The lower-order four bits of the Attribute Flags octet are + * unused. They MUST be zero when sent and MUST be ignored when + * received. + */ flag = 0xF0 & stream_getc(BGP_INPUT(peer)); type = stream_getc(BGP_INPUT(peer)); @@ -3495,9 +3523,14 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, (unsigned long)(endp - stream_pnt(BGP_INPUT(peer)))); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - ret = BGP_ATTR_PARSE_ERROR; + if (peer->sort != BGP_PEER_EBGP) { + bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + ret = BGP_ATTR_PARSE_ERROR; + } else { + ret = BGP_ATTR_PARSE_WITHDRAW; + } + goto done; } diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index d1ddfd0460..7f83e97107 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -56,7 +56,7 @@ static void bfd_session_status_update(struct bfd_session_params *bsp, peer->last_reset = PEER_DOWN_BFD_DOWN; /* rfc9384 */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_BFD_DOWN); diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index baf164679c..04a70aa59f 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -703,7 +703,7 @@ static int bmp_peer_status_changed(struct peer *peer) if (!bmpbgp) return 0; - if (peer->status == Deleted) { + if (peer->connection->status == Deleted) { bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid); if (bbpeer) { XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx); @@ -715,10 +715,12 @@ static int bmp_peer_status_changed(struct peer *peer) } /* Check if this peer just went to Established */ - if ((peer->ostatus != OpenConfirm) || !(peer_established(peer))) + if ((peer->connection->ostatus != OpenConfirm) || + !(peer_established(peer))) return 0; - if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { + if (peer->doppelganger && + (peer->doppelganger->connection->status != Deleted)) { bbpeer = bmp_bgp_peer_get(peer); bbdopp = bmp_bgp_peer_find(peer->doppelganger->qobj_node.nid); if (bbdopp) { diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index fe77e7e250..3b5fbf368b 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -512,8 +512,8 @@ int bgp_dump_state(struct peer *peer) bgp_dump_all.type); bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/ - stream_putw(obuf, peer->ostatus); - stream_putw(obuf, peer->status); + stream_putw(obuf, peer->connection->ostatus); + stream_putw(obuf, peer->connection->status); /* Set length. */ bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 3442eee1e1..7457326c1b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -6462,7 +6462,7 @@ void bgp_reimport_evpn_routes_upon_martian_change( if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) continue; - if (peer->status != Established) + if (peer->connection->status != Established) continue; if (CHECK_FLAG(peer->af_flags[afi][safi], diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 269f5c2948..92038a73e4 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -83,9 +83,6 @@ static void bgp_connect_timer(struct event *event); static void bgp_holdtime_timer(struct event *event); static void bgp_delayopen_timer(struct event *event); -/* BGP FSM functions. */ -static enum bgp_fsm_state_progress bgp_start(struct peer *); - /* Register peer with NHT */ int bgp_peer_reg_with_nht(struct peer *peer) { @@ -146,13 +143,13 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: peer transfer %p fd %d -> %p fd %d)", - from_peer->host, from_peer, from_peer->fd, peer, - peer->fd); + from_peer->host, from_peer, from_peer->connection->fd, + peer, peer->connection->fd); - bgp_writes_off(peer); - bgp_reads_off(peer); - bgp_writes_off(from_peer); - bgp_reads_off(from_peer); + bgp_writes_off(peer->connection); + bgp_reads_off(peer->connection); + bgp_writes_off(from_peer->connection); + bgp_reads_off(from_peer->connection); /* * Before exchanging FD remove doppelganger from @@ -172,20 +169,21 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) EVENT_OFF(from_peer->t_delayopen); EVENT_OFF(from_peer->t_connect_check_r); EVENT_OFF(from_peer->t_connect_check_w); - EVENT_OFF(from_peer->t_process_packet); + EVENT_OFF(from_peer->connection->t_process_packet); /* * At this point in time, it is possible that there are packets pending * on various buffers. Those need to be transferred or dropped, * otherwise we'll get spurious failures during session establishment. */ - frr_with_mutex (&peer->io_mtx, &from_peer->io_mtx) { - fd = peer->fd; - peer->fd = from_peer->fd; - from_peer->fd = fd; + frr_with_mutex (&peer->connection->io_mtx, + &from_peer->connection->io_mtx) { + fd = peer->connection->fd; + peer->connection->fd = from_peer->connection->fd; + from_peer->connection->fd = fd; - stream_fifo_clean(peer->ibuf); - stream_fifo_clean(peer->obuf); + stream_fifo_clean(peer->connection->ibuf); + stream_fifo_clean(peer->connection->obuf); /* * this should never happen, since bgp_process_packet() is the @@ -207,18 +205,21 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) } // copy each packet from old peer's output queue to new peer - while (from_peer->obuf->head) - stream_fifo_push(peer->obuf, - stream_fifo_pop(from_peer->obuf)); + while (from_peer->connection->obuf->head) + stream_fifo_push(peer->connection->obuf, + stream_fifo_pop( + from_peer->connection->obuf)); // copy each packet from old peer's input queue to new peer - while (from_peer->ibuf->head) - stream_fifo_push(peer->ibuf, - stream_fifo_pop(from_peer->ibuf)); + while (from_peer->connection->ibuf->head) + stream_fifo_push(peer->connection->ibuf, + stream_fifo_pop( + from_peer->connection->ibuf)); - ringbuf_wipe(peer->ibuf_work); - ringbuf_copy(peer->ibuf_work, from_peer->ibuf_work, - ringbuf_remain(from_peer->ibuf_work)); + ringbuf_wipe(peer->connection->ibuf_work); + ringbuf_copy(peer->connection->ibuf_work, + from_peer->connection->ibuf_work, + ringbuf_remain(from_peer->connection->ibuf_work)); } peer->as = from_peer->as; @@ -229,16 +230,16 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->v_gr_restart = from_peer->v_gr_restart; peer->cap = from_peer->cap; peer->remote_role = from_peer->remote_role; - status = peer->status; - pstatus = peer->ostatus; + status = peer->connection->status; + pstatus = peer->connection->ostatus; last_evt = peer->last_event; last_maj_evt = peer->last_major_event; - peer->status = from_peer->status; - peer->ostatus = from_peer->ostatus; + peer->connection->status = from_peer->connection->status; + peer->connection->ostatus = from_peer->connection->ostatus; peer->last_event = from_peer->last_event; peer->last_major_event = from_peer->last_major_event; - from_peer->status = status; - from_peer->ostatus = pstatus; + from_peer->connection->status = status; + from_peer->connection->ostatus = pstatus; from_peer->last_event = last_evt; from_peer->last_major_event = last_maj_evt; peer->remote_id = from_peer->remote_id; @@ -295,29 +296,29 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) } if (bgp_getsockname(peer) < 0) { - flog_err( - EC_LIB_SOCKET, - "%%bgp_getsockname() failed for %s peer %s fd %d (from_peer fd %d)", - (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) - ? "accept" - : ""), - peer->host, peer->fd, from_peer->fd); + flog_err(EC_LIB_SOCKET, + "%%bgp_getsockname() failed for %s peer %s fd %d (from_peer fd %d)", + (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) + ? "accept" + : ""), + peer->host, peer->connection->fd, + from_peer->connection->fd); BGP_EVENT_ADD(peer, BGP_Stop); BGP_EVENT_ADD(from_peer, BGP_Stop); return NULL; } - if (from_peer->status > Active) { + if (from_peer->connection->status > Active) { if (bgp_getsockname(from_peer) < 0) { - flog_err( - EC_LIB_SOCKET, - "%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)", - - (CHECK_FLAG(from_peer->sflags, - PEER_STATUS_ACCEPT_PEER) - ? "accept" - : ""), - from_peer->host, from_peer->fd, peer->fd); - bgp_stop(from_peer); + flog_err(EC_LIB_SOCKET, + "%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)", + + (CHECK_FLAG(from_peer->sflags, + PEER_STATUS_ACCEPT_PEER) + ? "accept" + : ""), + from_peer->host, from_peer->connection->fd, + peer->connection->fd); + bgp_stop(from_peer->connection); from_peer = NULL; } } @@ -334,10 +335,10 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) if (from_peer) bgp_replace_nexthop_by_peer(from_peer, peer); - bgp_reads_on(peer); - bgp_writes_on(peer); - event_add_event(bm->master, bgp_process_packet, peer, 0, - &peer->t_process_packet); + bgp_reads_on(peer->connection); + bgp_writes_on(peer->connection); + event_add_event(bm->master, bgp_process_packet, peer->connection, 0, + &peer->connection->t_process_packet); return (peer); } @@ -350,7 +351,7 @@ void bgp_timer_set(struct peer *peer) afi_t afi; safi_t safi; - switch (peer->status) { + switch (peer->connection->status) { case Idle: /* First entry point of peer's finite state machine. In Idle status start timer is on unless peer is shutdown or peer is @@ -518,14 +519,14 @@ static void bgp_connect_timer(struct event *thread) /* stop the DelayOpenTimer if it is running */ EVENT_OFF(peer->t_delayopen); - assert(!peer->t_write); - assert(!peer->t_read); + assert(!peer->connection->t_write); + assert(!peer->connection->t_read); if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host); if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) - bgp_stop(peer); + bgp_stop(peer->connection); else { EVENT_VAL(thread) = ConnectRetry_timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ @@ -554,7 +555,7 @@ static void bgp_holdtime_timer(struct event *thread) * for systems where we are heavily loaded for one * reason or another. */ - inq_count = atomic_load_explicit(&peer->ibuf->count, + inq_count = atomic_load_explicit(&peer->connection->ibuf->count, memory_order_relaxed); if (inq_count) BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, @@ -1221,8 +1222,8 @@ static void bgp_update_delay_process_status_change(struct peer *peer) if (CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) bgp_update_restarted_peers(peer); } - if (peer->ostatus == Established - && bgp_update_delay_active(peer->bgp)) { + if (peer->connection->ostatus == Established && + bgp_update_delay_active(peer->bgp)) { /* Adjust the update-delay state to account for this flap. NOTE: Intentionally skipping adjusting implicit_eors or explicit_eors @@ -1298,14 +1299,15 @@ void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) } /* Preserve old status and change into new status. */ - peer->ostatus = peer->status; - peer->status = status; + peer->connection->ostatus = peer->connection->status; + peer->connection->status = status; /* Reset received keepalives counter on every FSM change */ peer->rtt_keepalive_rcv = 0; /* Fire backward transition hook if that's the case */ - if (peer->ostatus == Established && peer->status != Established) + if (peer->connection->ostatus == Established && + peer->connection->status != Established) hook_call(peer_backward_transition, peer); /* Save event that caused status change. */ @@ -1332,15 +1334,21 @@ void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) bgp_update_delay_process_status_change(peer); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s fd %d went from %s to %s", peer->host, peer->fd, - lookup_msg(bgp_status_msg, peer->ostatus, NULL), - lookup_msg(bgp_status_msg, peer->status, NULL)); + zlog_debug("%s fd %d went from %s to %s", peer->host, + peer->connection->fd, + lookup_msg(bgp_status_msg, peer->connection->ostatus, + NULL), + lookup_msg(bgp_status_msg, peer->connection->status, + NULL)); } /* Flush the event queue and ensure the peer is shut down */ -static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_clearing_completed(struct peer_connection *connection) { - enum bgp_fsm_state_progress rc = bgp_stop(peer); + struct peer *peer = connection->peer; + + enum bgp_fsm_state_progress rc = bgp_stop(connection); if (rc >= BGP_FSM_SUCCESS) BGP_EVENT_FLUSH(peer); @@ -1350,12 +1358,13 @@ static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer) /* Administrative BGP peer stop event. */ /* May be called multiple times for the same peer */ -enum bgp_fsm_state_progress bgp_stop(struct peer *peer) +enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; + struct peer *peer = connection->peer; struct bgp *bgp = peer->bgp; struct graceful_restart_info *gr_info = NULL; @@ -1376,7 +1385,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) } /* Can't do this in Clearing; events are used for state transitions */ - if (peer->status != Clearing) { + if (connection->status != Clearing) { /* Delete all existing events of the peer */ BGP_EVENT_FLUSH(peer); } @@ -1495,8 +1504,8 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) bgp_keepalives_off(peer); /* Stop read and write threads. */ - bgp_writes_off(peer); - bgp_reads_off(peer); + bgp_writes_off(connection); + bgp_reads_off(connection); EVENT_OFF(peer->t_connect_check_r); EVENT_OFF(peer->t_connect_check_w); @@ -1509,14 +1518,14 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) EVENT_OFF(peer->t_delayopen); /* Clear input and output buffer. */ - frr_with_mutex (&peer->io_mtx) { - if (peer->ibuf) - stream_fifo_clean(peer->ibuf); - if (peer->obuf) - stream_fifo_clean(peer->obuf); + frr_with_mutex (&connection->io_mtx) { + if (connection->ibuf) + stream_fifo_clean(connection->ibuf); + if (connection->obuf) + stream_fifo_clean(connection->obuf); - if (peer->ibuf_work) - ringbuf_wipe(peer->ibuf_work); + if (connection->ibuf_work) + ringbuf_wipe(connection->ibuf_work); if (peer->curr) { stream_free(peer->curr); @@ -1525,9 +1534,9 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) } /* Close of file descriptor. */ - if (peer->fd >= 0) { - close(peer->fd); - peer->fd = -1; + if (connection->fd >= 0) { + close(connection->fd); + connection->fd = -1; } /* Reset capabilities. */ @@ -1551,7 +1560,8 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; - if ((peer->status == OpenConfirm) || (peer_established(peer))) { + if ((connection->status == OpenConfirm) || + peer_established(peer)) { /* ORF received prefix-filter pnt */ snprintf(orf_name, sizeof(orf_name), "%s.%d.%d", peer->host, afi, safi); @@ -1587,8 +1597,11 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) } /* BGP peer is stoped by the error. */ -static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_stop_with_error(struct peer_connection *connection) { + struct peer *peer = connection->peer; + /* Double start timer. */ peer->v_start *= 2; @@ -1604,7 +1617,7 @@ static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer) return BGP_FSM_FAILURE; } - return bgp_stop(peer); + return bgp_stop(connection); } @@ -1626,7 +1639,7 @@ bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code) /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; - return bgp_stop(peer); + return bgp_stop(peer->connection); } /** @@ -1652,18 +1665,20 @@ static void bgp_connect_check(struct event *thread) struct peer *peer; peer = EVENT_ARG(thread); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); - assert(!peer->t_read); - assert(!peer->t_write); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_READS_ON)); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_WRITES_ON)); + assert(!peer->connection->t_read); + assert(!peer->connection->t_write); EVENT_OFF(peer->t_connect_check_r); EVENT_OFF(peer->t_connect_check_w); /* Check file descriptor. */ slen = sizeof(status); - ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *)&status, - &slen); + ret = getsockopt(peer->connection->fd, SOL_SOCKET, SO_ERROR, + (void *)&status, &slen); /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { @@ -1691,21 +1706,24 @@ static void bgp_connect_check(struct event *thread) /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ -static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_connect_success(struct peer_connection *connection) { - if (peer->fd < 0) { + struct peer *peer = connection->peer; + + if (connection->fd < 0) { flog_err(EC_BGP_CONNECT, "%s peer's fd is negative value %d", - __func__, peer->fd); - return bgp_stop(peer); + __func__, connection->fd); + return bgp_stop(connection); } if (bgp_getsockname(peer) < 0) { flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname(): failed for peer %s, fd %d", - __func__, peer->host, peer->fd); + __func__, peer->host, connection->fd); bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); - bgp_writes_on(peer); + bgp_fsm_error_subcode(connection->status)); + bgp_writes_on(connection); return BGP_FSM_FAILURE; } @@ -1715,7 +1733,7 @@ static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer) */ bgp_nht_interface_events(peer); - bgp_reads_on(peer); + bgp_reads_on(connection); if (bgp_debug_neighbor_events(peer)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) @@ -1735,21 +1753,23 @@ static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer) * set. */ static enum bgp_fsm_state_progress -bgp_connect_success_w_delayopen(struct peer *peer) +bgp_connect_success_w_delayopen(struct peer_connection *connection) { - if (peer->fd < 0) { + struct peer *peer = connection->peer; + + if (connection->fd < 0) { flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d", - __func__, peer->fd); - return bgp_stop(peer); + __func__, connection->fd); + return bgp_stop(connection); } if (bgp_getsockname(peer) < 0) { flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname(): failed for peer %s, fd %d", - __func__, peer->host, peer->fd); + __func__, peer->host, connection->fd); bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); - bgp_writes_on(peer); + bgp_fsm_error_subcode(connection->status)); + bgp_writes_on(connection); return BGP_FSM_FAILURE; } @@ -1759,7 +1779,7 @@ bgp_connect_success_w_delayopen(struct peer *peer) */ bgp_nht_interface_events(peer); - bgp_reads_on(peer); + bgp_reads_on(connection); if (bgp_debug_neighbor_events(peer)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) @@ -1785,9 +1805,12 @@ bgp_connect_success_w_delayopen(struct peer *peer) } /* TCP connect fail */ -static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_connect_fail(struct peer_connection *connection) { - if (peer_dynamic_neighbor_no_nsf(peer)) { + struct peer *peer = connection->peer; + + if (peer_dynamic_neighbor(peer)) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); @@ -1801,14 +1824,15 @@ static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer) */ bgp_nht_interface_events(peer); - return bgp_stop(peer); + return bgp_stop(connection); } /* This function is the first starting point of all BGP connection. It * try to connect to remote peer with non-blocking IO. */ -enum bgp_fsm_state_progress bgp_start(struct peer *peer) +static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) { + struct peer *peer = connection->peer; int status; bgp_peer_conf_if_to_su_update(peer); @@ -1889,10 +1913,10 @@ enum bgp_fsm_state_progress bgp_start(struct peer *peer) } } - assert(!peer->t_write); - assert(!peer->t_read); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); + assert(!connection->t_write); + assert(!connection->t_read); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON)); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON)); status = bgp_connect(peer); switch (status) { @@ -1903,9 +1927,8 @@ enum bgp_fsm_state_progress bgp_start(struct peer *peer) break; case connect_success: if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s [FSM] Connect immediately success, fd %d", - peer->host, peer->fd); + zlog_debug("%s [FSM] Connect immediately success, fd %d", + peer->host, connection->fd); BGP_EVENT_ADD(peer, TCP_connection_open); break; @@ -1913,13 +1936,11 @@ enum bgp_fsm_state_progress bgp_start(struct peer *peer) /* To check nonblocking connect, we wait until socket is readable or writable. */ if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s [FSM] Non blocking connect waiting result, fd %d", - peer->host, peer->fd); - if (peer->fd < 0) { - flog_err(EC_BGP_FSM, - "%s peer's fd is negative value %d", __func__, - peer->fd); + zlog_debug("%s [FSM] Non blocking connect waiting result, fd %d", + peer->host, connection->fd); + if (connection->fd < 0) { + flog_err(EC_BGP_FSM, "%s peer's fd is negative value %d", + __func__, peer->connection->fd); return BGP_FSM_FAILURE; } /* @@ -1931,21 +1952,23 @@ enum bgp_fsm_state_progress bgp_start(struct peer *peer) * bgp_connect_check() as the handler for each and cancel the * unused event in that function. */ - event_add_read(bm->master, bgp_connect_check, peer, peer->fd, - &peer->t_connect_check_r); - event_add_write(bm->master, bgp_connect_check, peer, peer->fd, - &peer->t_connect_check_w); + event_add_read(bm->master, bgp_connect_check, peer, + peer->connection->fd, &peer->t_connect_check_r); + event_add_write(bm->master, bgp_connect_check, peer, + peer->connection->fd, &peer->t_connect_check_w); break; } return BGP_FSM_SUCCESS; } /* Connect retry timer is expired when the peer status is Connect. */ -static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_reconnect(struct peer_connection *connection) { + struct peer *peer = connection->peer; enum bgp_fsm_state_progress ret; - ret = bgp_stop(peer); + ret = bgp_stop(connection); if (ret < BGP_FSM_SUCCESS) return ret; @@ -1953,13 +1976,16 @@ static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer) BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, peer->bgp->peer); - return bgp_start(peer); + return bgp_start(connection); } -static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_open(struct peer_connection *connection) { + struct peer *peer = connection->peer; + /* If DelayOpen is active, we may still need to send an open message */ - if ((peer->status == Connect) || (peer->status == Active)) + if ((connection->status == Connect) || (connection->status == Active)) bgp_open_send(peer); /* Send keepalive and make keepalive timer */ @@ -1970,19 +1996,26 @@ static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer) /* FSM error, unexpected event. This is error of BGP connection. So cut the peer and change to Idle status. */ -static enum bgp_fsm_state_progress bgp_fsm_event_error(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_event_error(struct peer_connection *connection) { + struct peer *peer = connection->peer; + flog_err(EC_BGP_FSM, "%s [FSM] unexpected packet received in state %s", - peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); + peer->host, + lookup_msg(bgp_status_msg, connection->status, NULL)); return bgp_stop_with_notify(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); + bgp_fsm_error_subcode(connection->status)); } /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ -static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_holdtime_expire(struct peer_connection *connection) { + struct peer *peer = connection->peer; + if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Hold timer expire", peer->host); @@ -2000,8 +2033,10 @@ static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer) /* RFC 4271 DelayOpenTimer_Expires event */ static enum bgp_fsm_state_progress -bgp_fsm_delayopen_timer_expire(struct peer *peer) +bgp_fsm_delayopen_timer_expire(struct peer_connection *connection) { + struct peer *peer = connection->peer; + /* Stop the DelayOpenTimer */ EVENT_OFF(peer->t_delayopen); @@ -2092,7 +2127,8 @@ 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 enum bgp_fsm_state_progress bgp_establish(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_establish(struct peer_connection *connection) { afi_t afi; safi_t safi; @@ -2100,6 +2136,7 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; struct peer *other; int status; + struct peer *peer = connection->peer; other = peer->doppelganger; hash_release(peer->bgp->peerhash, peer); @@ -2282,13 +2319,14 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); } - if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { + if (peer->doppelganger && + (peer->doppelganger->connection->status != Deleted)) { if (bgp_debug_neighbor_events(peer)) zlog_debug( "[Event] Deleting stub connection for peer %s", peer->host); - if (peer->doppelganger->status > Active) + if (peer->doppelganger->connection->status > Active) bgp_notify_send(peer->doppelganger, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); else @@ -2311,43 +2349,48 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) } /* Keepalive packet is received. */ -static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_keepalive(struct peer_connection *connection) { - EVENT_OFF(peer->t_holdtime); + EVENT_OFF(connection->peer->t_holdtime); return BGP_FSM_SUCCESS; } /* Update packet is received. */ -static enum bgp_fsm_state_progress bgp_fsm_update(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_update(struct peer_connection *connection) { - EVENT_OFF(peer->t_holdtime); + EVENT_OFF(connection->peer->t_holdtime); return BGP_FSM_SUCCESS; } /* This is empty event. */ -static enum bgp_fsm_state_progress bgp_ignore(struct peer *peer) -{ - flog_err( - EC_BGP_FSM, - "%s [FSM] Ignoring event %s in state %s, prior events %s, %s, fd %d", - peer->host, bgp_event_str[peer->cur_event], - lookup_msg(bgp_status_msg, peer->status, NULL), - bgp_event_str[peer->last_event], - bgp_event_str[peer->last_major_event], peer->fd); +static enum bgp_fsm_state_progress bgp_ignore(struct peer_connection *connection) +{ + struct peer *peer = connection->peer; + + flog_err(EC_BGP_FSM, + "%s [FSM] Ignoring event %s in state %s, prior events %s, %s, fd %d", + peer->host, bgp_event_str[peer->cur_event], + lookup_msg(bgp_status_msg, connection->status, NULL), + bgp_event_str[peer->last_event], + bgp_event_str[peer->last_major_event], connection->fd); return BGP_FSM_SUCCESS; } /* This is to handle unexpected events.. */ -static enum bgp_fsm_state_progress bgp_fsm_exception(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_exception(struct peer_connection *connection) { - flog_err( - EC_BGP_FSM, - "%s [FSM] Unexpected event %s in state %s, prior events %s, %s, fd %d", - peer->host, bgp_event_str[peer->cur_event], - 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); + struct peer *peer = connection->peer; + + flog_err(EC_BGP_FSM, + "%s [FSM] Unexpected event %s in state %s, prior events %s, %s, fd %d", + peer->host, bgp_event_str[peer->cur_event], + lookup_msg(bgp_status_msg, connection->status, NULL), + bgp_event_str[peer->last_event], + bgp_event_str[peer->last_major_event], connection->fd); + return bgp_stop(connection); } void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) @@ -2355,7 +2398,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) if (!peer) return; - switch (peer->status) { + switch (peer->connection->status) { case Idle: if (has_valid_nexthops) BGP_EVENT_ADD(peer, BGP_Start); @@ -2388,7 +2431,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) /* Finite State Machine structure */ static const struct { - enum bgp_fsm_state_progress (*func)(struct peer *); + enum bgp_fsm_state_progress (*func)(struct peer_connection *); enum bgp_fsm_status next_state; } FSM[BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = { { @@ -2571,12 +2614,11 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) { enum bgp_fsm_status next; enum bgp_fsm_state_progress ret = 0; + int fsm_result = FSM_PEER_NOOP; struct peer *other; int passive_conn = 0; int dyn_nbr; - - /* default return code */ - ret = FSM_PEER_NOOP; + struct peer_connection *connection = peer->connection; other = peer->doppelganger; passive_conn = @@ -2584,33 +2626,38 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) dyn_nbr = peer_dynamic_neighbor(peer); /* Logging this event. */ - next = FSM[peer->status - 1][event - 1].next_state; + next = FSM[peer->connection->status - 1][event - 1].next_state; - if (bgp_debug_neighbor_events(peer) && peer->status != next) + if (bgp_debug_neighbor_events(peer) && peer->connection->status != next) zlog_debug("%s [FSM] %s (%s->%s), fd %d", peer->host, bgp_event_str[event], - lookup_msg(bgp_status_msg, peer->status, NULL), - lookup_msg(bgp_status_msg, next, NULL), peer->fd); + lookup_msg(bgp_status_msg, peer->connection->status, + NULL), + lookup_msg(bgp_status_msg, next, NULL), + peer->connection->fd); peer->last_event = peer->cur_event; peer->cur_event = event; /* Call function. */ - if (FSM[peer->status - 1][event - 1].func) - ret = (*(FSM[peer->status - 1][event - 1].func))(peer); + if (FSM[peer->connection->status - 1][event - 1].func) + ret = (*(FSM[peer->connection->status - 1][event - 1].func))( + peer->connection); - if (ret >= BGP_FSM_SUCCESS) { + switch (ret) { + case BGP_FSM_SUCCESS: + case BGP_FSM_SUCCESS_STATE_TRANSFER: if (ret == BGP_FSM_SUCCESS_STATE_TRANSFER && next == Established) { /* The case when doppelganger swap accurred in bgp_establish. Update the peer pointer accordingly */ - ret = FSM_PEER_TRANSFERRED; + fsm_result = FSM_PEER_TRANSFERRED; peer = other; } /* If status is changed. */ - if (next != peer->status) { + if (next != peer->connection->status) { bgp_fsm_change_status(peer, next); /* @@ -2620,14 +2667,14 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) * Opting for TRANSFERRED since transfer implies * session establishment. */ - if (ret != FSM_PEER_TRANSFERRED) - ret = FSM_PEER_TRANSITIONED; + if (fsm_result != FSM_PEER_TRANSFERRED) + fsm_result = FSM_PEER_TRANSITIONED; } /* Make sure timer is set. */ bgp_timer_set(peer); - - } else { + break; + case BGP_FSM_FAILURE: /* * If we got a return value of -1, that means there was an * error, restart the FSM. Since bgp_stop() was called on the @@ -2637,22 +2684,27 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) */ 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, last reset: %s", - peer->host, bgp_event_str[peer->cur_event], - lookup_msg(bgp_status_msg, peer->status, NULL), - bgp_event_str[peer->last_event], - bgp_event_str[peer->last_major_event], peer->fd, - peer_down_str[peer->last_reset]); - bgp_stop(peer); + flog_err(EC_BGP_FSM, + "%s [FSM] Failure handling event %s in state %s, prior events %s, %s, fd %d, last reset: %s", + peer->host, bgp_event_str[peer->cur_event], + lookup_msg(bgp_status_msg, connection->status, + NULL), + bgp_event_str[peer->last_event], + bgp_event_str[peer->last_major_event], + connection->fd, + peer_down_str[peer->last_reset]); + bgp_stop(connection); bgp_fsm_change_status(peer, Idle); bgp_timer_set(peer); } - ret = FSM_PEER_STOPPED; + fsm_result = FSM_PEER_STOPPED; + break; + case BGP_FSM_FAILURE_AND_DELETE: + fsm_result = FSM_PEER_STOPPED; + break; } - return ret; + return fsm_result; } /* BGP GR Code */ diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index daf31b266e..1f53ac6118 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -17,15 +17,14 @@ enum bgp_fsm_state_progress { /* Macro for BGP read, write and timer thread. */ #define BGP_TIMER_ON(T, F, V) \ do { \ - if ((peer->status != Deleted)) \ + if ((peer->connection->status != Deleted)) \ event_add_timer(bm->master, (F), peer, (V), &(T)); \ } while (0) -#define BGP_EVENT_ADD(P, E) \ - do { \ - if ((P)->status != Deleted) \ - event_add_event(bm->master, bgp_event, (P), (E), \ - NULL); \ +#define BGP_EVENT_ADD(P, E) \ + do { \ + if ((P)->connection->status != Deleted) \ + event_add_event(bm->master, bgp_event, (P), (E), NULL); \ } while (0) #define BGP_EVENT_FLUSH(P) \ @@ -115,7 +114,7 @@ enum bgp_fsm_state_progress { extern void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops); extern void bgp_event(struct event *event); extern int bgp_event_update(struct peer *, enum bgp_fsm_events event); -extern enum bgp_fsm_state_progress bgp_stop(struct peer *peer); +extern enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection); extern void bgp_timer_set(struct peer *); extern void bgp_routeadv_timer(struct event *event); extern void bgp_fsm_change_status(struct peer *peer, diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index a375bd6005..84e428cbc4 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -29,11 +29,11 @@ /* clang-format on */ /* forward declarations */ -static uint16_t bgp_write(struct peer *); -static uint16_t bgp_read(struct peer *peer, int *code_p); +static uint16_t bgp_write(struct peer_connection *connection); +static uint16_t bgp_read(struct peer_connection *connection, int *code_p); static void bgp_process_writes(struct event *event); static void bgp_process_reads(struct event *event); -static bool validate_header(struct peer *); +static bool validate_header(struct peer_connection *connection); /* generic i/o status codes */ #define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */ @@ -42,65 +42,69 @@ static bool validate_header(struct peer *); /* Thread external API ----------------------------------------------------- */ -void bgp_writes_on(struct peer *peer) +void bgp_writes_on(struct peer_connection *connection) { struct frr_pthread *fpt = bgp_pth_io; + struct peer *peer = connection->peer; + assert(fpt->running); - assert(peer->status != Deleted); - assert(peer->obuf); - assert(peer->ibuf); - assert(peer->ibuf_work); + assert(connection->status != Deleted); + assert(connection->obuf); + assert(connection->ibuf); + assert(connection->ibuf_work); assert(!peer->t_connect_check_r); assert(!peer->t_connect_check_w); - assert(peer->fd); + assert(connection->fd); - event_add_write(fpt->master, bgp_process_writes, peer, peer->fd, - &peer->t_write); - SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON); + event_add_write(fpt->master, bgp_process_writes, connection, + connection->fd, &connection->t_write); + SET_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON); } -void bgp_writes_off(struct peer *peer) +void bgp_writes_off(struct peer_connection *connection) { + struct peer *peer = connection->peer; struct frr_pthread *fpt = bgp_pth_io; assert(fpt->running); - event_cancel_async(fpt->master, &peer->t_write, NULL); + event_cancel_async(fpt->master, &connection->t_write, NULL); EVENT_OFF(peer->t_generate_updgrp_packets); - UNSET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON); + UNSET_FLAG(peer->connection->thread_flags, PEER_THREAD_WRITES_ON); } -void bgp_reads_on(struct peer *peer) +void bgp_reads_on(struct peer_connection *connection) { + struct peer *peer = connection->peer; struct frr_pthread *fpt = bgp_pth_io; assert(fpt->running); - assert(peer->status != Deleted); - assert(peer->ibuf); - assert(peer->fd); - assert(peer->ibuf_work); - assert(peer->obuf); + assert(connection->status != Deleted); + assert(connection->ibuf); + assert(connection->fd); + assert(connection->ibuf_work); + assert(connection->obuf); assert(!peer->t_connect_check_r); assert(!peer->t_connect_check_w); - assert(peer->fd); + assert(connection->fd); - event_add_read(fpt->master, bgp_process_reads, peer, peer->fd, - &peer->t_read); + event_add_read(fpt->master, bgp_process_reads, connection, + connection->fd, &connection->t_read); - SET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON); + SET_FLAG(connection->thread_flags, PEER_THREAD_READS_ON); } -void bgp_reads_off(struct peer *peer) +void bgp_reads_off(struct peer_connection *connection) { struct frr_pthread *fpt = bgp_pth_io; assert(fpt->running); - event_cancel_async(fpt->master, &peer->t_read, NULL); - EVENT_OFF(peer->t_process_packet); - EVENT_OFF(peer->t_process_packet_error); + event_cancel_async(fpt->master, &connection->t_read, NULL); + EVENT_OFF(connection->t_process_packet); + EVENT_OFF(connection->t_process_packet_error); - UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON); + UNSET_FLAG(connection->thread_flags, PEER_THREAD_READS_ON); } /* Thread internal functions ----------------------------------------------- */ @@ -111,19 +115,21 @@ void bgp_reads_off(struct peer *peer) static void bgp_process_writes(struct event *thread) { static struct peer *peer; - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); uint16_t status; bool reschedule; bool fatal = false; - if (peer->fd < 0) + peer = connection->peer; + + if (connection->fd < 0) return; struct frr_pthread *fpt = bgp_pth_io; - frr_with_mutex (&peer->io_mtx) { - status = bgp_write(peer); - reschedule = (stream_fifo_head(peer->obuf) != NULL); + frr_with_mutex (&connection->io_mtx) { + status = bgp_write(connection); + reschedule = (stream_fifo_head(connection->obuf) != NULL); } /* no problem */ @@ -142,26 +148,26 @@ static void bgp_process_writes(struct event *thread) * sent in the update message */ if (reschedule) { - event_add_write(fpt->master, bgp_process_writes, peer, peer->fd, - &peer->t_write); + event_add_write(fpt->master, bgp_process_writes, connection, + connection->fd, &connection->t_write); } else if (!fatal) { BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets, bgp_generate_updgrp_packets); } } -static int read_ibuf_work(struct peer *peer) +static int read_ibuf_work(struct peer_connection *connection) { /* static buffer for transferring packets */ /* shorter alias to peer's input buffer */ - struct ringbuf *ibw = peer->ibuf_work; + struct ringbuf *ibw = connection->ibuf_work; /* packet size as given by header */ uint16_t pktsize = 0; struct stream *pkt; /* ============================================== */ - frr_with_mutex (&peer->io_mtx) { - if (peer->ibuf->count >= bm->inq_limit) + frr_with_mutex (&connection->io_mtx) { + if (connection->ibuf->count >= bm->inq_limit) return -ENOMEM; } @@ -170,7 +176,7 @@ static int read_ibuf_work(struct peer *peer) return 0; /* check that header is valid */ - if (!validate_header(peer)) + if (!validate_header(connection)) return -EBADMSG; /* header is valid; retrieve packet size */ @@ -179,7 +185,7 @@ static int read_ibuf_work(struct peer *peer) pktsize = ntohs(pktsize); /* if this fails we are seriously screwed */ - assert(pktsize <= peer->max_packet_size); + assert(pktsize <= connection->peer->max_packet_size); /* * If we have that much data, chuck it into its own @@ -195,9 +201,9 @@ static int read_ibuf_work(struct peer *peer) assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize); stream_set_endp(pkt, pktsize); - frrtrace(2, frr_bgp, packet_read, peer, pkt); - frr_with_mutex (&peer->io_mtx) { - stream_fifo_push(peer->ibuf, pkt); + frrtrace(2, frr_bgp, packet_read, connection->peer, pkt); + frr_with_mutex (&connection->io_mtx) { + stream_fifo_push(connection->ibuf, pkt); } return pktsize; @@ -208,29 +214,31 @@ static int read_ibuf_work(struct peer *peer) * or has hung up. * * We read as much data as possible, process as many packets as we can and - * place them on peer->ibuf for secondary processing by the main thread. + * place them on peer->connection.ibuf for secondary processing by the main + * thread. */ static void bgp_process_reads(struct event *thread) { /* clang-format off */ + struct peer_connection *connection = EVENT_ARG(thread); static struct peer *peer; /* peer to read from */ uint16_t status; /* bgp_read status code */ bool fatal = false; /* whether fatal error occurred */ - bool added_pkt = false; /* whether we pushed onto ->ibuf */ + bool added_pkt = false; /* whether we pushed onto ->connection.ibuf */ int code = 0; /* FSM code if error occurred */ static bool ibuf_full_logged; /* Have we logged full already */ int ret = 1; /* clang-format on */ - peer = EVENT_ARG(thread); + peer = connection->peer; - if (bm->terminating || peer->fd < 0) + if (bm->terminating || connection->fd < 0) return; struct frr_pthread *fpt = bgp_pth_io; - frr_with_mutex (&peer->io_mtx) { - status = bgp_read(peer, &code); + frr_with_mutex (&connection->io_mtx) { + status = bgp_read(connection, &code); } /* error checking phase */ @@ -246,13 +254,13 @@ static void bgp_process_reads(struct event *thread) /* Handle the error in the main pthread, include the * specific state change from 'bgp_read'. */ - event_add_event(bm->master, bgp_packet_process_error, peer, - code, &peer->t_process_packet_error); + event_add_event(bm->master, bgp_packet_process_error, connection, + code, &connection->t_process_packet_error); goto done; } while (true) { - ret = read_ibuf_work(peer); + ret = read_ibuf_work(connection); if (ret <= 0) break; @@ -282,31 +290,33 @@ done: /* handle invalid header */ if (fatal) { /* wipe buffer just in case someone screwed up */ - ringbuf_wipe(peer->ibuf_work); + ringbuf_wipe(connection->ibuf_work); return; } - event_add_read(fpt->master, bgp_process_reads, peer, peer->fd, - &peer->t_read); + event_add_read(fpt->master, bgp_process_reads, connection, + connection->fd, &connection->t_read); if (added_pkt) - event_add_event(bm->master, bgp_process_packet, peer, 0, - &peer->t_process_packet); + event_add_event(bm->master, bgp_process_packet, connection, 0, + &connection->t_process_packet); } /* * Flush peer output buffer. * - * This function pops packets off of peer->obuf and writes them to peer->fd. - * The amount of packets written is equal to the minimum of peer->wpkt_quanta - * and the number of packets on the output buffer, unless an error occurs. + * This function pops packets off of peer->connection.obuf and writes them to + * peer->connection.fd. The amount of packets written is equal to the minimum of + * peer->wpkt_quanta and the number of packets on the output buffer, unless an + * error occurs. * * If write() returns an error, the appropriate FSM event is generated. * * The return value is equal to the number of packets written * (which may be zero). */ -static uint16_t bgp_write(struct peer *peer) +static uint16_t bgp_write(struct peer_connection *connection) { + struct peer *peer = connection->peer; uint8_t type; struct stream *s; int update_last_write = 0; @@ -328,7 +338,7 @@ static uint16_t bgp_write(struct peer *peer) struct stream **streams = ostreams; struct iovec iov[wpkt_quanta_old]; - s = stream_fifo_head(peer->obuf); + s = stream_fifo_head(connection->obuf); if (!s) goto done; @@ -348,7 +358,7 @@ static uint16_t bgp_write(struct peer *peer) total_written = 0; do { - num = writev(peer->fd, iov, iovsz); + num = writev(connection->fd, iov, iovsz); if (num < 0) { if (!ERRNO_IO_RETRY(errno)) { @@ -397,7 +407,7 @@ static uint16_t bgp_write(struct peer *peer) /* Handle statistics */ for (unsigned int i = 0; i < total_written; i++) { - s = stream_fifo_pop(peer->obuf); + s = stream_fifo_pop(connection->obuf); assert(s == ostreams[i]); @@ -476,7 +486,8 @@ done : { uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX]; /* - * Reads a chunk of data from peer->fd into peer->ibuf_work. + * Reads a chunk of data from peer->connection.fd into + * peer->connection.ibuf_work. * * code_p * Pointer to location to store FSM event code in case of fatal error. @@ -487,14 +498,14 @@ uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX] * per peer then we need to rethink the global ibuf_scratch * data structure above. */ -static uint16_t bgp_read(struct peer *peer, int *code_p) +static uint16_t bgp_read(struct peer_connection *connection, int *code_p) { size_t readsize; /* how many bytes we want to read */ ssize_t nbytes; /* how many bytes we actually read */ size_t ibuf_work_space; /* space we can read into the work buf */ uint16_t status = 0; - ibuf_work_space = ringbuf_space(peer->ibuf_work); + ibuf_work_space = ringbuf_space(connection->ibuf_work); if (ibuf_work_space == 0) { SET_FLAG(status, BGP_IO_WORK_FULL_ERR); @@ -503,7 +514,7 @@ static uint16_t bgp_read(struct peer *peer, int *code_p) readsize = MIN(ibuf_work_space, sizeof(ibuf_scratch)); - nbytes = read(peer->fd, ibuf_scratch, readsize); + nbytes = read(connection->fd, ibuf_scratch, readsize); /* EAGAIN or EWOULDBLOCK; come back later */ if (nbytes < 0 && ERRNO_IO_RETRY(errno)) { @@ -511,8 +522,8 @@ static uint16_t bgp_read(struct peer *peer, int *code_p) } else if (nbytes < 0) { /* Fatal error; tear down session */ flog_err(EC_BGP_UPDATE_RCV, - "%s [Error] bgp_read_packet error: %s", peer->host, - safe_strerror(errno)); + "%s [Error] bgp_read_packet error: %s", + connection->peer->host, safe_strerror(errno)); /* Handle the error in the main pthread. */ if (code_p) @@ -522,9 +533,9 @@ static uint16_t bgp_read(struct peer *peer, int *code_p) } else if (nbytes == 0) { /* Received EOF / TCP session closed */ - if (bgp_debug_neighbor_events(peer)) + if (bgp_debug_neighbor_events(connection->peer)) zlog_debug("%s [Event] BGP connection closed fd %d", - peer->host, peer->fd); + connection->peer->host, connection->fd); /* Handle the error in the main pthread. */ if (code_p) @@ -532,8 +543,8 @@ static uint16_t bgp_read(struct peer *peer, int *code_p) SET_FLAG(status, BGP_IO_FATAL_ERR); } else { - assert(ringbuf_put(peer->ibuf_work, ibuf_scratch, nbytes) == - (size_t)nbytes); + assert(ringbuf_put(connection->ibuf_work, ibuf_scratch, + nbytes) == (size_t)nbytes); } return status; @@ -546,11 +557,12 @@ static uint16_t bgp_read(struct peer *peer, int *code_p) * Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input * buffer. */ -static bool validate_header(struct peer *peer) +static bool validate_header(struct peer_connection *connection) { + struct peer *peer = connection->peer; uint16_t size; uint8_t type; - struct ringbuf *pkt = peer->ibuf_work; + struct ringbuf *pkt = connection->ibuf_work; static const uint8_t m_correct[BGP_MARKER_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 4c92373c2d..8d481129e5 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -14,6 +14,8 @@ #include "bgpd/bgpd.h" #include "frr_pthread.h" +struct peer_connection; + /** * Start function for write thread. * @@ -33,57 +35,57 @@ extern int bgp_io_stop(void **result, struct frr_pthread *fpt); /** * Turns on packet writing for a peer. * - * After this function is called, any packets placed on peer->obuf will be - * written to peer->fd until no more packets remain. + * After this function is called, any packets placed on connection->obuf will be + * written to connection->fd until no more packets remain. * - * Additionally, it becomes unsafe to perform socket actions on peer->fd. + * Additionally, it becomes unsafe to perform socket actions on connection->fd. * * @param peer - peer to register */ -extern void bgp_writes_on(struct peer *peer); +extern void bgp_writes_on(struct peer_connection *peer); /** * Turns off packet writing for a peer. * - * After this function returns, packets placed on peer->obuf will not be - * written to peer->fd by the I/O thread. + * After this function returns, packets placed on connection->obuf will not be + * written to connection->fd by the I/O thread. * * After this function returns it becomes safe to perform socket actions on - * peer->fd. + * connection->fd. * - * @param peer - peer to deregister + * @param connection - connection to deregister * @param flush - as described */ -extern void bgp_writes_off(struct peer *peer); +extern void bgp_writes_off(struct peer_connection *connection); /** * Turns on packet reading for a peer. * - * After this function is called, any packets received on peer->fd will be read - * and copied into the FIFO queue peer->ibuf. + * After this function is called, any packets received on connection->fd + * will be read and copied into the FIFO queue connection->ibuf. * - * Additionally, it becomes unsafe to perform socket actions on peer->fd. + * Additionally, it becomes unsafe to perform socket actions on connection->fd. * - * Whenever one or more packets are placed onto peer->ibuf, a task of type + * Whenever one or more packets are placed onto connection->ibuf, a task of type * THREAD_EVENT will be placed on the main thread whose handler is * * bgp_packet.c:bgp_process_packet() * - * @param peer - peer to register + * @param connection - The connection to register */ -extern void bgp_reads_on(struct peer *peer); +extern void bgp_reads_on(struct peer_connection *connection); /** * Turns off packet reading for a peer. * - * After this function is called, any packets received on peer->fd will not be - * read by the I/O thread. + * After this function is called, any packets received on connection->fd + * will not be read by the I/O thread. * * After this function returns it becomes safe to perform socket actions on - * peer->fd. + * connection->fd. * - * @param peer - peer to deregister + * @param connection - The connection to register for */ -extern void bgp_reads_off(struct peer *peer); +extern void bgp_reads_off(struct peer_connection *connection); #endif /* _FRR_BGP_IO_H */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 73fe00c7ab..c5e7f7be63 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -429,7 +429,7 @@ static void bgp_accept(struct event *thread) peer1 = peer_lookup_dynamic_neighbor(bgp, &su); if (peer1) { /* Dynamic neighbor has been created, let it proceed */ - peer1->fd = bgp_sock; + peer1->connection->fd = bgp_sock; /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) @@ -482,11 +482,12 @@ static void bgp_accept(struct event *thread) * Established and then the Clearing_Completed event is generated. Also, * block incoming connection in Deleted state. */ - if (peer1->status == Clearing || peer1->status == Deleted) { + if (peer1->connection->status == Clearing || + peer1->connection->status == Deleted) { if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] Closing incoming conn for %s (%p) state %d", - peer1->host, peer1, peer1->status); + zlog_debug("[Event] Closing incoming conn for %s (%p) state %d", + peer1->host, peer1, + peer1->connection->status); close(bgp_sock); return; } @@ -521,10 +522,9 @@ static void bgp_accept(struct event *thread) } if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] connection from %s fd %d, active peer status %d fd %d", - inet_sutop(&su, buf), bgp_sock, peer1->status, - peer1->fd); + zlog_debug("[Event] connection from %s fd %d, active peer status %d fd %d", + inet_sutop(&su, buf), bgp_sock, + peer1->connection->status, peer1->connection->fd); if (peer1->doppelganger) { /* We have an existing connection. Kill the existing one and run @@ -563,7 +563,7 @@ static void bgp_accept(struct event *thread) peer->doppelganger = peer1; peer1->doppelganger = peer; - peer->fd = bgp_sock; + peer->connection->fd = bgp_sock; frr_with_privs(&bgpd_privs) { vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); } @@ -684,13 +684,13 @@ static int bgp_update_source(struct peer *peer) if (bgp_update_address(ifp, &peer->su, &addr)) return -1; - ret = sockunion_bind(peer->fd, &addr, 0, &addr); + ret = sockunion_bind(peer->connection->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ if (peer->update_source) - ret = sockunion_bind(peer->fd, peer->update_source, 0, - peer->update_source); + ret = sockunion_bind(peer->connection->fd, peer->update_source, + 0, peer->update_source); return ret; } @@ -698,8 +698,10 @@ static int bgp_update_source(struct peer *peer) /* BGP try to connect to the peer. */ int bgp_connect(struct peer *peer) { - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_WRITES_ON)); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_READS_ON)); ifindex_t ifindex = 0; if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) { @@ -708,11 +710,12 @@ int bgp_connect(struct peer *peer) return 0; } frr_with_privs(&bgpd_privs) { - /* Make socket for the peer. */ - peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id, - bgp_get_bound_name(peer)); + /* Make socket for the peer. */ + peer->connection->fd = + vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id, + bgp_get_bound_name(peer)); } - if (peer->fd < 0) { + if (peer->connection->fd < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to create socket for connection to %s, error received: %s(%d)", @@ -721,18 +724,18 @@ int bgp_connect(struct peer *peer) return -1; } - set_nonblocking(peer->fd); + set_nonblocking(peer->connection->fd); /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) - sockopt_tcp_mss_set(peer->fd, peer->tcp_mss); + sockopt_tcp_mss_set(peer->connection->fd, peer->tcp_mss); - bgp_socket_set_buffer_size(peer->fd); + bgp_socket_set_buffer_size(peer->connection->fd); /* Set TCP keepalive when TCP keepalive is enabled */ - bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd); + bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->connection->fd); - if (bgp_set_socket_ttl(peer, peer->fd) < 0) { + if (bgp_set_socket_ttl(peer, peer->connection->fd) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)", @@ -742,15 +745,16 @@ int bgp_connect(struct peer *peer) return -1; } - sockopt_reuseaddr(peer->fd); - sockopt_reuseport(peer->fd); + sockopt_reuseaddr(peer->connection->fd); + sockopt_reuseport(peer->connection->fd); #ifdef IPTOS_PREC_INTERNETCONTROL frr_with_privs(&bgpd_privs) { if (sockunion_family(&peer->su) == AF_INET) - setsockopt_ipv4_tos(peer->fd, bm->tcp_dscp); + setsockopt_ipv4_tos(peer->connection->fd, bm->tcp_dscp); else if (sockunion_family(&peer->su) == AF_INET6) - setsockopt_ipv6_tclass(peer->fd, bm->tcp_dscp); + setsockopt_ipv6_tclass(peer->connection->fd, + bm->tcp_dscp); } #endif @@ -762,7 +766,7 @@ int bgp_connect(struct peer *peer) if (!BGP_PEER_SU_UNSPEC(peer)) bgp_md5_set(peer); - bgp_md5_set_connect(peer->fd, &peer->su, prefixlen, + bgp_md5_set_connect(peer->connection->fd, &peer->su, prefixlen, peer->password); } @@ -779,11 +783,11 @@ int bgp_connect(struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] Connect start to %s fd %d", peer->host, - peer->host, peer->fd); + peer->host, peer->connection->fd); /* Connect to the remote peer. */ - return sockunion_connect(peer->fd, &peer->su, htons(peer->port), - ifindex); + return sockunion_connect(peer->connection->fd, &peer->su, + htons(peer->port), ifindex); } /* After TCP connection is established. Get local address and port. */ @@ -799,10 +803,10 @@ int bgp_getsockname(struct peer *peer) peer->su_remote = NULL; } - peer->su_local = sockunion_getsockname(peer->fd); + peer->su_local = sockunion_getsockname(peer->connection->fd); if (!peer->su_local) return -1; - peer->su_remote = sockunion_getpeername(peer->fd); + peer->su_remote = sockunion_getpeername(peer->connection->fd); if (!peer->su_remote) return -1; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index e826548e69..9cb88a2d6d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -911,8 +911,18 @@ static int bgp_capability_software_version(struct peer *peer, return -1; } - if (len) { + if (len > BGP_MAX_SOFT_VERSION) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "%s: Received Software Version, but the length is too big, truncating, from peer %s", + __func__, peer->host); + stream_get(str, s, BGP_MAX_SOFT_VERSION); + stream_forward_getp(s, len - BGP_MAX_SOFT_VERSION); + len = BGP_MAX_SOFT_VERSION; + } else if (len) { stream_get(str, s, len); + } + + if (len) { str[len] = '\0'; XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 327c6b79fd..a9e772e243 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -111,15 +111,15 @@ static void bgp_packet_add(struct peer *peer, struct stream *s) uint32_t holdtime; intmax_t sendholdtime; - frr_with_mutex (&peer->io_mtx) { + frr_with_mutex (&peer->connection->io_mtx) { /* if the queue is empty, reset the "last OK" timestamp to * now, otherwise if we write another packet immediately * after it'll get confused */ - if (!stream_fifo_count_safe(peer->obuf)) + if (!stream_fifo_count_safe(peer->connection->obuf)) peer->last_sendq_ok = monotime(NULL); - stream_fifo_push(peer->obuf, s); + stream_fifo_push(peer->connection->obuf, s); delta = monotime(NULL) - peer->last_sendq_ok; @@ -477,7 +477,7 @@ void bgp_generate_updgrp_packets(struct event *thread) * let's stop adding to the outq if we are * already at the limit. */ - if (peer->obuf->count >= bm->outq_limit) { + if (peer->connection->obuf->count >= bm->outq_limit) { bgp_write_proceed_actions(peer); return; } @@ -605,10 +605,10 @@ void bgp_generate_updgrp_packets(struct event *thread) bpacket_queue_advance_peer(paf); } } while (s && (++generated < wpq) && - (peer->obuf->count <= bm->outq_limit)); + (peer->connection->obuf->count <= bm->outq_limit)); if (generated) - bgp_writes_on(peer); + bgp_writes_on(peer->connection); bgp_write_proceed_actions(peer); } @@ -637,7 +637,7 @@ void bgp_keepalive_send(struct peer *peer) /* Add packet to the peer. */ bgp_packet_add(peer, s); - bgp_writes_on(peer); + bgp_writes_on(peer->connection); } /* @@ -706,18 +706,18 @@ void bgp_open_send(struct peer *peer) /* Add packet to the peer. */ bgp_packet_add(peer, s); - bgp_writes_on(peer); + bgp_writes_on(peer->connection); } /* * Writes NOTIFICATION message directly to a peer socket without waiting for * the I/O thread. * - * There must be exactly one stream on the peer->obuf FIFO, and the data within - * this stream must match the format of a BGP NOTIFICATION message. + * There must be exactly one stream on the peer->connection->obuf FIFO, and the + * data within this stream must match the format of a BGP NOTIFICATION message. * Transmission is best-effort. * - * @requires peer->io_mtx + * @requires peer->connection->io_mtx * @param peer * @return 0 */ @@ -728,7 +728,7 @@ static void bgp_write_notify(struct peer *peer) struct stream *s; /* There should be at least one packet. */ - s = stream_fifo_pop(peer->obuf); + s = stream_fifo_pop(peer->connection->obuf); if (!s) return; @@ -739,7 +739,7 @@ static void bgp_write_notify(struct peer *peer) * socket is in nonblocking mode, if we can't deliver the NOTIFY, well, * we only care about getting a clean shutdown at this point. */ - ret = write(peer->fd, STREAM_DATA(s), stream_get_endp(s)); + ret = write(peer->connection->fd, STREAM_DATA(s), stream_get_endp(s)); /* * only connection reset/close gets counted as TCP_fatal_error, failure @@ -753,8 +753,8 @@ static void bgp_write_notify(struct peer *peer) /* Disable Nagle, make NOTIFY packet go out right away */ val = 1; - (void)setsockopt(peer->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, - sizeof(val)); + (void)setsockopt(peer->connection->fd, IPPROTO_TCP, TCP_NODELAY, + (char *)&val, sizeof(val)); /* Retrieve BGP packet type. */ stream_set_getp(s, BGP_MARKER_SIZE + 2); @@ -910,7 +910,7 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, bool hard_reset = bgp_notify_send_hard_reset(peer, code, sub_code); /* Lock I/O mutex to prevent other threads from pushing packets */ - frr_mutex_lock_autounlock(&peer->io_mtx); + frr_mutex_lock_autounlock(&peer->connection->io_mtx); /* ============================================== */ /* Allocate new stream. */ @@ -943,7 +943,7 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, bgp_packet_set_size(s); /* wipe output buffer */ - stream_fifo_clean(peer->obuf); + stream_fifo_clean(peer->connection->obuf); /* * If possible, store last packet for debugging purposes. This check is @@ -1028,7 +1028,7 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, peer->last_reset = PEER_DOWN_NOTIFY_SEND; /* Add packet to peer's output queue */ - stream_fifo_push(peer->obuf, s); + stream_fifo_push(peer->connection->obuf, s); bgp_peer_gr_flags_update(peer); BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, @@ -1181,7 +1181,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, /* Add packet to the peer. */ bgp_packet_add(peer, s); - bgp_writes_on(peer); + bgp_writes_on(peer->connection); } /* @@ -1299,7 +1299,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, /* Add packet to the peer. */ bgp_packet_add(peer, s); - bgp_writes_on(peer); + bgp_writes_on(peer->connection); } /* RFC1771 6.8 Connection collision detection. */ @@ -1326,13 +1326,14 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) * states. Note that a peer GR is handled by closing the existing * connection upon receipt of new one. */ - if (peer_established(peer) || peer->status == Clearing) { + if (peer_established(peer) || peer->connection->status == Clearing) { bgp_notify_send(new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } - if ((peer->status != OpenConfirm) && (peer->status != OpenSent)) + if ((peer->connection->status != OpenConfirm) && + (peer->connection->status != OpenSent)) return 0; /* @@ -1413,7 +1414,7 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) * Side effects * ------------ * - May send NOTIFY messages - * - May not modify peer->status + * - May not modify peer->connection->status * - May not call bgp_event_update() */ @@ -1812,7 +1813,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) return BGP_Stop; } } - peer->rtt = sockopt_tcp_rtt(peer->fd); + peer->rtt = sockopt_tcp_rtt(peer->connection->fd); return Receive_OPEN_message; } @@ -1831,7 +1832,7 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size) bgp_update_implicit_eors(peer); - peer->rtt = sockopt_tcp_rtt(peer->fd); + peer->rtt = sockopt_tcp_rtt(peer->connection->fd); /* If the peer's RTT is higher than expected, shutdown * the peer automatically. @@ -1921,9 +1922,10 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_INVALID_STATUS, "%s [FSM] Update packet received under status %s", peer->host, - lookup_msg(bgp_status_msg, peer->status, NULL)); + lookup_msg(bgp_status_msg, peer->connection->status, + NULL)); bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); + bgp_fsm_error_subcode(peer->connection->status)); return BGP_Stop; } @@ -2047,7 +2049,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) /* Network Layer Reachability Information. */ update_len = end - stream_pnt(s); - if (update_len) { + if (update_len && attribute_len) { /* Set NLRI portion to structure. */ nlris[NLRI_UPDATE].afi = AFI_IP; nlris[NLRI_UPDATE].safi = SAFI_UNICAST; @@ -2369,13 +2371,13 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) /* Status must be Established. */ if (!peer_established(peer)) { - flog_err( - EC_BGP_INVALID_STATUS, - "%s [Error] Route refresh packet received under status %s", - peer->host, - lookup_msg(bgp_status_msg, peer->status, NULL)); + flog_err(EC_BGP_INVALID_STATUS, + "%s [Error] Route refresh packet received under status %s", + peer->host, + lookup_msg(bgp_status_msg, peer->connection->status, + NULL)); bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); + bgp_fsm_error_subcode(peer->connection->status)); return BGP_Stop; } @@ -2471,7 +2473,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) * and 7 bytes of ORF Address-filter entry from * the stream */ - if (*p_pnt & ORF_COMMON_PART_REMOVE_ALL) { + if (p_pnt < p_end && + *p_pnt & ORF_COMMON_PART_REMOVE_ALL) { if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP rcvd Remove-All pfxlist ORF request", @@ -2957,13 +2960,13 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size) /* Status must be Established. */ if (!peer_established(peer)) { - flog_err( - EC_BGP_NO_CAP, - "%s [Error] Dynamic capability packet received under status %s", - peer->host, - lookup_msg(bgp_status_msg, peer->status, NULL)); + flog_err(EC_BGP_NO_CAP, + "%s [Error] Dynamic capability packet received under status %s", + peer->host, + lookup_msg(bgp_status_msg, peer->connection->status, + NULL)); bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->status)); + bgp_fsm_error_subcode(peer->connection->status)); return BGP_Stop; } @@ -2989,17 +2992,19 @@ void bgp_process_packet(struct event *thread) { /* Yes first of all get peer pointer. */ struct peer *peer; // peer + struct peer_connection *connection; uint32_t rpkt_quanta_old; // how many packets to read int fsm_update_result; // return code of bgp_event_update() int mprc; // message processing return code - peer = EVENT_ARG(thread); + connection = EVENT_ARG(thread); + peer = connection->peer; rpkt_quanta_old = atomic_load_explicit(&peer->bgp->rpkt_quanta, memory_order_relaxed); fsm_update_result = 0; /* Guard against scheduled events that occur after peer deletion. */ - if (peer->status == Deleted || peer->status == Clearing) + if (connection->status == Deleted || connection->status == Clearing) return; unsigned int processed = 0; @@ -3009,8 +3014,8 @@ void bgp_process_packet(struct event *thread) bgp_size_t size; char notify_data_length[2]; - frr_with_mutex (&peer->io_mtx) { - peer->curr = stream_fifo_pop(peer->ibuf); + frr_with_mutex (&connection->io_mtx) { + peer->curr = stream_fifo_pop(connection->ibuf); } if (peer->curr == NULL) // no packets to process, hmm... @@ -3136,12 +3141,12 @@ void bgp_process_packet(struct event *thread) if (fsm_update_result != FSM_PEER_TRANSFERRED && fsm_update_result != FSM_PEER_STOPPED) { - frr_with_mutex (&peer->io_mtx) { + frr_with_mutex (&connection->io_mtx) { // more work to do, come back later - if (peer->ibuf->count > 0) + if (connection->ibuf->count > 0) event_add_event(bm->master, bgp_process_packet, - peer, 0, - &peer->t_process_packet); + connection, 0, + &connection->t_process_packet); } } } @@ -3164,15 +3169,17 @@ void bgp_send_delayed_eor(struct bgp *bgp) */ void bgp_packet_process_error(struct event *thread) { + struct peer_connection *connection; struct peer *peer; int code; - peer = EVENT_ARG(thread); + connection = EVENT_ARG(thread); + peer = connection->peer; code = EVENT_VAL(thread); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s [Event] BGP error %d on fd %d", - peer->host, code, peer->fd); + zlog_debug("%s [Event] BGP error %d on fd %d", peer->host, code, + connection->fd); /* Closed connection or error on the socket */ if (peer_established(peer)) { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3b3cbb28a9..dce8859bc8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2754,13 +2754,11 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, continue; if (BGP_PATH_HOLDDOWN(pi2)) continue; - if (pi2->peer != bgp->peer_self - && !CHECK_FLAG( - pi2->peer->sflags, - PEER_STATUS_NSF_WAIT)) - if (pi2->peer->status - != Established) - continue; + if (pi2->peer != bgp->peer_self && + !CHECK_FLAG(pi2->peer->sflags, + PEER_STATUS_NSF_WAIT) && + !peer_established(pi2->peer)) + continue; if (!aspath_cmp_left(pi1->attr->aspath, pi2->attr->aspath) @@ -9674,9 +9672,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, } } - label = decode_label(&path->extra->label[0]); - - if (bgp_is_valid_label(&label)) { + if (bgp_is_valid_label(&path->extra->label[0])) { + label = decode_label(&path->extra->label[0]); if (json) { json_object_int_add(json_out, "notag", label); json_object_array_add(json, json_out); diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c index 68df175c18..b37385812e 100644 --- a/bgpd/bgp_script.c +++ b/bgpd/bgp_script.c @@ -26,7 +26,8 @@ void lua_pushpeer(lua_State *L, const struct peer *peer) lua_setfield(L, -2, "remote_id"); lua_pushinaddr(L, &peer->local_id); lua_setfield(L, -2, "local_id"); - lua_pushstring(L, lookup_msg(bgp_status_msg, peer->status, NULL)); + lua_pushstring(L, lookup_msg(bgp_status_msg, peer->connection->status, + NULL)); lua_setfield(L, -2, "state"); lua_pushstring(L, peer->desc ? peer->desc : ""); lua_setfield(L, -2, "description"); diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c index 123d33bd14..8af87ae4b2 100644 --- a/bgpd/bgp_snmp_bgp4.c +++ b/bgpd/bgp_snmp_bgp4.c @@ -251,7 +251,7 @@ static uint8_t *bgpPeerTable(struct variable *v, oid name[], size_t *length, case BGPPEERIDENTIFIER: return SNMP_IPADDRESS(peer->remote_id); case BGPPEERSTATE: - return SNMP_INTEGER(peer->status); + return SNMP_INTEGER(peer->connection->status); case BGPPEERADMINSTATUS: *write_method = write_bgpPeerTable; #define BGP_PeerAdmin_stop 1 @@ -756,7 +756,8 @@ int bgpTrapEstablished(struct peer *peer) oid index[sizeof(oid) * IN_ADDR_SIZE]; /* Check if this peer just went to Established */ - if ((peer->ostatus != OpenConfirm) || !(peer_established(peer))) + if ((peer->connection->ostatus != OpenConfirm) || + !(peer_established(peer))) return 0; ret = inet_aton(peer->host, &addr); diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 712b5d4af8..5e77a9297b 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -265,7 +265,7 @@ static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length, else return SNMP_INTEGER(BGP_PEER_ADMIN_STATUS_RUNNING); case BGP4V2_PEER_STATE: - return SNMP_INTEGER(peer->status); + return SNMP_INTEGER(peer->connection->status); case BGP4V2_PEER_DESCRIPTION: if (peer->desc) return SNMP_STRING(peer->desc); diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 3213b29d99..964393a9f5 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -54,9 +54,9 @@ PKT_PROCESS_TRACEPOINT_INSTANCE(refresh_process) TRACEPOINT_EVENT( frr_bgp, packet_read, - TP_ARGS(struct peer *, peer, struct stream *, pkt), + TP_ARGS(struct peer_connection *, connection, struct stream *, pkt), TP_FIELDS( - ctf_string(peer, PEER_HOSTNAME(peer)) + ctf_string(peer, PEER_HOSTNAME(connection->peer)) ctf_sequence_hex(uint8_t, packet, pkt->data, size_t, STREAM_READABLE(pkt)) ) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index be0fe42837..445dea92d5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2888,7 +2888,7 @@ DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_AS_SETS_REJECT; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -2914,7 +2914,7 @@ DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_AS_SETS_REJECT; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -4851,7 +4851,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY); /* v6only flag changed. Reset bgp seesion */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5040,7 +5040,7 @@ DEFUN (no_neighbor, peer_notify_unconfig(peer); peer_delete(peer); - if (other && other->status != Deleted) { + if (other && other->connection->status != Deleted) { peer_notify_unconfig(other); peer_delete(other); } @@ -11748,12 +11748,16 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, PEER_TOTAL_TX(peer)); atomic_size_t outq_count, inq_count; - outq_count = atomic_load_explicit( - &peer->obuf->count, - memory_order_relaxed); - inq_count = atomic_load_explicit( - &peer->ibuf->count, - memory_order_relaxed); + outq_count = + atomic_load_explicit(&peer->connection + ->obuf + ->count, + memory_order_relaxed); + inq_count = + atomic_load_explicit(&peer->connection + ->ibuf + ->count, + memory_order_relaxed); json_object_int_add( json_peer, "tableVersion", @@ -11789,7 +11793,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_string_add( json_peer, "state", lookup_msg(bgp_status_msg, - peer->status, NULL)); + peer->connection->status, + NULL)); else if (CHECK_FLAG( peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) @@ -11800,7 +11805,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_string_add( json_peer, "state", lookup_msg(bgp_status_msg, - peer->status, NULL)); + peer->connection->status, + NULL)); /* BGP peer state */ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN) @@ -11916,12 +11922,16 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, " "); atomic_size_t outq_count, inq_count; - outq_count = atomic_load_explicit( - &peer->obuf->count, - memory_order_relaxed); - inq_count = atomic_load_explicit( - &peer->ibuf->count, - memory_order_relaxed); + outq_count = + atomic_load_explicit(&peer->connection + ->obuf + ->count, + memory_order_relaxed); + inq_count = + atomic_load_explicit(&peer->connection + ->ibuf + ->count, + memory_order_relaxed); vty_out(vty, "4"); vty_out(vty, ASN_FORMAT_SPACE(bgp->asnotation), @@ -11993,7 +12003,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, else vty_out(vty, " %12s", lookup_msg(bgp_status_msg, - peer->status, NULL)); + peer->connection + ->status, + NULL)); vty_out(vty, " %8u", 0); } @@ -13573,9 +13585,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, "nbrCommonAdmin"); /* Status. */ - json_object_string_add( - json_neigh, "bgpState", - lookup_msg(bgp_status_msg, p->status, NULL)); + json_object_string_add(json_neigh, "bgpState", + lookup_msg(bgp_status_msg, + p->connection->status, NULL)); if (peer_established(p)) { time_t uptime; @@ -13593,9 +13605,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_int_add(json_neigh, "bgpTimerUpEstablishedEpoch", epoch_tbuf); - } - - else if (p->status == Active) { + } else if (p->connection->status == Active) { if (CHECK_FLAG(p->flags, PEER_FLAG_PASSIVE)) json_object_string_add(json_neigh, "bgpStateIs", "passive"); @@ -13656,7 +13666,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* Configured and Synced tcp-mss value for peer */ if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { - sync_tcp_mss = sockopt_tcp_mss_get(p->fd); + sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); json_object_int_add(json_neigh, "bgpTcpMssConfigured", p->tcp_mss); json_object_int_add(json_neigh, "bgpTcpMssSynced", @@ -13701,14 +13711,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* Status. */ vty_out(vty, " BGP state = %s", - lookup_msg(bgp_status_msg, p->status, NULL)); + lookup_msg(bgp_status_msg, p->connection->status, NULL)); if (peer_established(p)) vty_out(vty, ", up for %8s", peer_uptime(p->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL)); - - else if (p->status == Active) { + else if (p->connection->status == Active) { if (CHECK_FLAG(p->flags, PEER_FLAG_PASSIVE)) vty_out(vty, " (passive)"); else if (CHECK_FLAG(p->sflags, PEER_STATUS_NSF_WAIT)) @@ -13743,7 +13752,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* Configured and synced tcp-mss value for peer */ if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { - sync_tcp_mss = sockopt_tcp_mss_get(p->fd); + sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); } @@ -14717,9 +14726,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* Packet counts. */ atomic_size_t outq_count, inq_count; - outq_count = atomic_load_explicit(&p->obuf->count, + outq_count = atomic_load_explicit(&p->connection->obuf->count, memory_order_relaxed); - inq_count = atomic_load_explicit(&p->ibuf->count, + inq_count = atomic_load_explicit(&p->connection->ibuf->count, memory_order_relaxed); json_object_int_add(json_stat, "depthInq", @@ -14770,9 +14779,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, notify_out, notify_in, update_out, update_in, keepalive_out, keepalive_in, refresh_out, refresh_in, dynamic_cap_out, dynamic_cap_in; - outq_count = atomic_load_explicit(&p->obuf->count, + outq_count = atomic_load_explicit(&p->connection->obuf->count, memory_order_relaxed); - inq_count = atomic_load_explicit(&p->ibuf->count, + inq_count = atomic_load_explicit(&p->connection->ibuf->count, memory_order_relaxed); open_out = atomic_load_explicit(&p->open_out, memory_order_relaxed); @@ -15116,12 +15125,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_int_add(json_neigh, "authenticationEnabled", 1); - if (p->t_read) + if (p->connection->t_read) json_object_string_add(json_neigh, "readThread", "on"); else json_object_string_add(json_neigh, "readThread", "off"); - if (CHECK_FLAG(p->thread_flags, PEER_THREAD_WRITES_ON)) + if (CHECK_FLAG(p->connection->thread_flags, + PEER_THREAD_WRITES_ON)) json_object_string_add(json_neigh, "writeThread", "on"); else json_object_string_add(json_neigh, "writeThread", @@ -15152,10 +15162,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "Peer Authentication Enabled\n"); vty_out(vty, "Read thread: %s Write thread: %s FD used: %d\n", - p->t_read ? "on" : "off", - CHECK_FLAG(p->thread_flags, PEER_THREAD_WRITES_ON) + p->connection->t_read ? "on" : "off", + CHECK_FLAG(p->connection->thread_flags, + PEER_THREAD_WRITES_ON) ? "on" - : "off", p->fd); + : "off", + p->connection->fd); } if (p->notify.code == BGP_NOTIFY_OPEN_ERR @@ -16419,8 +16431,10 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, PEER_STATUS_PREFIX_OVERFLOW)) peer_status = "Idle (PfxCt)"; else - peer_status = lookup_msg(bgp_status_msg, - peer->status, NULL); + peer_status = + lookup_msg(bgp_status_msg, + peer->connection->status, + NULL); dynamic = peer_dynamic_neighbor(peer); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index aaf1f41c4b..730c96cdda 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -80,6 +80,7 @@ #include "bgp_trace.h" DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)"); +DEFINE_MTYPE_STATIC(BGPD, BGP_PEER_CONNECTION, "BGP Connection information"); DEFINE_QOBJ_TYPE(bgp_master); DEFINE_QOBJ_TYPE(bgp); DEFINE_QOBJ_TYPE(peer); @@ -134,8 +135,9 @@ static int bgp_check_main_socket(bool create, struct bgp *bgp) void bgp_session_reset(struct peer *peer) { - if (peer->doppelganger && (peer->doppelganger->status != Deleted) - && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE))) + if (peer->doppelganger && + (peer->doppelganger->connection->status != Deleted) && + !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); BGP_EVENT_ADD(peer, BGP_Stop); @@ -155,9 +157,9 @@ static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) n = (nnode) ? *nnode : NULL; npeer = (n) ? listgetdata(n) : NULL; - if (peer->doppelganger && (peer->doppelganger->status != Deleted) - && !(CHECK_FLAG(peer->doppelganger->flags, - PEER_FLAG_CONFIG_NODE))) { + if (peer->doppelganger && + (peer->doppelganger->connection->status != Deleted) && + !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE))) { if (peer->doppelganger == npeer) /* nnode and *nnode are confirmed to be non-NULL here */ *nnode = (*nnode)->next; @@ -305,7 +307,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY(&peer->local_id, id); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -484,7 +486,7 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -508,7 +510,7 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -581,7 +583,7 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) if (ptype == BGP_PEER_EBGP) { peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->status)) { + peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send( @@ -599,7 +601,7 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) if (ptype == BGP_PEER_EBGP) peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->status)) { + peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send( @@ -626,7 +628,8 @@ void bgp_confederation_id_unset(struct bgp *bgp) /* We're looking for peers who's AS is not local */ if (peer_sort(peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -680,7 +683,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str) peer->local_as = bgp->as; (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->status)) { + peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send( @@ -737,7 +740,7 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) peer->local_as = bgp->confed_id; (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->status)) { + peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send( @@ -1110,12 +1113,80 @@ enum bgp_peer_sort peer_sort_lookup(struct peer *peer) return peer->sort; } +/* + * Mutex will be freed in peer_connection_free + * this is a convenience function to reduce cut-n-paste + */ +void bgp_peer_connection_buffers_free(struct peer_connection *connection) +{ + frr_with_mutex (&connection->io_mtx) { + if (connection->ibuf) { + stream_fifo_free(connection->ibuf); + connection->ibuf = NULL; + } + + if (connection->obuf) { + stream_fifo_free(connection->obuf); + connection->obuf = NULL; + } + + if (connection->ibuf_work) { + ringbuf_del(connection->ibuf_work); + connection->ibuf_work = NULL; + } + } +} + +static void bgp_peer_connection_free(struct peer_connection *connection) +{ + bgp_peer_connection_buffers_free(connection); + pthread_mutex_destroy(&connection->io_mtx); + + memset(connection, 0, sizeof(struct peer_connection)); + XFREE(MTYPE_BGP_PEER_CONNECTION, connection); +} + +struct peer_connection *bgp_peer_connection_new(struct peer *peer) +{ + struct peer_connection *connection; + + connection = XCALLOC(MTYPE_BGP_PEER_CONNECTION, + sizeof(struct peer_connection)); + + connection->peer = peer; + connection->fd = -1; + + connection->ibuf = stream_fifo_new(); + connection->obuf = stream_fifo_new(); + pthread_mutex_init(&connection->io_mtx, NULL); + + /* We use a larger buffer for peer->obuf_work in the event that: + * - We RX a BGP_UPDATE where the attributes alone are just + * under BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE. + * - The user configures an outbound route-map that does many as-path + * prepends or adds many communities. At most they can have + * CMD_ARGC_MAX args in a route-map so there is a finite limit on how + * large they can make the attributes. + * + * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid + * bounds checking for every single attribute as we construct an + * UPDATE. + */ + connection->ibuf_work = + ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX); + + connection->status = Idle; + connection->ostatus = Idle; + + return connection; +} + static void peer_free(struct peer *peer) { afi_t afi; safi_t safi; - assert(peer->status == Deleted); + assert(peer->connection->status == Deleted); QOBJ_UNREG(peer); @@ -1123,17 +1194,15 @@ static void peer_free(struct peer *peer) * but just to be sure.. */ bgp_timer_set(peer); - bgp_reads_off(peer); - bgp_writes_off(peer); + bgp_reads_off(peer->connection); + bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer); FOREACH_AFI_SAFI (afi, safi) EVENT_OFF(peer->t_revalidate_all[afi][safi]); - assert(!peer->t_write); - assert(!peer->t_read); + assert(!peer->connection->t_write); + assert(!peer->connection->t_read); BGP_EVENT_FLUSH(peer); - pthread_mutex_destroy(&peer->io_mtx); - /* Free connected nexthop, if present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && !peer_dynamic_neighbor(peer)) @@ -1187,6 +1256,8 @@ static void peer_free(struct peer *peer) if (peer->as_pretty) XFREE(MTYPE_BGP, peer->as_pretty); + bgp_peer_connection_free(peer->connection); + bgp_unlock(peer->bgp); stream_free(peer->last_reset_cause); @@ -1368,12 +1439,12 @@ struct peer *peer_new(struct bgp *bgp) /* Allocate new peer. */ peer = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer)); + /* Create buffers. */ + peer->connection = bgp_peer_connection_new(peer); + /* Set default value. */ - peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = bgp->default_connect_retry; - peer->status = Idle; - peer->ostatus = Idle; peer->cur_event = peer->last_event = peer->last_major_event = 0; peer->bgp = bgp_lock(bgp); peer = peer_lock(peer); /* initial reference */ @@ -1410,14 +1481,6 @@ struct peer *peer_new(struct bgp *bgp) /* Initialize per peer bgp GR FSM */ bgp_peer_gr_init(peer); - /* Create buffers. */ - peer->ibuf = stream_fifo_new(); - peer->obuf = stream_fifo_new(); - pthread_mutex_init(&peer->io_mtx, NULL); - - peer->ibuf_work = - ringbuf_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE/2); - /* Get service port number. */ sp = getservbyname("bgp", "tcp"); peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs(sp->s_port); @@ -1894,7 +1957,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -2266,7 +2329,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } - if (peer->status == OpenSent || peer->status == OpenConfirm) { + if (peer->connection->status == OpenSent || + peer->connection->status == OpenConfirm) { peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -2281,9 +2345,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) * activation. */ other = peer->doppelganger; - if (other - && (other->status == OpenSent - || other->status == OpenConfirm)) { + if (other && (other->connection->status == OpenSent || + other->connection->status == OpenConfirm)) { other->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(other, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -2504,7 +2567,7 @@ int peer_delete(struct peer *peer) struct listnode *pn; int accept_peer; - assert(peer->status != Deleted); + assert(peer->connection->status != Deleted); bgp = peer->bgp; accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); @@ -2512,13 +2575,15 @@ int peer_delete(struct peer *peer) bgp_soft_reconfig_table_task_cancel(bgp, NULL, peer); bgp_keepalives_off(peer); - bgp_reads_off(peer); - bgp_writes_off(peer); + bgp_reads_off(peer->connection); + bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer); FOREACH_AFI_SAFI (afi, safi) EVENT_OFF(peer->t_revalidate_all[afi][safi]); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_WRITES_ON)); + assert(!CHECK_FLAG(peer->connection->thread_flags, + PEER_THREAD_READS_ON)); assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -2549,7 +2614,7 @@ int peer_delete(struct peer *peer) * executed after peer structure is deleted. */ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; - bgp_stop(peer); + bgp_stop(peer->connection); UNSET_FLAG(peer->flags, PEER_FLAG_DELETE); if (peer->doppelganger) { @@ -2590,22 +2655,6 @@ int peer_delete(struct peer *peer) peer_unlock(peer); /* bgp peer list reference */ } - /* Buffers. */ - if (peer->ibuf) { - stream_fifo_free(peer->ibuf); - peer->ibuf = NULL; - } - - if (peer->obuf) { - stream_fifo_free(peer->obuf); - peer->obuf = NULL; - } - - if (peer->ibuf_work) { - ringbuf_del(peer->ibuf_work); - peer->ibuf_work = NULL; - } - /* Local and remote addresses. */ if (peer->su_local) { sockunion_free(peer->su_local); @@ -2856,7 +2905,7 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, void peer_notify_unconfig(struct peer *peer) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); } @@ -2871,7 +2920,7 @@ static void peer_notify_shutdown(struct peer *peer) return; } - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } @@ -2883,7 +2932,7 @@ void peer_group_notify_unconfig(struct peer_group *group) for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { other = peer->doppelganger; - if (other && other->status != Deleted) { + if (other && other->connection->status != Deleted) { other->group = NULL; peer_notify_unconfig(other); } else @@ -2909,7 +2958,7 @@ int peer_group_delete(struct peer_group *group) bgp_zebra_terminate_radv(bgp, peer); peer_delete(peer); - if (other && other->status != Deleted) { + if (other && other->connection->status != Deleted) { other->group = NULL; peer_delete(other); } @@ -2958,7 +3007,7 @@ int peer_group_remote_as_delete(struct peer_group *group) peer_delete(peer); - if (other && other->status != Deleted) { + if (other && other->connection->status != Deleted) { other->group = NULL; peer_delete(other); } @@ -3138,7 +3187,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -3694,7 +3743,7 @@ void bgp_instance_down(struct bgp *bgp) /* Bring down peers, so corresponding routes are purged. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else @@ -4377,10 +4426,10 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, if (type == peer_change_reset) { /* If we're resetting session, we've to delete both peer struct */ - if ((peer->doppelganger) - && (peer->doppelganger->status != Deleted) - && (!CHECK_FLAG(peer->doppelganger->flags, - PEER_FLAG_CONFIG_NODE))) + if ((peer->doppelganger) && + (peer->doppelganger->connection->status != Deleted) && + (!CHECK_FLAG(peer->doppelganger->flags, + PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); bgp_notify_send(peer, BGP_NOTIFY_CEASE, @@ -4390,10 +4439,10 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, bgp_route_refresh_send(peer, afi, safi, 0, 0, 0, BGP_ROUTE_REFRESH_NORMAL); else { - if ((peer->doppelganger) - && (peer->doppelganger->status != Deleted) - && (!CHECK_FLAG(peer->doppelganger->flags, - PEER_FLAG_CONFIG_NODE))) + if ((peer->doppelganger) && + (peer->doppelganger->connection->status != Deleted) && + (!CHECK_FLAG(peer->doppelganger->flags, + PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); bgp_notify_send(peer, BGP_NOTIFY_CEASE, @@ -4549,7 +4598,8 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) peer); } - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) { char *msg = peer->tx_shutdown_message; size_t msglen; uint8_t msgbuf[BGP_ADMIN_SHUTDOWN_MSG_LEN + 1]; @@ -4579,7 +4629,7 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) peer->v_start = BGP_INIT_START_TIMER; BGP_EVENT_ADD(peer, BGP_Stop); } - } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_PASSIVE) @@ -4616,7 +4666,7 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) continue; /* send a RFC 4486 notification message if necessary */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { if (msg) { size_t datalen = strlen(msg); @@ -5038,7 +5088,8 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (peer->sort != BGP_PEER_IBGP) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -5056,7 +5107,8 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) peer->ttl = group->conf->ttl; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -5093,7 +5145,7 @@ int peer_ebgp_multihop_unset(struct peer *peer) peer->ttl = ttl; if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -5110,8 +5162,9 @@ int peer_ebgp_multihop_unset(struct peer *peer) peer->ttl = BGP_DEFAULT_TTL; - if (peer->fd >= 0) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (peer->connection->fd >= 0) { + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) bgp_notify_send( peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5266,7 +5319,7 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5304,7 +5357,7 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) member->update_source = NULL; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5337,7 +5390,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5374,7 +5427,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5425,7 +5478,7 @@ void peer_update_source_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -5461,7 +5514,7 @@ void peer_update_source_unset(struct peer *peer) XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -6426,7 +6479,7 @@ int peer_local_as_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -6454,7 +6507,7 @@ int peer_local_as_unset(struct peer *peer) XFREE(MTYPE_BGP, member->change_local_as_pretty); /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -6486,7 +6539,7 @@ int peer_password_set(struct peer *peer, const char *password) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -6522,7 +6575,7 @@ int peer_password_set(struct peer *peer, const char *password) member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -6567,7 +6620,7 @@ int peer_password_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -6594,7 +6647,7 @@ int peer_password_unset(struct peer *peer) XFREE(MTYPE_PEER_PASSWORD, member->password); /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else @@ -7795,13 +7848,15 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { peer->gtsm_hops = gtsm_hops; - if (peer->fd >= 0) - sockopt_minttl(peer->su.sa.sa_family, peer->fd, + if (peer->connection->fd >= 0) + sockopt_minttl(peer->su.sa.sa_family, + peer->connection->fd, MAXTTL + 1 - gtsm_hops); - if ((peer->status < Established) && peer->doppelganger - && (peer->doppelganger->fd >= 0)) + if ((peer->connection->status < Established) && + peer->doppelganger && + (peer->doppelganger->connection->fd >= 0)) sockopt_minttl(peer->su.sa.sa_family, - peer->doppelganger->fd, + peer->doppelganger->connection->fd, MAXTTL + 1 - gtsm_hops); } else { group = peer->group; @@ -7818,18 +7873,18 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) * no session then do nothing (will get * handled by next connection) */ - if (gpeer->fd >= 0 - && gpeer->gtsm_hops - != BGP_GTSM_HOPS_DISABLED) - sockopt_minttl( - gpeer->su.sa.sa_family, - gpeer->fd, - MAXTTL + 1 - gpeer->gtsm_hops); - if ((gpeer->status < Established) - && gpeer->doppelganger - && (gpeer->doppelganger->fd >= 0)) + if (gpeer->connection->fd >= 0 && + gpeer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) + sockopt_minttl(gpeer->su.sa.sa_family, + gpeer->connection->fd, + MAXTTL + 1 - + gpeer->gtsm_hops); + if ((gpeer->connection->status < Established) && + gpeer->doppelganger && + (gpeer->doppelganger->connection->fd >= 0)) sockopt_minttl(gpeer->su.sa.sa_family, - gpeer->doppelganger->fd, + gpeer->doppelganger + ->connection->fd, MAXTTL + 1 - gtsm_hops); } } @@ -7862,14 +7917,16 @@ int peer_ttl_security_hops_unset(struct peer *peer) if (peer->sort == BGP_PEER_EBGP) ret = peer_ebgp_multihop_unset(peer); else { - if (peer->fd >= 0) - sockopt_minttl(peer->su.sa.sa_family, peer->fd, - 0); + if (peer->connection->fd >= 0) + sockopt_minttl(peer->su.sa.sa_family, + peer->connection->fd, 0); - if ((peer->status < Established) && peer->doppelganger - && (peer->doppelganger->fd >= 0)) + if ((peer->connection->status < Established) && + peer->doppelganger && + (peer->doppelganger->connection->fd >= 0)) sockopt_minttl(peer->su.sa.sa_family, - peer->doppelganger->fd, 0); + peer->doppelganger->connection->fd, + 0); } } else { group = peer->group; @@ -7878,15 +7935,16 @@ int peer_ttl_security_hops_unset(struct peer *peer) if (peer->sort == BGP_PEER_EBGP) ret = peer_ebgp_multihop_unset(peer); else { - if (peer->fd >= 0) + if (peer->connection->fd >= 0) sockopt_minttl(peer->su.sa.sa_family, - peer->fd, 0); + peer->connection->fd, 0); - if ((peer->status < Established) - && peer->doppelganger - && (peer->doppelganger->fd >= 0)) + if ((peer->connection->status < Established) && + peer->doppelganger && + (peer->doppelganger->connection->fd >= 0)) sockopt_minttl(peer->su.sa.sa_family, - peer->doppelganger->fd, + peer->doppelganger + ->connection->fd, 0); } } @@ -7938,7 +7996,7 @@ int peer_clear(struct peer *peer, struct listnode **nnode) return 0; peer->v_start = BGP_INIT_START_TIMER; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else @@ -7958,7 +8016,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, if (!peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; - peer->rtt = sockopt_tcp_rtt(peer->fd); + peer->rtt = sockopt_tcp_rtt(peer->connection->fd); if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) { /* Clear the "neighbor x.x.x.x default-originate" flag */ @@ -8241,8 +8299,9 @@ static int peer_unshut_after_cfg(struct bgp *bgp) peer->host); peer->shut_during_cfg = false; - if (peer_active(peer) && peer->status != Established) { - if (peer->status != Idle) + if (peer_active(peer) && + peer->connection->status != Established) { + if (peer->connection->status != Idle) BGP_EVENT_ADD(peer, BGP_Stop); BGP_EVENT_ADD(peer, BGP_Start); } @@ -8343,7 +8402,8 @@ void bgp_terminate(void) peer); continue; } - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + if (BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 67ee8aa138..51e0cb3802 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1120,6 +1120,36 @@ struct llgr_info { uint8_t flags; }; +struct peer_connection { + struct peer *peer; + + /* Status of the peer connection. */ + enum bgp_fsm_status status; + enum bgp_fsm_status ostatus; + + int fd; + + /* Packet receive and send buffer. */ + pthread_mutex_t io_mtx; // guards ibuf, obuf + struct stream_fifo *ibuf; // packets waiting to be processed + struct stream_fifo *obuf; // packets waiting to be written + + struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only + + struct event *t_read; + struct event *t_write; + + struct event *t_process_packet; + struct event *t_process_packet_error; + + /* Thread flags */ + _Atomic uint32_t thread_flags; +#define PEER_THREAD_WRITES_ON (1U << 0) +#define PEER_THREAD_READS_ON (1U << 1) +}; +extern struct peer_connection *bgp_peer_connection_new(struct peer *peer); +extern void bgp_peer_connection_buffers_free(struct peer_connection *connection); + /* BGP neighbor structure. */ struct peer { /* BGP structure. */ @@ -1160,22 +1190,11 @@ struct peer { /* Local router ID. */ struct in_addr local_id; - /* Packet receive and send buffer. */ - pthread_mutex_t io_mtx; // guards ibuf, obuf - struct stream_fifo *ibuf; // packets waiting to be processed - struct stream_fifo *obuf; // packets waiting to be written - - struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only - struct stream *curr; // the current packet being parsed /* the doppelganger peer structure, due to dual TCP conn setup */ struct peer *doppelganger; - /* Status of the peer. */ - enum bgp_fsm_status status; - enum bgp_fsm_status ostatus; - /* FSM events, stored for debug purposes. * Note: uchar used for reduced memory usage. */ @@ -1187,7 +1206,16 @@ struct peer { uint16_t table_dump_index; /* Peer information */ - int fd; /* File descriptor */ + + /* + * We will have 2 `struct peer_connection` data structures + * connection is our attempt to talk to our peer. incoming + * is the peer attempting to talk to us. When it is + * time to consolidate between the two, we'll solidify + * into the connection variable being used. + */ + struct peer_connection *connection; + int ttl; /* TTL of TCP connection to the peer. */ int rtt; /* Estimated round-trip-time from TCP_INFO */ int rtt_expected; /* Expected round-trip-time for a peer */ @@ -1520,8 +1548,6 @@ struct peer { _Atomic uint32_t v_gr_restart; /* Threads. */ - struct event *t_read; - struct event *t_write; struct event *t_start; struct event *t_connect_check_r; struct event *t_connect_check_w; @@ -1535,16 +1561,12 @@ struct peer { struct event *t_llgr_stale[AFI_MAX][SAFI_MAX]; struct event *t_revalidate_all[AFI_MAX][SAFI_MAX]; struct event *t_generate_updgrp_packets; - struct event *t_process_packet; - struct event *t_process_packet_error; struct event *t_refresh_stalepath; /* Thread flags. */ _Atomic uint32_t thread_flags; -#define PEER_THREAD_WRITES_ON (1U << 0) -#define PEER_THREAD_READS_ON (1U << 1) -#define PEER_THREAD_KEEPALIVES_ON (1U << 2) -#define PEER_THREAD_SUBGRP_ADV_DELAY (1U << 3) +#define PEER_THREAD_KEEPALIVES_ON (1U << 0) +#define PEER_THREAD_SUBGRP_ADV_DELAY (1U << 1) /* workqueues */ struct work_queue *clear_node_queue; @@ -2574,7 +2596,7 @@ static inline char *timestamp_string(time_t ts) static inline bool peer_established(struct peer *peer) { - return peer->status == Established; + return peer->connection->status == Established; } static inline bool peer_dynamic_neighbor(struct peer *peer) diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 985094d323..ff7137bdd9 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1236,26 +1236,9 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp, * Fill in BGP peer structure */ rfd->peer = peer_new(bgp); - rfd->peer->status = Established; /* keep bgp core happy */ + rfd->peer->connection->status = Established; /* keep bgp core happy */ - /* - * since this peer is not on the I/O thread, this lock is not strictly - * necessary, but serves as a reminder to those who may meddle... - */ - frr_with_mutex (&rfd->peer->io_mtx) { - // we don't need any I/O related facilities - if (rfd->peer->ibuf) - stream_fifo_free(rfd->peer->ibuf); - if (rfd->peer->obuf) - stream_fifo_free(rfd->peer->obuf); - - if (rfd->peer->ibuf_work) - ringbuf_del(rfd->peer->ibuf_work); - - rfd->peer->ibuf = NULL; - rfd->peer->obuf = NULL; - rfd->peer->ibuf_work = NULL; - } + bgp_peer_connection_buffers_free(rfd->peer->connection); { /* base code assumes have valid host pointer */ char buf[INET6_ADDRSTRLEN]; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index c17b17a335..c886beea91 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -171,28 +171,11 @@ static void vnc_redistribute_add(struct prefix *p, uint32_t metric, * Same setup as in rfapi_open() */ vncHD1VR.peer = peer_new(bgp); - vncHD1VR.peer->status = + vncHD1VR.peer->connection->status = Established; /* keep bgp core happy */ - /* - * since this peer is not on the I/O thread, this lock - * is not strictly necessary, but serves as a reminder - * to those who may meddle... - */ - frr_with_mutex (&vncHD1VR.peer->io_mtx) { - // we don't need any I/O related facilities - if (vncHD1VR.peer->ibuf) - stream_fifo_free(vncHD1VR.peer->ibuf); - if (vncHD1VR.peer->obuf) - stream_fifo_free(vncHD1VR.peer->obuf); - - if (vncHD1VR.peer->ibuf_work) - ringbuf_del(vncHD1VR.peer->ibuf_work); - - vncHD1VR.peer->ibuf = NULL; - vncHD1VR.peer->obuf = NULL; - vncHD1VR.peer->ibuf_work = NULL; - } + bgp_peer_connection_buffers_free( + vncHD1VR.peer->connection); /* base code assumes have valid host pointer */ vncHD1VR.peer->host = diff --git a/configure.ac b/configure.ac index 6d0ffc7adf..cea7571fe0 100644 --- a/configure.ac +++ b/configure.ac @@ -1385,7 +1385,9 @@ if test "$enable_protobuf3" = "yes"; then [PROTO3=false && AC_MSG_FAILURE([protobuf3 requested but protobuf-c.h not found. Install protobuf-c.])]) fi -AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf]) +if test "$enable_protobuf" != "no"; then + AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf]) +fi # # End of logic for protobuf support. # diff --git a/debian/not-installed b/debian/not-installed index 1a89f35853..8999dd948b 100644 --- a/debian/not-installed +++ b/debian/not-installed @@ -1,3 +1,4 @@ usr/include usr/lib/frr/ospfclient usr/lib/frr/rfptest +usr/lib/*/frr/modules/dplane_sample_plugin.so diff --git a/doc/manpages/frr-zebra.rst b/doc/manpages/frr-zebra.rst index 722b011ecd..6cc46b806d 100644 --- a/doc/manpages/frr-zebra.rst +++ b/doc/manpages/frr-zebra.rst @@ -45,6 +45,11 @@ ROUTES When the program terminates, do not flush routes installed by zebra from the kernel. +.. option:: -R, --routing-table <tableno> + + Specify which kernel routing table *Zebra* should communicate with. + If this option is not specified the default table (RT_TABLE_MAIN) is used. + FILES ===== diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 39add2235f..e3c9998354 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -68,6 +68,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the option and we will use Route Replace Semantics instead of delete than add. +.. option:: --routing-table <tableno> + + Specify which kernel routing table *Zebra* should communicate with. + If this option is not specified the default table (RT_TABLE_MAIN) is + used. + .. option:: --asic-offload=[notify_on_offload|notify_on_ack] The linux kernel has the ability to use asic-offload ( see switchdev diff --git a/lib/cspf.c b/lib/cspf.c index 6a0fb7f63c..c17d8e0929 100644 --- a/lib/cspf.c +++ b/lib/cspf.c @@ -331,6 +331,8 @@ void cspf_clean(struct cspf *algo) if (processed_count(&algo->processed)) { frr_each_safe (processed, &algo->processed, path) { processed_del(&algo->processed, path); + if (path == algo->pdst) + algo->pdst = NULL; cpath_del(path); } } @@ -343,6 +345,9 @@ void cspf_clean(struct cspf *algo) } } + if (algo->pdst) + cpath_del(algo->pdst); + memset(&algo->csts, 0, sizeof(struct constraints)); algo->path = NULL; algo->pdst = NULL; diff --git a/lib/link_state.c b/lib/link_state.c index 6537f881ce..105e3e28a9 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -523,7 +523,9 @@ struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) if (!ls_node_same(old->node, node)) { ls_node_del(old->node); old->node = node; - } + } else + ls_node_del(node); + old->status = UPDATE; return old; } @@ -805,7 +807,9 @@ struct ls_edge *ls_edge_update(struct ls_ted *ted, if (!ls_attributes_same(old->attributes, attributes)) { ls_attributes_del(old->attributes); old->attributes = attributes; - } + } else + ls_attributes_del(attributes); + old->status = UPDATE; return old; } @@ -902,7 +906,9 @@ struct ls_subnet *ls_subnet_update(struct ls_ted *ted, struct ls_prefix *pref) if (!ls_prefix_same(old->ls_pref, pref)) { ls_prefix_del(old->ls_pref); old->ls_pref = pref; - } + } else + ls_prefix_del(pref); + old->status = UPDATE; return old; } @@ -99,6 +99,7 @@ struct pbr_action { #define PBR_ACTION_DST_PORT (1 << 8) #define PBR_ACTION_DSCP (1 << 9) #define PBR_ACTION_ECN (1 << 10) +#define PBR_ACTION_DROP (1 << 11) /* nexthop == blackhole */ uint32_t table; uint32_t queue_id; diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c index f98f092edb..10e00921f1 100644 --- a/ospf6d/ospf6_auth_trailer.c +++ b/ospf6d/ospf6_auth_trailer.c @@ -664,7 +664,7 @@ void ospf6_auth_update_digest(struct ospf6_interface *oi, struct ospf6_auth_hdr *ospf6_auth, char *auth_str, uint32_t pkt_len, enum keychain_hash_algo algo) { - static const uint16_t cpid = 1; + const uint16_t cpid = htons(OSPFV3_CRYPTO_PROTO_ID); uint32_t hash_len = keychain_get_hash_len(algo); uint32_t block_s = keychain_get_block_size(algo); uint32_t k_len = strlen(auth_str); diff --git a/ospf6d/ospf6_auth_trailer.h b/ospf6d/ospf6_auth_trailer.h index 924b89503f..3f82a7b197 100644 --- a/ospf6d/ospf6_auth_trailer.h +++ b/ospf6d/ospf6_auth_trailer.h @@ -15,6 +15,8 @@ #define OSPF6_AUTHENTICATION_NULL 0 #define OSPF6_AUTHENTICATION_CRYPTOGRAPHIC 1 +#define OSPFV3_CRYPTO_PROTO_ID 1 + /* Auth debug options */ extern unsigned char conf_debug_ospf6_auth[2]; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 4e1a0f7503..582ffac9b2 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -1120,6 +1120,9 @@ static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms) pbrms->nhs_installed = false; pbrms->forwarding_type = PBR_FT_UNSPEC; + + /* clear advisory flag indicating nexthop == blackhole */ + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_DROP); } @@ -1278,6 +1281,8 @@ DEFPY (pbr_map_nexthop, } } else if (bh) { nhop.type = NEXTHOP_TYPE_BLACKHOLE; + /* advisory flag for non-linux dataplanes */ + SET_FLAG(pbrms->action_bm, PBR_ACTION_DROP); } else { nhop.type = NEXTHOP_TYPE_IFINDEX; } diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 57aa2af9de..799733b7b5 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1343,10 +1343,11 @@ static int handle_attr_test(struct aspath_tests *t) bgp.asnotation = t->segment->asnotation; peer.curr = stream_new(BGP_MAX_PACKET_SIZE); - peer.obuf = stream_fifo_new(); + peer.connection = bgp_peer_connection_new(&peer); + peer.connection->obuf = stream_fifo_new(); peer.bgp = &bgp; peer.host = (char *)"none"; - peer.fd = -1; + peer.connection->fd = -1; peer.cap = t->cap; peer.max_packet_size = BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE; diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index da17471fd1..84c9f53066 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -972,7 +972,8 @@ int main(void) parse_test(peer, &opt_params[i++], OPT_PARAM); SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); - peer->status = Established; + peer->connection = bgp_peer_connection_new(peer); + peer->connection->status = Established; i = 0; while (dynamic_cap_msgs[i].name) diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index ae7903e0cc..cebdda9e5c 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1085,7 +1085,8 @@ int main(void) peer = peer_create_accept(bgp); peer->host = (char *)"foo"; - peer->status = Established; + peer->connection = bgp_peer_connection_new(peer); + peer->connection->status = Established; peer->curr = stream_new(BGP_MAX_PACKET_SIZE); ifp.ifindex = 0; diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index 94c3feaa93..a83276be07 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -64,11 +64,12 @@ int main(int argc, char *argv[]) } SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); - peer->status = Established; + peer->connection = bgp_peer_connection_new(peer); + peer->connection->status = Established; - peer->fd = open(argv[1], O_RDONLY|O_NONBLOCK); + peer->connection->fd = open(argv[1], O_RDONLY | O_NONBLOCK); t.arg = peer; - peer->t_read = &t; + peer->connection->t_read = &t; // printf("bgp_read_packet returns: %d\n", bgp_read(&t)); } diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py index 817336ac21..fd87224b57 100644 --- a/tests/topotests/static_simple/test_static_simple.py +++ b/tests/topotests/static_simple/test_static_simple.py @@ -68,7 +68,7 @@ def disable_debug(router): router.vtysh_cmd("no debug northbound callbacks configuration") -@retry(retry_timeout=3, initial_wait=0.1) +@retry(retry_timeout=30, initial_wait=0.1) def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): network = ipaddress.ip_network(super_prefix) vrfstr = f" vrf {vrf}" if vrf else "" diff --git a/zebra/interface.c b/zebra/interface.c index 90787f3aa0..9ca330571f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1195,6 +1195,12 @@ static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down, zif = ifp->info; + /* + * FRR does not have enough data to make this request + */ + if (ifp->ifindex == IFINDEX_INTERNAL) + return true; + /* Current state as we know it */ old_down = !!(ZEBRA_IF_IS_PROTODOWN(zif)); old_set_down = !!CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index fff3e6416f..d897f4a1df 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1100,11 +1100,11 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, zebra_flags, - &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, 0, distance, 0, + &p, NULL, &nh, 0, rt_table_main_id, 0, 0, distance, 0, false); else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, - zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, + zebra_flags, &p, NULL, &nh, 0, rt_table_main_id, 0, distance, true); } diff --git a/zebra/main.c b/zebra/main.c index aeb9739c13..1e833ce7f1 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -69,6 +69,8 @@ uint32_t rcvbufsize = RCVBUFSIZE_MIN; uint32_t rcvbufsize = 128 * 1024; #endif +uint32_t rt_table_main_id = RT_TABLE_MAIN; + #define OPTION_V6_RR_SEMANTICS 2000 #define OPTION_ASIC_OFFLOAD 2001 #define OPTION_V6_WITH_V4_NEXTHOP 2002 @@ -88,6 +90,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ + {"routing-table", optional_argument, NULL, 'R'}, { 0 } }; @@ -298,7 +301,7 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); - frr_opt_add("baz:e:rK:s:" + frr_opt_add("baz:e:rK:s:R:" #ifdef HAVE_NETLINK "n" #endif @@ -319,6 +322,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ + " -R, --routing-table Set kernel routing table\n" ); while (1) { @@ -373,6 +377,9 @@ int main(int argc, char **argv) "Rcvbufsize is smaller than recommended value: %d\n", RCVBUFSIZE_MIN); break; + case 'R': + rt_table_main_id = atoi(optarg); + break; #ifdef HAVE_NETLINK case 'n': vrf_configure_backend(VRF_BACKEND_NETNS); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 8c8cbfc8d1..7aa254b1cb 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -716,7 +716,7 @@ int zebra_import_table(afi_t afi, vrf_id_t vrf_id, uint32_t table_id, struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf_id); if (!is_zebra_valid_kernel_table(table_id) - || (table_id == RT_TABLE_MAIN)) + || (table_id == rt_table_main_id)) return -1; if (afi >= AFI_MAX) diff --git a/zebra/rib.h b/zebra/rib.h index 64bbaf3e76..e20084f8cf 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -185,6 +185,10 @@ struct route_entry { * don't generate routes */ #define MQ_SIZE 11 + +/* For checking that an object has already queued in some sub-queue */ +#define MQ_BIT_MASK ((1 << MQ_SIZE) - 1) + struct meta_queue { struct list *subq[MQ_SIZE]; uint32_t size; /* sum of lengths of all subqueues */ @@ -625,6 +629,8 @@ extern pid_t pid; extern bool v6_rr_semantics; +extern uint32_t rt_table_main_id; + /* Name of hook calls */ #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a51d7b849b..2318cd6374 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2476,7 +2476,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) * are trying to give me. So now we have this little hack. */ if (mroute->family == AF_INET) - actual_table = (zvrf->table_id == RT_TABLE_MAIN) + actual_table = (zvrf->table_id == rt_table_main_id) ? RT_TABLE_DEFAULT : zvrf->table_id; else @@ -4759,7 +4759,7 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, req->n.nlmsg_pid = nl->snl.nl_pid; req->r.rtm_family = AF_MPLS; - req->r.rtm_table = RT_TABLE_MAIN; + req->r.rtm_table = rt_table_main_id; req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS; req->r.rtm_scope = RT_SCOPE_UNIVERSE; req->r.rtm_type = RTN_UNICAST; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 780d3c8991..5a32cf6bb9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -365,7 +365,7 @@ int is_zebra_valid_kernel_table(uint32_t table_id) int is_zebra_main_routing_table(uint32_t table_id) { - if (table_id == RT_TABLE_MAIN) + if (table_id == rt_table_main_id) return 1; return 0; } @@ -3255,12 +3255,26 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) return -1; /* Invariant: at this point we always have rn->info set. */ - if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_QUEUED(qindex))) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) + /* A route node must only be in one sub-queue at a time. */ + if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, MQ_BIT_MASK)) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + /* + * curr_qindex_bitmask is power of 2, because a route node must only be in one sub-queue at a time, + * so for getting current sub-queue index from bitmask we may use part of classic msb function + * (find most significant set bit). + */ + const uint32_t curr_qindex_bitmask = CHECK_FLAG(rib_dest_from_rnode(rn)->flags, MQ_BIT_MASK); + static const uint8_t pos[32] = { 0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, + 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + + curr_qindex = pos[(uint32_t)(curr_qindex_bitmask * 0x077CB531UL) >> 27]; + rnode_debug(rn, re->vrf_id, "rn %p is already queued in sub-queue %s", - (void *)rn, subqueue2str(qindex)); + (void *)rn, subqueue2str(curr_qindex)); + } + return -1; } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index b246d445da..0c063830d3 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -371,7 +371,7 @@ struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); zebra_pw_init(zvrf); - zvrf->table_id = RT_TABLE_MAIN; + zvrf->table_id = rt_table_main_id; /* by default table ID is default one */ return zvrf; } |
