diff options
78 files changed, 1484 insertions, 987 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e07af4ab03..8c53191d68 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; @@ -1398,6 +1405,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, case BGP_ATTR_LARGE_COMMUNITIES: case BGP_ATTR_ORIGINATOR_ID: case BGP_ATTR_CLUSTER_LIST: + case BGP_ATTR_ENCAP: case BGP_ATTR_OTC: return BGP_ATTR_PARSE_WITHDRAW; case BGP_ATTR_MP_REACH_NLRI: @@ -2628,26 +2636,21 @@ ipv6_ext_community_ignore: } /* Parse Tunnel Encap attribute in an UPDATE */ -static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ - bgp_size_t length, /* IN: attr's length field */ - struct attr *attr, /* IN: caller already allocated */ - uint8_t flag, /* IN: attr's flags field */ - uint8_t *startp) +static int bgp_attr_encap(struct bgp_attr_parser_args *args) { - bgp_size_t total; uint16_t tunneltype = 0; - - total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + bgp_size_t length = args->length; + uint8_t type = args->type; + uint8_t flag = args->flags; if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) { - zlog_info( - "Tunnel Encap attribute flag isn't optional and transitive %d", - flag); - bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; + zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d", + flag); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } if (BGP_ATTR_ENCAP == type) { @@ -2655,12 +2658,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ uint16_t tlv_length; if (length < 4) { - zlog_info( + zlog_err( "Tunnel Encap attribute not long enough to contain outer T,L"); - bgp_notify_send_with_data( - peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); - return -1; + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } tunneltype = stream_getw(BGP_INPUT(peer)); tlv_length = stream_getw(BGP_INPUT(peer)); @@ -2692,13 +2694,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ } if (sublength > length) { - zlog_info( - "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", - sublength, length); - bgp_notify_send_with_data( - peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); - return -1; + zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", + sublength, length); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } /* alloc and copy sub-tlv */ @@ -2746,13 +2746,10 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ if (length) { /* spurious leftover data */ - zlog_info( - "Tunnel Encap attribute length is bad: %d leftover octets", - length); - bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); - return -1; + zlog_err("Tunnel Encap attribute length is bad: %d leftover octets", + length); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } return 0; @@ -3461,8 +3458,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 +3484,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 +3513,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; } @@ -3699,8 +3722,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, case BGP_ATTR_VNC: #endif case BGP_ATTR_ENCAP: - ret = bgp_attr_encap(type, peer, length, attr, flag, - startp); + ret = bgp_attr_encap(&attr_args); break; case BGP_ATTR_PREFIX_SID: ret = bgp_attr_prefix_sid(&attr_args); 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..9821dcf7bb 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) { @@ -1305,7 +1307,7 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, if (frrtrace_enabled(frr_bgp, bmp_process)) { char pfxprint[PREFIX2STR_BUFFER]; - prefix2str(&bn->p, pfxprint, sizeof(pfxprint)); + prefix2str(&bn->rn->p, pfxprint, sizeof(pfxprint)); frrtrace(5, frr_bgp, bmp_process, peer, pfxprint, afi, safi, withdraw); } 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..e5d33e6d59 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1699,7 +1699,7 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, int paths_eq; struct ethaddr *tmp_mac; bool mac_cmp = false; - struct prefix_evpn *evp = (struct prefix_evpn *)&dest->p; + struct prefix_evpn *evp = (struct prefix_evpn *)&dest->rn->p; /* mac comparison is not needed for MAC-only routes */ @@ -2361,15 +2361,15 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * VNI table MAC-IP prefixes don't have MAC so make sure it's set from * path info here. */ - if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->p)) { + if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->rn->p)) { /* VNI MAC -> Global */ evpn_type2_prefix_global_copy( - &evp, (struct prefix_evpn *)&dest->p, NULL /* mac */, + &evp, (struct prefix_evpn *)&dest->rn->p, NULL /* mac */, evpn_type2_path_info_get_ip(local_pi)); } else { /* VNI IP -> Global */ evpn_type2_prefix_global_copy( - &evp, (struct prefix_evpn *)&dest->p, + &evp, (struct prefix_evpn *)&dest->rn->p, evpn_type2_path_info_get_mac(local_pi), NULL /* ip */); } @@ -3091,7 +3091,7 @@ static int install_evpn_route_entry_in_vni_common( if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug("VNI %d path %pFX chg to %s es", - vpn->vni, &pi->net->p, + vpn->vni, &pi->net->rn->p, new_local_es ? "local" : "non-local"); bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); @@ -4174,7 +4174,7 @@ void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import) return; install_uninstall_evpn_route(bgp_evpn, AFI_L2VPN, SAFI_EVPN, - &pi->net->p, pi, import); + &pi->net->rn->p, pi, import); } /* @@ -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], @@ -7259,7 +7259,7 @@ static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn, || !CHECK_FLAG(pi->flags, BGP_PATH_VALID)) return; - evp = (struct prefix_evpn *)&pi->net->p; + evp = (struct prefix_evpn *)&pi->net->rn->p; if (evp->family != AF_EVPN || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE @@ -7292,7 +7292,7 @@ static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn, if (!evpn_resolve_overlay_index()) return; - evp = (struct prefix_evpn *)&pi->net->p; + evp = (struct prefix_evpn *)&pi->net->rn->p; if (evp->family != AF_EVPN || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE @@ -7337,7 +7337,7 @@ static void show_remote_ip_entry(struct hash_bucket *bucket, void *args) ipaddr2str(&ip->addr, buf, sizeof(buf))); vty_out(vty, " Linked MAC/IP routes:\n"); for (ALL_LIST_ELEMENTS_RO(ip->macip_path_list, node, pi)) - vty_out(vty, " %pFX\n", &pi->net->p); + vty_out(vty, " %pFX\n", &pi->net->rn->p); } void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket, void *args) diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 36bf752d48..91db9a061a 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -527,7 +527,7 @@ int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn) { afi_t afi; safi_t safi; - struct bgp_dest *rdrn, *rn; + struct bgp_dest *rdrn, *bd; struct bgp_table *table; struct bgp_path_info *pi; @@ -543,15 +543,15 @@ int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn) * Iterate over all the routes in this table and delete EAD/EVI * routes */ - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + for (bd = bgp_table_top(table); bd; bd = bgp_route_next(bd)) { + struct prefix_evpn *evp = (struct prefix_evpn *)&bd->rn->p; if (evp->prefix.route_type != BGP_EVPN_AD_ROUTE) continue; - delete_evpn_route_entry(bgp, afi, safi, rn, &pi); + delete_evpn_route_entry(bgp, afi, safi, bd, &pi); if (pi) - bgp_process(bgp, rn, afi, safi); + bgp_process(bgp, bd, afi, safi); } } @@ -1583,7 +1583,7 @@ static void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info) pi = es_info->pi; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni, - &pi->net->p, es->esi_str); + &pi->net->rn->p, es->esi_str); if (es_info->vni) list_delete_node(es->macip_evi_path_list, @@ -1641,7 +1641,7 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi) bgp_evpn_path_es_unlink(es_info); if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->p, + zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->rn->p, es->esi_str); /* link mac-ip path to the new destination ES */ @@ -1661,7 +1661,7 @@ static bool bgp_evpn_is_macip_path(struct bgp_path_info *pi) * skipped) as these lists are maintained for managing * host routes in the tenant VRF */ - evp = (struct prefix_evpn *)&pi->net->p; + evp = (struct prefix_evpn *)&pi->net->rn->p; return is_evpn_prefix_ipaddr_v4(evp) || is_evpn_prefix_ipaddr_v6(evp); } @@ -1697,7 +1697,7 @@ bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf, if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug( "update path %pFX linked to es %s on vrf chg", - &pi->net->p, es->esi_str); + &pi->net->rn->p, es->esi_str); bgp_evpn_route_entry_install_if_vrf_match(es_vrf->bgp_vrf, pi, 1); } @@ -2086,7 +2086,7 @@ static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es *es) if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug( "update path %d %pFX linked to es %s on oper chg", - es_info->vni, &pi->net->p, es->esi_str); + es_info->vni, &pi->net->rn->p, es->esi_str); bgp_evpn_update_type2_route_entry(bgp, vpn, pi->net, pi, __func__); @@ -2135,7 +2135,7 @@ static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es, if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug( "update path %pFX linked to es %s on chg to %s", - &pi->net->p, es->esi_str, + &pi->net->rn->p, es->esi_str, is_local ? "local" : "non-local"); attr_tmp = *pi->attr; @@ -3160,7 +3160,7 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, esi_t *esi; struct bgp_evpn_es_vrf *es_vrf = NULL; struct bgp_path_info *parent_pi; - struct bgp_node *rn; + struct bgp_dest *bd; struct prefix_evpn *evp; struct bgp_path_info *mpinfo; bool use_l3nhg = false; @@ -3176,11 +3176,11 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, if (!parent_pi) return false; - rn = parent_pi->net; - if (!rn) + bd = parent_pi->net; + if (!bd) return false; - evp = (struct prefix_evpn *)&rn->p; + evp = (struct prefix_evpn *)&bd->rn->p; if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) return false; @@ -4706,7 +4706,7 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info) pi = nh_info->pi; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug("path %s unlinked from nh %s %s", - pi->net ? prefix2str(&pi->net->p, prefix_buf, + pi->net ? prefix2str(&pi->net->rn->p, prefix_buf, sizeof(prefix_buf)) : "", nh->bgp_vrf->name_pretty, nh->nh_str); @@ -4741,7 +4741,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) if (!bgp_vrf->evpn_nh_table) { if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug("path %pFX linked to vrf %s failed", - &pi->net->p, bgp_vrf->name_pretty); + &pi->net->rn->p, bgp_vrf->name_pretty); return; } @@ -4764,7 +4764,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) /* find-create nh */ memset(&ip, 0, sizeof(ip)); - if (pi->net->p.family == AF_INET6) { + if (pi->net->rn->p.family == AF_INET6) { SET_IPADDR_V6(&ip); memcpy(&ip.ipaddr_v6, &pi->attr->mp_nexthop_global, sizeof(ip.ipaddr_v6)); @@ -4788,7 +4788,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) bgp_evpn_path_nh_unlink(nh_info); if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %pFX linked to nh %s %s", &pi->net->p, + zlog_debug("path %pFX linked to nh %s %s", &pi->net->rn->p, nh->bgp_vrf->name_pretty, nh->nh_str); /* link mac-ip path to the new nh */ @@ -4803,7 +4803,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) if (!nh->ref_pi) zlog_debug( "path %pFX linked to nh %s %s with no valid pi", - &pi->net->p, nh->bgp_vrf->name_pretty, + &pi->net->rn->p, nh->bgp_vrf->name_pretty, nh->nh_str); } } @@ -4840,7 +4840,7 @@ static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh *nh, struct vty *vty, prefix_mac2str(&nh->rmac, mac_buf, sizeof(mac_buf)); if (nh->ref_pi && nh->ref_pi->net) - prefix2str(&nh->ref_pi->net->p, prefix_buf, sizeof(prefix_buf)); + prefix2str(&nh->ref_pi->net->rn->p, prefix_buf, sizeof(prefix_buf)); else prefix_buf[0] = '\0'; if (json) { diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f141ddd6ef..5af99afa34 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -750,7 +750,7 @@ bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p, extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import); extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_node *rn, + struct bgp_dest *rn, struct bgp_path_info *local_pi, const char *caller); extern int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 2f158ab1be..e4c7fdb124 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -714,7 +714,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, json_object *json, int detail, bool global_table) { - struct bgp_node *rn; + struct bgp_dest *bd; struct bgp_path_info *pi; int header = detail ? 0 : 1; uint32_t path_cnt; @@ -747,7 +747,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, json_object *json_path = NULL; pi = es_info->pi; - rn = pi->net; + bd = pi->net; if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) continue; @@ -765,11 +765,11 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, if (detail) route_vty_out_detail( - vty, bgp, rn, bgp_dest_get_prefix(rn), + vty, bgp, bd, bgp_dest_get_prefix(bd), pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path); else - route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, + route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN, json_path, false); if (json) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 269f5c2948..786e953843 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, @@ -722,7 +723,7 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", - peer, &dest->p); + peer, &dest->rn->p); attr = *pi->attr; bgp_attr_add_llgr_community(&attr); @@ -750,7 +751,7 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", - peer, &dest->p); + peer, &dest->rn->p); attr = *pi->attr; bgp_attr_add_llgr_community(&attr); @@ -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,8 @@ 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; + struct peer *orig = peer; other = peer->doppelganger; hash_release(peer->bgp->peerhash, peer); @@ -2109,6 +2147,17 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) peer = peer_xfer_conn(peer); if (!peer) { flog_err(EC_BGP_CONNECT, "%%Neighbor failed in xfer_conn"); + + /* + * A failure of peer_xfer_conn but not putting the peers + * back in the hash ends up with a situation where incoming + * connections are rejected, as that the peer is not found + * when a lookup is done + */ + (void)hash_get(orig->bgp->peerhash, orig, hash_alloc_intern); + if (other) + (void)hash_get(other->bgp->peerhash, other, + hash_alloc_intern); return BGP_FSM_FAILURE; } @@ -2282,13 +2331,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 +2361,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 +2410,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 +2443,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 +2626,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 +2638,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 +2679,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 +2696,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..c7c91da74d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -27,22 +27,23 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_memory.h" -static const struct message capcode_str[] = { - {CAPABILITY_CODE_MP, "MultiProtocol Extensions"}, - {CAPABILITY_CODE_REFRESH, "Route Refresh"}, - {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"}, - {CAPABILITY_CODE_RESTART, "Graceful Restart"}, - {CAPABILITY_CODE_AS4, "4-octet AS number"}, - {CAPABILITY_CODE_ADDPATH, "AddPath"}, - {CAPABILITY_CODE_DYNAMIC, "Dynamic"}, - {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"}, - {CAPABILITY_CODE_FQDN, "FQDN"}, - {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, - {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, - {CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"}, - {CAPABILITY_CODE_ROLE, "Role"}, - {CAPABILITY_CODE_SOFT_VERSION, "Software Version"}, - {0}}; +const struct message capcode_str[] = { + { CAPABILITY_CODE_MP, "MultiProtocol Extensions" }, + { CAPABILITY_CODE_REFRESH, "Route Refresh" }, + { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" }, + { CAPABILITY_CODE_RESTART, "Graceful Restart" }, + { CAPABILITY_CODE_AS4, "4-octet AS number" }, + { CAPABILITY_CODE_ADDPATH, "AddPath" }, + { CAPABILITY_CODE_DYNAMIC, "Dynamic" }, + { CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding" }, + { CAPABILITY_CODE_FQDN, "FQDN" }, + { CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh" }, + { CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message" }, + { CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" }, + { CAPABILITY_CODE_ROLE, "Role" }, + { CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, + { 0 } +}; /* Minimum sizes for length field of each cap (so not inc. the header) */ static const size_t cap_minsizes[] = { @@ -911,8 +912,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_open.h b/bgpd/bgp_open.h index b18dbaa04f..20f5fdb22b 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -94,5 +94,6 @@ extern uint16_t bgp_open_capability(struct stream *s, struct peer *peer, extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, json_object *json_neigh); extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length); +extern const struct message capcode_str[]; #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 327c6b79fd..74291383da 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", @@ -2769,6 +2772,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, iana_safi_t pkt_safi; safi_t safi; char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; + const char *capability; end = pnt + length; @@ -2776,7 +2780,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, /* We need at least action, capability code and capability * length. */ if (pnt + 3 > end) { - zlog_info("%s Capability length error", peer->host); + zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; @@ -2787,21 +2791,20 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, /* Action value check. */ if (action != CAPABILITY_ACTION_SET && action != CAPABILITY_ACTION_UNSET) { - zlog_info("%s Capability Action Value error %d", - peer->host, action); + zlog_err("%pBP: Capability Action Value error %d", peer, + action); bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s CAPABILITY has action: %d, code: %u, length %u", - peer->host, action, hdr->code, hdr->length); + zlog_debug("%pBP: CAPABILITY has action: %d, code: %u, length %u", + peer, action, hdr->code, hdr->length); /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { - zlog_info("%s Capability length error", peer->host); + zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; @@ -2811,6 +2814,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) continue; + capability = lookup_msg(capcode_str, hdr->code, "Unknown"); + switch (hdr->code) { case CAPABILITY_CODE_SOFT_VERSION: if (action == CAPABILITY_ACTION_SET) { @@ -2832,10 +2837,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, break; case CAPABILITY_CODE_MP: if (hdr->length < sizeof(struct capability_mp_data)) { - zlog_info("%pBP Capability structure is not properly filled out, expected at least %zu bytes but header length specified is %d", - peer, - sizeof(struct capability_mp_data), - hdr->length); + zlog_err("%pBP: Capability (%s) structure is not properly filled out, expected at least %zu bytes but header length specified is %d", + peer, capability, + sizeof(struct capability_mp_data), + hdr->length); return BGP_Stop; } @@ -2847,24 +2852,22 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Dynamic Capability MP_EXT afi/safi invalid (%s/%s)", - peer->host, - iana_afi2str(pkt_afi), - iana_safi2str(pkt_safi)); + zlog_debug("%pBP: Dynamic Capability %s afi/safi invalid (%s/%s)", + peer, capability, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); continue; } /* Address family check. */ if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s CAPABILITY has %s MP_EXT CAP for afi/safi: %s/%s", - peer->host, - action == CAPABILITY_ACTION_SET - ? "Advertising" - : "Removing", - iana_afi2str(pkt_afi), - iana_safi2str(pkt_safi)); + zlog_debug("%pBP: CAPABILITY has %s %s CAP for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); if (action == CAPABILITY_ACTION_SET) { peer->afc_recv[afi][safi] = 1; @@ -2896,26 +2899,30 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_EXT_MESSAGE: break; case CAPABILITY_CODE_ROLE: - SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { - flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, - "Role: Received invalid length %d", - hdr->length); + zlog_err("%pBP: Capability (%s) length error", + peer, capability); bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } + uint8_t role; - memcpy(&role, pnt + 3, sizeof(role)); + if (action == CAPABILITY_ACTION_SET) { + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + memcpy(&role, pnt + 3, sizeof(role)); - peer->remote_role = role; + peer->remote_role = role; + } else { + UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + peer->remote_role = ROLE_UNDEFINED; + } break; default: - flog_warn( - EC_BGP_UNRECOGNIZED_CAPABILITY, - "%s unrecognized capability code: %d - ignored", - peer->host, hdr->code); + flog_warn(EC_BGP_UNRECOGNIZED_CAPABILITY, + "%pBP: unrecognized capability code: %d - ignored", + peer, hdr->code); break; } @@ -2957,13 +2964,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 +2996,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 +3018,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 +3145,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 +3173,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..c8271bf5ce 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -77,7 +77,7 @@ #include "bgpd/bgp_route_clippy.c" DEFINE_HOOK(bgp_snmp_update_stats, - (struct bgp_node *rn, struct bgp_path_info *pi, bool added), + (struct bgp_dest *rn, struct bgp_path_info *pi, bool added), (rn, pi, added)); DEFINE_HOOK(bgp_rpki_prefix_status, @@ -265,7 +265,7 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) { if (!pi->extra) pi->extra = bgp_path_info_extra_new(); - if (!pi->extra->evpn && pi->net && pi->net->p.family == AF_EVPN) + if (!pi->extra->evpn && pi->net && pi->net->rn->p.family == AF_EVPN) pi->extra->evpn = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_EVPN, sizeof(struct bgp_path_info_extra_evpn)); @@ -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); @@ -12796,6 +12793,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, rpki_target_state = RPKI_VALID; else if (argv_find(argv, argc, "invalid", &idx)) rpki_target_state = RPKI_INVALID; + else if (argv_find(argv, argc, "notfound", &idx)) + rpki_target_state = RPKI_NOTFOUND; } /* Display prefixes with matching version numbers */ @@ -15574,8 +15573,8 @@ DEFUN (show_bgp_peerhash, struct bgp *bgp; for (ALL_LIST_ELEMENTS_RO(instances, node, bgp)) { - vty_out(vty, "BGP: %s\n", bgp->name); - hash_iterate(bgp->peerhash, show_bgp_peerhash_entry, + vty_out(vty, "BGP: %s\n", bgp->name_pretty); + hash_iterate(bgp->peerhash, show_bgp_peerhash_entry, vty); } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index f424e6d286..e001bf4f07 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -670,7 +670,7 @@ static inline bool bgp_check_withdrawal(struct bgp *bgp, struct bgp_dest *dest, /* called before bgp_process() */ DECLARE_HOOK(bgp_process, - (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + (struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, struct peer *peer, bool withdraw), (bgp, afi, safi, bn, peer, withdraw)); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 1c99495e6c..af9490f0b3 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -6163,6 +6163,7 @@ DEFPY_YANG( char xpath_value[XPATH_MAXLEN]; as_t as_configured_value; char replace_value[ASN_STRING_MAX_SIZE * 2]; + int ret; if (configured_asn_str && !asn_str2asn(configured_asn_str, &as_configured_value)) { @@ -6181,7 +6182,9 @@ DEFPY_YANG( "%s/rmap-set-action/frr-bgp-route-map:replace-as-path", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + XFREE(MTYPE_TMP, str); + return ret; } DEFPY_YANG( @@ -6323,6 +6326,7 @@ DEFPY_YANG(set_aspath_exclude_access_list, set_aspath_exclude_access_list_cmd, const char *xpath = "./set-action[action='frr-bgp-route-map:as-path-exclude']"; char xpath_value[XPATH_MAXLEN]; + int ret; str = argv_concat(argv, argc, 3); @@ -6332,7 +6336,9 @@ DEFPY_YANG(set_aspath_exclude_access_list, set_aspath_exclude_access_list_cmd, "%s/rmap-set-action/frr-bgp-route-map:exclude-as-path", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + XFREE(MTYPE_TMP, str); + return ret; } DEFPY_YANG(no_set_aspath_exclude_access_list, no_set_aspath_exclude_access_list_cmd, 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_table.c b/bgpd/bgp_table.c index cb658c0308..149a5b9142 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -47,16 +47,6 @@ void bgp_table_finish(struct bgp_table **rt) } /* - * bgp_dest_unlock_node - */ -void bgp_dest_unlock_node(struct bgp_dest *dest) -{ - frrtrace(1, frr_bgp, bgp_dest_unlock, dest); - bgp_delete_listnode(dest); - route_unlock_node(bgp_dest_to_rnode(dest)); -} - -/* * bgp_dest_lock_node */ struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest) @@ -83,44 +73,56 @@ const char *bgp_dest_get_prefix_str(struct bgp_dest *dest) } /* - * bgp_node_create + * bgp_dest_unlock_node */ -static struct route_node *bgp_node_create(route_table_delegate_t *delegate, - struct route_table *table) +inline void bgp_dest_unlock_node(struct bgp_dest *dest) { - struct bgp_node *node; - node = XCALLOC(MTYPE_BGP_NODE, sizeof(struct bgp_node)); - - RB_INIT(bgp_adj_out_rb, &node->adj_out); - return bgp_dest_to_rnode(node); + frrtrace(1, frr_bgp, bgp_dest_unlock, dest); + bgp_delete_listnode(dest); + struct route_node *rn = bgp_dest_to_rnode(dest); + + if (rn->lock == 1) { + struct bgp_table *rt = bgp_dest_table(dest); + if (rt->bgp) { + bgp_addpath_free_node_data(&rt->bgp->tx_addpath, + &dest->tx_addpath, rt->afi, + rt->safi); + } + XFREE(MTYPE_BGP_NODE, dest); + rn->info = NULL; + } + route_unlock_node(rn); } /* * bgp_node_destroy */ static void bgp_node_destroy(route_table_delegate_t *delegate, - struct route_table *table, struct route_node *node) + struct route_table *table, struct route_node *node) { - struct bgp_node *bgp_node; + struct bgp_dest *dest; struct bgp_table *rt; - bgp_node = bgp_dest_from_rnode(node); + dest = bgp_dest_from_rnode(node); rt = table->info; - - if (rt->bgp) { - bgp_addpath_free_node_data(&rt->bgp->tx_addpath, - &bgp_node->tx_addpath, - rt->afi, rt->safi); + if (dest) { + if (rt->bgp) { + bgp_addpath_free_node_data(&rt->bgp->tx_addpath, + &dest->tx_addpath, + rt->afi, rt->safi); + } + XFREE(MTYPE_BGP_NODE, dest); + node->info = NULL; } - XFREE(MTYPE_BGP_NODE, bgp_node); + XFREE(MTYPE_ROUTE_NODE, node); } /* * Function vector to customize the behavior of the route table * library for BGP route tables. */ -route_table_delegate_t bgp_table_delegate = {.create_node = bgp_node_create, - .destroy_node = bgp_node_destroy}; +route_table_delegate_t bgp_table_delegate = { .create_node = route_node_create, + .destroy_node = bgp_node_destroy }; /* * bgp_table_init @@ -151,9 +153,9 @@ struct bgp_table *bgp_table_init(struct bgp *bgp, afi_t afi, safi_t safi) } /* Delete the route node from the selection deferral route list */ -void bgp_delete_listnode(struct bgp_node *node) +void bgp_delete_listnode(struct bgp_dest *dest) { - struct route_node *rn = NULL; + const struct route_node *rn = NULL; struct bgp_table *table = NULL; struct bgp *bgp = NULL; afi_t afi; @@ -162,8 +164,8 @@ void bgp_delete_listnode(struct bgp_node *node) /* If the route to be deleted is selection pending, update the * route node in gr_info */ - if (CHECK_FLAG(node->flags, BGP_NODE_SELECT_DEFER)) { - table = bgp_dest_table(node); + if (CHECK_FLAG(dest->flags, BGP_NODE_SELECT_DEFER)) { + table = bgp_dest_table(dest); if (table) { bgp = table->bgp; @@ -172,47 +174,48 @@ void bgp_delete_listnode(struct bgp_node *node) } else return; - rn = bgp_dest_to_rnode(node); + rn = bgp_dest_to_rnode(dest); if (bgp && rn && rn->lock == 1) { /* Delete the route from the selection pending list */ bgp->gr_info[afi][safi].gr_deferred--; - UNSET_FLAG(node->flags, BGP_NODE_SELECT_DEFER); + UNSET_FLAG(dest->flags, BGP_NODE_SELECT_DEFER); } } } -struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, +struct bgp_dest *bgp_table_subtree_lookup(const struct bgp_table *table, const struct prefix *p) { - struct bgp_node *node = bgp_dest_from_rnode(table->route_table->top); - struct bgp_node *matched = NULL; + struct bgp_dest *dest = bgp_dest_from_rnode(table->route_table->top); + struct bgp_dest *matched = NULL; - if (node == NULL) + if (dest == NULL) return NULL; - while (node) { - const struct prefix *node_p = bgp_dest_get_prefix(node); + while (dest) { + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + struct route_node *node = dest->rn; - if (node_p->prefixlen >= p->prefixlen) { - if (!prefix_match(p, node_p)) + if (dest_p->prefixlen >= p->prefixlen) { + if (!prefix_match(p, dest_p)) return NULL; - matched = node; + matched = dest; break; } - if (!prefix_match(node_p, p)) + if (!prefix_match(dest_p, p)) return NULL; - if (node_p->prefixlen == p->prefixlen) { - matched = node; + if (dest_p->prefixlen == p->prefixlen) { + matched = dest; break; } - node = bgp_dest_from_rnode(node->link[prefix_bit( - &p->u.prefix, node_p->prefixlen)]); + dest = bgp_dest_from_rnode( + node->link[prefix_bit(&p->u.prefix, dest_p->prefixlen)]); } if (!matched) diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 91941315f7..1f28624c16 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -6,10 +6,6 @@ #ifndef _QUAGGA_BGP_TABLE_H #define _QUAGGA_BGP_TABLE_H -/* XXX BEGIN TEMPORARY COMPAT */ -#define bgp_dest bgp_node -/* XXX END TEMPORARY COMPAT */ - #include "mpls.h" #include "table.h" #include "queue.h" @@ -67,16 +63,10 @@ enum bgp_path_selection_reason { bgp_path_selection_default, }; -struct bgp_node { - /* - * CAUTION - * - * These fields must be the very first fields in this structure. - * - * @see bgp_node_to_rnode - * @see bgp_node_from_rnode - */ - ROUTE_NODE_FIELDS +struct bgp_dest { + struct route_node *rn; + + void *info; struct bgp_adj_out_rb adj_out; @@ -134,7 +124,7 @@ extern const char *bgp_dest_get_prefix_str(struct bgp_dest *dest); */ static inline struct bgp_dest *bgp_dest_from_rnode(struct route_node *rnode) { - return (struct bgp_dest *)rnode; + return (rnode && rnode->info) ? (struct bgp_dest *)rnode->info : NULL; } /* @@ -144,7 +134,7 @@ static inline struct bgp_dest *bgp_dest_from_rnode(struct route_node *rnode) */ static inline struct route_node *bgp_dest_to_rnode(const struct bgp_dest *dest) { - return (struct route_node *)dest; + return dest ? dest->rn : NULL; } /* @@ -166,6 +156,9 @@ static inline struct bgp_dest *bgp_dest_parent_nolock(struct bgp_dest *dest) { struct route_node *rn = bgp_dest_to_rnode(dest)->parent; + while (rn && !rn->info) + rn = rn->parent; + return bgp_dest_from_rnode(rn); } @@ -179,7 +172,17 @@ static inline struct bgp_dest *bgp_dest_parent_nolock(struct bgp_dest *dest) static inline struct bgp_dest * bgp_table_top_nolock(const struct bgp_table *const table) { - return bgp_dest_from_rnode(table->route_table->top); + struct route_node *top; + struct route_node *rn = top = table->route_table->top; + + while (rn && !rn->info) { + if (rn == top) + route_lock_node(rn); + rn = route_next(rn); + } + if (rn && rn != top) + route_unlock_node(rn); + return rn ? rn->info : NULL; } /* @@ -188,7 +191,11 @@ bgp_table_top_nolock(const struct bgp_table *const table) static inline struct bgp_dest * bgp_table_top(const struct bgp_table *const table) { - return bgp_dest_from_rnode(route_top(table->route_table)); + struct route_node *rn = route_top(table->route_table); + + while (rn && !rn->info) + rn = route_next(rn); + return rn ? rn->info : NULL; } /* @@ -196,7 +203,11 @@ bgp_table_top(const struct bgp_table *const table) */ static inline struct bgp_dest *bgp_route_next(struct bgp_dest *dest) { - return bgp_dest_from_rnode(route_next(bgp_dest_to_rnode(dest))); + struct route_node *rn = route_next(bgp_dest_to_rnode(dest)); + + while (rn && !rn->info) + rn = route_next(rn); + return bgp_dest_from_rnode(rn); } /* @@ -210,6 +221,9 @@ static inline struct bgp_dest *bgp_route_next_until(struct bgp_dest *dest, rnode = route_next_until(bgp_dest_to_rnode(dest), bgp_dest_to_rnode(limit)); + while (rnode && !rnode->info) + rnode = route_next_until(rnode, bgp_dest_to_rnode(limit)); + return bgp_dest_from_rnode(rnode); } @@ -219,7 +233,17 @@ static inline struct bgp_dest *bgp_route_next_until(struct bgp_dest *dest, static inline struct bgp_dest *bgp_node_get(struct bgp_table *const table, const struct prefix *p) { - return bgp_dest_from_rnode(route_node_get(table->route_table, p)); + struct route_node *rn = route_node_get(table->route_table, p); + + if (!rn->info) { + struct bgp_dest *dest = XCALLOC(MTYPE_BGP_NODE, + sizeof(struct bgp_dest)); + + RB_INIT(bgp_adj_out_rb, &dest->adj_out); + rn->info = dest; + dest->rn = rn; + } + return rn->info; } /* @@ -255,7 +279,11 @@ static inline unsigned long bgp_table_count(const struct bgp_table *const table) static inline struct bgp_dest *bgp_table_get_next(const struct bgp_table *table, const struct prefix *p) { - return bgp_dest_from_rnode(route_table_get_next(table->route_table, p)); + struct route_node *rn = route_table_get_next(table->route_table, p); + + while (rn && !rn->info) + rn = route_next(rn); + return bgp_dest_from_rnode(rn); } /* This would benefit from a real atomic operation... @@ -357,7 +385,7 @@ static inline void bgp_dest_set_bgp_path_info(struct bgp_dest *dest, static inline struct bgp_table * bgp_dest_get_bgp_table_info(struct bgp_dest *dest) { - return dest->info; + return dest ? dest->info : NULL; } static inline void bgp_dest_set_bgp_table_info(struct bgp_dest *dest, @@ -368,17 +396,17 @@ static inline void bgp_dest_set_bgp_table_info(struct bgp_dest *dest, static inline bool bgp_dest_has_bgp_path_info_data(struct bgp_dest *dest) { - return !!dest->info; + return dest ? !!dest->info : false; } static inline const struct prefix *bgp_dest_get_prefix(const struct bgp_dest *dest) { - return &dest->p; + return dest ? &dest->rn->p : NULL; } static inline unsigned int bgp_dest_get_lock_count(const struct bgp_dest *dest) { - return dest->lock; + return dest ? dest->rn->lock : 0; } #ifdef _FRR_ATTRIBUTE_PRINTFRR 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..1c90214971 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -590,7 +590,7 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, int ret = bgp_get(bgp, as, name, inst_type, as_pretty, asnotation); if (ret == BGP_CREATED) { - bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, + bgp_timers_set(NULL, *bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN); if (DFLT_BGP_IMPORT_CHECK) @@ -2661,7 +2661,7 @@ DEFUN (bgp_timers, return CMD_WARNING_CONFIG_FAILED; } - bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY, + bgp_timers_set(vty, bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN); return CMD_SUCCESS; @@ -2677,7 +2677,7 @@ DEFUN (no_bgp_timers, "Holdtime\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - bgp_timers_set(bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, + bgp_timers_set(vty, bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN); return CMD_SUCCESS; @@ -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); @@ -16960,7 +16974,8 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, protocol = ZEBRA_ROUTE_TABLE; instance = strtoul(argv[idx_number]->arg, NULL, 10); - return bgp_redistribute_unset(bgp, AFI_IP, protocol, instance); + bgp_redistribute_unset(bgp, AFI_IP, protocol, instance); + return CMD_SUCCESS; } ALIAS_HIDDEN( @@ -16996,7 +17011,8 @@ DEFUN (no_bgp_redistribute_ipv4, vty_out(vty, "%% Invalid route type\n"); return CMD_WARNING_CONFIG_FAILED; } - return bgp_redistribute_unset(bgp, AFI_IP, type, 0); + bgp_redistribute_unset(bgp, AFI_IP, type, 0); + return CMD_SUCCESS; } ALIAS_HIDDEN( @@ -17180,7 +17196,8 @@ DEFUN (no_bgp_redistribute_ipv6, return CMD_WARNING_CONFIG_FAILED; } - return bgp_redistribute_unset(bgp, AFI_IP6, type, 0); + bgp_redistribute_unset(bgp, AFI_IP6, type, 0); + return CMD_SUCCESS; } /* Neighbor update tcp-mss. */ @@ -17735,8 +17752,12 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, && !(peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED && peer->ttl == MAXTTL)) { if (!peer_group_active(peer) || g_peer->ttl != peer->ttl) { - vty_out(vty, " neighbor %s ebgp-multihop %d\n", addr, - peer->ttl); + if (peer->ttl != MAXTTL) + vty_out(vty, " neighbor %s ebgp-multihop %d\n", + addr, peer->ttl); + else + vty_out(vty, " neighbor %s ebgp-multihop\n", + addr); } } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 21ccbebe67..105c1080bc 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2078,8 +2078,8 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, } /* Unset redistribution. */ -int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, - unsigned short instance) +static void _bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, + unsigned short instance) { struct bgp_redist *red; @@ -2096,7 +2096,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, red = bgp_redist_lookup(bgp, afi, type, instance); if (!red) - return CMD_SUCCESS; + return; bgp_redistribute_unreg(bgp, afi, type, instance); @@ -2110,8 +2110,23 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, red->redist_metric = 0; bgp_redist_del(bgp, afi, type, instance); +} - return CMD_SUCCESS; +void bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, + unsigned short instance) +{ + struct listnode *node, *nnode; + struct bgp_redist *red; + + if (type != ZEBRA_ROUTE_TABLE || instance != 0) + return _bgp_redistribute_unset(bgp, afi, type, instance); + + /* walk over instance */ + if (!bgp->redist[afi][type]) + return; + + for (ALL_LIST_ELEMENTS(bgp->redist[afi][type], node, nnode, red)) + _bgp_redistribute_unset(bgp, afi, type, red->instance); } void bgp_redistribute_redo(struct bgp *bgp) @@ -2658,7 +2673,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN : INSTALLED", dest); + zlog_debug("route %pRN : INSTALLED", (void *)dest); /* Find the best route */ for (pi = dest->info; pi; pi = pi->next) { /* Process aggregate route */ @@ -2671,7 +2686,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, group_announce_route(bgp, afi, safi, dest, new_select); else { flog_err(EC_BGP_INVALID_ROUTE, - "selected route %pRN not found", dest); + "selected route %pRN not found", (void *)dest); bgp_dest_unlock_node(dest); return -1; @@ -2684,13 +2699,13 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, */ UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN: Removed from Fib", dest); + zlog_debug("route %pRN: Removed from Fib", (void *)dest); break; case ZAPI_ROUTE_FAIL_INSTALL: new_select = NULL; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("route: %pRN Failed to Install into Fib", - dest); + (void *)dest); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { @@ -2704,7 +2719,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, case ZAPI_ROUTE_BETTER_ADMIN_WON: if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("route: %pRN removed due to better admin won", - dest); + (void *)dest); new_select = NULL; UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); @@ -2719,7 +2734,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, break; case ZAPI_ROUTE_REMOVE_FAIL: zlog_warn("%s: Route %pRN failure to remove", - __func__, dest); + __func__, (void *)dest); break; } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index ed2d5e669d..0edae041d2 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -64,8 +64,8 @@ extern bool bgp_redistribute_rmap_set(struct bgp_redist *red, const char *name, struct route_map *route_map); extern bool bgp_redistribute_metric_set(struct bgp *bgp, struct bgp_redist *red, afi_t afi, int type, uint32_t metric); -extern int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, - unsigned short instance); +extern void bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, + unsigned short instance); extern int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, unsigned short instance); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index aaf1f41c4b..60b394b697 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); @@ -517,11 +519,22 @@ void bgp_cluster_id_unset(struct bgp *bgp) } /* BGP timer configuration. */ -void bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime, - uint32_t connect_retry, uint32_t delayopen) +void bgp_timers_set(struct vty *vty, struct bgp *bgp, uint32_t keepalive, + uint32_t holdtime, uint32_t connect_retry, + uint32_t delayopen) { - bgp->default_keepalive = - (keepalive < holdtime / 3 ? keepalive : holdtime / 3); + uint32_t default_keepalive = holdtime / 3; + + if (keepalive > default_keepalive) { + if (vty) + vty_out(vty, + "%% keepalive value %u is larger than 1/3 of the holdtime, setting to %u\n", + keepalive, default_keepalive); + } else { + default_keepalive = keepalive; + } + + bgp->default_keepalive = default_keepalive; bgp->default_holdtime = holdtime; bgp->default_connect_retry = connect_retry; bgp->default_delayopen = delayopen; @@ -581,7 +594,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 +612,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 +639,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 +694,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 +751,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 +1124,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 +1205,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 +1267,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 +1450,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 +1492,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 +1968,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 +2340,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 +2356,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 +2578,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 +2586,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 +2625,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 +2666,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 +2916,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 +2931,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 +2943,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 +2969,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 +3018,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 +3198,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 +3754,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 +4437,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 +4450,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 +4609,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 +4640,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 +4677,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 +5099,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 +5118,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 +5156,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 +5173,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 +5330,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 +5368,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 +5401,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 +5438,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 +5489,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 +5525,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 +6490,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 +6518,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 +6550,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 +6586,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 +6631,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 +6658,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 +7859,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 +7884,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 +7928,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 +7946,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 +8007,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 +8027,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 +8310,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 +8413,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..dd8096c574 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; @@ -2232,8 +2254,9 @@ extern void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str); extern void bgp_confederation_peers_remove(struct bgp *bgp, as_t as); -extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime, - uint32_t connect_retry, uint32_t delayopen); +extern void bgp_timers_set(struct vty *vty, struct bgp *, uint32_t keepalive, + uint32_t holdtime, uint32_t connect_retry, + uint32_t delayopen); extern void bgp_timers_unset(struct bgp *); extern void bgp_default_local_preference_set(struct bgp *bgp, @@ -2574,7 +2597,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) @@ -2670,7 +2693,7 @@ DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer)); DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_snmp_update_stats, - (struct bgp_node *rn, struct bgp_path_info *pi, bool added), + (struct bgp_dest *rn, struct bgp_path_info *pi, bool added), (rn, pi, added)); DECLARE_HOOK(bgp_rpki_prefix_status, (struct peer * peer, struct attr *attr, 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; @@ -252,6 +252,9 @@ struct interface { /* Interface Speed in Mb/s */ uint32_t speed; + /* TX queue len */ + uint32_t txqlen; + /* Interface MTU. */ unsigned int mtu; /* IPv4 MTU */ unsigned int 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/lib/table.c b/lib/table.c index 380852b54d..3bf93894ec 100644 --- a/lib/table.c +++ b/lib/table.c @@ -334,7 +334,6 @@ void route_node_delete(struct route_node *node) struct route_node *parent; assert(node->lock == 0); - assert(node->info == NULL); if (node->l_left && node->l_right) return; diff --git a/lib/zclient.c b/lib/zclient.c index e40725826a..68a3429822 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2761,6 +2761,7 @@ static void zebra_interface_if_set_value(struct stream *s, STREAM_GETC(s, ifp->ptm_status); STREAM_GETL(s, ifp->metric); STREAM_GETL(s, ifp->speed); + STREAM_GETL(s, ifp->txqlen); STREAM_GETL(s, ifp->mtu); STREAM_GETL(s, ifp->mtu6); STREAM_GETL(s, ifp->bandwidth); 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/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index fd5a4a426e..98d3bbc519 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -1045,6 +1045,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, zlog_debug( "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA", __func__); + ospf6_lsa_delete(new); return; } } else { diff --git a/ospfd/ospf_ti_lfa.c b/ospfd/ospf_ti_lfa.c index f9bc2b4dd6..d8a2613075 100644 --- a/ospfd/ospf_ti_lfa.c +++ b/ospfd/ospf_ti_lfa.c @@ -694,6 +694,7 @@ static void ospf_ti_lfa_generate_q_spaces(struct ospf_area *area, __func__, &p_space->root->id, &q_space->root->id, res_buf); + list_delete(&q_space->vertex_list); XFREE(MTYPE_OSPF_Q_SPACE, q_space->p_node_info); XFREE(MTYPE_OSPF_Q_SPACE, q_space->q_node_info); XFREE(MTYPE_OSPF_Q_SPACE, q_space); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 172356895a..aa3cadf997 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -806,25 +806,6 @@ static void ospf_finish_final(struct ospf *ospf) ospf_area_free(area); } - /* Cancel all timers. */ - EVENT_OFF(ospf->t_read); - EVENT_OFF(ospf->t_write); - EVENT_OFF(ospf->t_spf_calc); - EVENT_OFF(ospf->t_ase_calc); - EVENT_OFF(ospf->t_maxage); - EVENT_OFF(ospf->t_maxage_walker); - EVENT_OFF(ospf->t_abr_task); - EVENT_OFF(ospf->t_abr_fr); - EVENT_OFF(ospf->t_asbr_check); - EVENT_OFF(ospf->t_asbr_redist_update); - EVENT_OFF(ospf->t_distribute_update); - EVENT_OFF(ospf->t_lsa_refresher); - EVENT_OFF(ospf->t_opaque_lsa_self); - EVENT_OFF(ospf->t_sr_update); - EVENT_OFF(ospf->t_default_routemap_timer); - EVENT_OFF(ospf->t_external_aggr); - EVENT_OFF(ospf->gr_info.t_grace_period); - LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) ospf_discard_from_db(ospf, ospf->lsdb, lsa); LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) @@ -912,8 +893,26 @@ static void ospf_finish_final(struct ospf *ospf) } } - route_table_finish(ospf->rt_aggr_tbl); + /* Cancel all timers. */ + EVENT_OFF(ospf->t_read); + EVENT_OFF(ospf->t_write); + EVENT_OFF(ospf->t_spf_calc); + EVENT_OFF(ospf->t_ase_calc); + EVENT_OFF(ospf->t_maxage); + EVENT_OFF(ospf->t_maxage_walker); + EVENT_OFF(ospf->t_abr_task); + EVENT_OFF(ospf->t_abr_fr); + EVENT_OFF(ospf->t_asbr_check); + EVENT_OFF(ospf->t_asbr_redist_update); + EVENT_OFF(ospf->t_distribute_update); + EVENT_OFF(ospf->t_lsa_refresher); + EVENT_OFF(ospf->t_opaque_lsa_self); + EVENT_OFF(ospf->t_sr_update); + EVENT_OFF(ospf->t_default_routemap_timer); + EVENT_OFF(ospf->t_external_aggr); + EVENT_OFF(ospf->gr_info.t_grace_period); + route_table_finish(ospf->rt_aggr_tbl); ospf_free_refresh_queue(ospf); diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 6b81e1058e..774e7ee85a 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -62,7 +62,7 @@ static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1, return 1; } -static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms) +void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms) { XFREE(MTYPE_TMP, pbrms->internal_nhg_name); diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 61577e4076..9fb674bd6e 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -251,6 +251,8 @@ extern void pbr_map_policy_install(const char *name); extern void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi); +extern void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms); + extern void pbr_map_check_vrf_nh_group_change(const char *nh_group, struct pbr_vrf *pbr_vrf, uint32_t old_vrf_id); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 0d6e1afd5b..582ffac9b2 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -123,6 +123,7 @@ DEFUN_NOSH(no_pbr_map, continue; pbr_map_delete(pbrms); + pbr_map_sequence_delete(pbrms); } return CMD_SUCCESS; @@ -441,28 +442,29 @@ DEFPY (pbr_map_match_dscp, } unsigned long ul_dscp; - char *pend; - uint8_t raw_dscp; + char *pend = NULL; + uint8_t shifted_dscp; assert(dscp); - ul_dscp = strtol(dscp, &pend, 0); - if (*pend) - raw_dscp = pbr_map_decode_dscp_enum(dscp); - else - raw_dscp = ul_dscp << 2; - if (raw_dscp > PBR_DSFIELD_DSCP) { + ul_dscp = strtoul(dscp, &pend, 0); + if (pend && *pend) + ul_dscp = pbr_map_decode_dscp_enum(dscp); + + if (ul_dscp > (PBR_DSFIELD_DSCP >> 2)) { vty_out(vty, "Invalid dscp value: %s%s\n", dscp, - (pend ? "" : " (numeric value must be in range 0-63)")); + ((pend && *pend) ? "" : " (numeric value must be in range 0-63)")); return CMD_WARNING_CONFIG_FAILED; } + shifted_dscp = (ul_dscp << 2) & PBR_DSFIELD_DSCP; + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP) && - (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == raw_dscp)) { + ((pbrms->dsfield & PBR_DSFIELD_DSCP) == shifted_dscp)) { return CMD_SUCCESS; } /* Set the DSCP bits of the DSField */ - pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (raw_dscp << 2); + pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | shifted_dscp; SET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP); check: @@ -790,6 +792,9 @@ DEFPY (pbr_map_action_src_port, /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (no) { if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT)) return CMD_SUCCESS; @@ -821,6 +826,9 @@ DEFPY (pbr_map_action_dst_port, /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (no) { if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT)) return CMD_SUCCESS; @@ -851,6 +859,9 @@ DEFPY (pbr_map_action_dscp, /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (no) { if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP)) return CMD_SUCCESS; @@ -859,27 +870,28 @@ DEFPY (pbr_map_action_dscp, } unsigned long ul_dscp; - char *pend; - uint8_t raw_dscp; + char *pend = NULL; + uint8_t shifted_dscp; assert(dscp); - ul_dscp = strtol(dscp, &pend, 0); - if (*pend) - raw_dscp = pbr_map_decode_dscp_enum(dscp); - else - raw_dscp = ul_dscp << 2; + ul_dscp = strtoul(dscp, &pend, 0); + if (pend && *pend) + ul_dscp = pbr_map_decode_dscp_enum(dscp); - if (raw_dscp > PBR_DSFIELD_DSCP) { + if (ul_dscp > (PBR_DSFIELD_DSCP >> 2)) { vty_out(vty, "Invalid dscp value: %s%s\n", dscp, - (pend ? "" : " (numeric value must be in range 0-63)")); + ((pend && *pend) ? "" : " (numeric value must be in range 0-63)")); return CMD_WARNING_CONFIG_FAILED; } + + shifted_dscp = (ul_dscp << 2) & PBR_DSFIELD_DSCP; + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP) && - (pbrms->action_dscp == raw_dscp)) { + (pbrms->action_dscp == shifted_dscp)) { return CMD_SUCCESS; } SET_FLAG(pbrms->action_bm, PBR_ACTION_DSCP); - pbrms->action_dscp = raw_dscp; + pbrms->action_dscp = shifted_dscp; check: pbr_map_check(pbrms, true); @@ -898,6 +910,9 @@ DEFPY (pbr_map_action_ecn, /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (no) { if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN)) return CMD_SUCCESS; @@ -1105,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); } @@ -1263,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; } @@ -1342,6 +1362,7 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, * If an equivalent set vrf * exists, just return success. */ if ((pbrms->forwarding_type == PBR_FT_SETVRF) && + vrf_name && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0) return CMD_SUCCESS; else if (!vrf_name && (pbrms->forwarding_type == PBR_FT_VRF_UNCHANGED)) diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 35c771469c..ee17a193f4 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -568,15 +568,10 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s, /* actions */ - SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ - - /* - * PBR should maintain its own set of action flags that we - * can copy here instead of trying to infer from magic values. - */ - r.action.flags = pbrms->action_bm; + SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ + /* * if the user does not use the command "set vrf name unchanged" * then pbr_encode_pbr_map_sequence_vrf will not be called diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 4a272a4802..a4c9178bb9 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -155,7 +155,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, bool no_fwd; #if PIM_IPV == 4 - if (len < sizeof(*ip_hdr)) { + if (len <= sizeof(*ip_hdr)) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( "PIM packet size=%zu shorter than minimum=%zu", @@ -189,7 +189,6 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, iovp->iov_len = pim_msg_len; iovp++; - header = (struct pim_msg_header *)pim_msg; if (pim_msg_len < PIM_PIM_MIN_LEN) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( @@ -197,6 +196,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, pim_msg_len, PIM_PIM_MIN_LEN); return -1; } + header = (struct pim_msg_header *)pim_msg; if (header->ver != PIM_PROTO_VERSION) { if (PIM_DEBUG_PIM_PACKETS) diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b3e312e047..1f69175829 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -494,6 +494,7 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr, struct pim_interface *pim_ifp = ifp->info; struct pim_instance *pim = pim_ifp->pim; pim_addr rp_addr; + struct pim_rpf *rpg; if (pim_ifp->pim_passive_enable) { if (PIM_DEBUG_PIM_PACKETS) @@ -602,7 +603,14 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr, } } - rp_addr = (RP(pim, sg.grp))->rpf_addr; + rpg = RP(pim, sg.grp); + if (!rpg) { + zlog_warn("%s: Received Register Message %pSG from %pPA on %s where the RP could not be looked up", + __func__, &sg, &src_addr, ifp->name); + return 0; + } + + rp_addr = rpg->rpf_addr; if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) { sentRegisterStop = 0; diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 01cd281d9c..6673cce108 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -135,7 +135,8 @@ static bool static_nexthop_create(struct nb_cb_create_args *args) switch (args->event) { case NB_EV_VALIDATE: ifname = yang_dnode_get_string(args->dnode, "./interface"); - if (ifname != NULL) { + nh_type = yang_dnode_get_enum(args->dnode, "./nh-type"); + if (ifname != NULL && nh_type != STATIC_BLACKHOLE) { if (strcasecmp(ifname, "Null0") == 0 || strcasecmp(ifname, "reject") == 0 || strcasecmp(ifname, "blackhole") == 0) { @@ -371,10 +372,26 @@ static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args) { struct static_nexthop *nh; enum static_nh_type nh_type; + const char *nh_ifname; + const char *nh_vrf; switch (args->event) { case NB_EV_VALIDATE: nh_type = yang_dnode_get_enum(args->dnode, "../nh-type"); + nh_ifname = yang_dnode_get_string(args->dnode, "../interface"); + nh_vrf = yang_dnode_get_string(args->dnode, "../vrf"); + if (nh_ifname && nh_vrf) { + struct vrf *vrf = vrf_lookup_by_name(nh_vrf); + struct interface *ifp = if_lookup_by_name(nh_ifname, + vrf->vrf_id); + + if (ifp && (!strmatch(nh_ifname, "blackhole") || + !strmatch(nh_ifname, "reject"))) { + snprintf(args->errmsg, args->errmsg_len, + "nexthop interface name must be (reject, blackhole)"); + return NB_ERR_VALIDATION; + } + } if (nh_type != STATIC_BLACKHOLE) { snprintf(args->errmsg, args->errmsg_len, "nexthop type is not the blackhole type"); diff --git a/staticd/static_vty.c b/staticd/static_vty.c index d5fd0e3a2e..16e4cb7d83 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -58,6 +58,8 @@ struct static_route_args { bool bfd_multi_hop; const char *bfd_source; const char *bfd_profile; + + const char *input; }; static int static_route_nb_run(struct vty *vty, struct static_route_args *args) @@ -145,9 +147,20 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) else buf_gate_str = ""; - if (args->gateway == NULL && args->interface_name == NULL) + if (args->gateway == NULL && args->interface_name == NULL) { type = STATIC_BLACKHOLE; - else if (args->gateway && args->interface_name) { + /* If this is blackhole/reject flagged route, then + * specify interface_name with the value of what was really + * entered. + * interface_name will be validated later in NB functions + * to check if we don't create blackhole/reject routes that + * match the real interface names. + * E.g.: `ip route 10.0.0.1/32 bla` will create a blackhole + * route despite the real interface named `bla` exists. + */ + if (args->input) + args->interface_name = args->input; + } else if (args->gateway && args->interface_name) { if (args->afi == AFI_IP) type = STATIC_IPV4_GATEWAY_IFNAME; else @@ -499,6 +512,8 @@ DEFPY_YANG(ip_route_blackhole, "Table to configure\n" "The table number to configure\n") { + int idx_flag = 0; + struct static_route_args args = { .delete = !!no, .afi = AFI_IP, @@ -513,6 +528,9 @@ DEFPY_YANG(ip_route_blackhole, .vrf = vrf, }; + if (flag && argv_find(argv, argc, flag, &idx_flag)) + args.input = argv[idx_flag]->arg; + return static_route_nb_run(vty, &args); } @@ -541,6 +559,8 @@ DEFPY_YANG(ip_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { + int idx_flag = 0; + struct static_route_args args = { .delete = !!no, .afi = AFI_IP, @@ -562,6 +582,9 @@ DEFPY_YANG(ip_route_blackhole_vrf, */ assert(args.prefix); + if (flag && argv_find(argv, argc, flag, &idx_flag)) + args.input = argv[idx_flag]->arg; + return static_route_nb_run(vty, &args); } @@ -852,6 +875,8 @@ DEFPY_YANG(ipv6_route_blackhole, "Table to configure\n" "The table number to configure\n") { + int idx_flag = 0; + struct static_route_args args = { .delete = !!no, .afi = AFI_IP6, @@ -866,6 +891,9 @@ DEFPY_YANG(ipv6_route_blackhole, .vrf = vrf, }; + if (flag && argv_find(argv, argc, flag, &idx_flag)) + args.input = argv[idx_flag]->arg; + return static_route_nb_run(vty, &args); } @@ -894,6 +922,8 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { + int idx_flag = 0; + struct static_route_args args = { .delete = !!no, .afi = AFI_IP6, @@ -915,6 +945,9 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, */ assert(args.prefix); + if (flag && argv_find(argv, argc, flag, &idx_flag)) + args.input = argv[idx_flag]->arg; + return static_route_nb_run(vty, &args); } 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_mpath.c b/tests/bgpd/test_mpath.c index 0124ad9b22..bc2c1e8a44 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -244,6 +244,7 @@ static int run_bgp_mp_list(testcase_t *t) for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count; i++, mp_node = listnextnode(mp_node)) { info = listgetdata(mp_node); + info->lock++; EXPECT_TRUE(info == &test_mp_list_info[i], test_result); } @@ -274,14 +275,14 @@ testcase_t test_bgp_mp_list = { * Testcase for bgp_path_info_mpath_update */ -struct bgp_node test_rn; +static struct bgp_dest *dest; static int setup_bgp_path_info_mpath_update(testcase_t *t) { int i; struct bgp *bgp; struct bgp_table *rt; - struct route_node *rt_node; + struct prefix p; as_t asn = 1; t->tmp_data = bgp_create_fake(&asn, NULL); @@ -294,13 +295,12 @@ static int setup_bgp_path_info_mpath_update(testcase_t *t) if (!rt) return -1; - str2prefix("42.1.1.0/24", &test_rn.p); - rt_node = bgp_dest_to_rnode(&test_rn); - memcpy((struct route_table *)&rt_node->table, &rt->route_table, - sizeof(struct route_table)); + str2prefix("42.1.1.0/24", &p); + dest = bgp_node_get(rt, &p); + setup_bgp_mp_list(t); for (i = 0; i < test_mp_list_info_count; i++) - bgp_path_info_add(&test_rn, &test_mp_list_info[i]); + bgp_path_info_add(dest, &test_mp_list_info[i]); return 0; } @@ -309,6 +309,7 @@ static int run_bgp_path_info_mpath_update(testcase_t *t) struct bgp_path_info *new_best, *old_best, *mpath; struct list mp_list; struct bgp_maxpaths_cfg mp_cfg = {3, 3}; + int test_result = TEST_PASSED; bgp_mp_list_init(&mp_list); bgp_mp_list_add(&mp_list, &test_mp_list_info[4]); @@ -317,7 +318,7 @@ static int run_bgp_path_info_mpath_update(testcase_t *t) bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[3]; old_best = NULL; - bgp_path_info_mpath_update(NULL, &test_rn, new_best, old_best, &mp_list, + bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear(&mp_list); EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 2, test_result); @@ -332,7 +333,7 @@ static int run_bgp_path_info_mpath_update(testcase_t *t) bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[0]; old_best = &test_mp_list_info[3]; - bgp_path_info_mpath_update(NULL, &test_rn, new_best, old_best, &mp_list, + bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear(&mp_list); EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 1, test_result); 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/pbr_topo1/test_pbr_topo1.py b/tests/topotests/pbr_topo1/test_pbr_topo1.py index 2b437170ff..a70f2cc8da 100644 --- a/tests/topotests/pbr_topo1/test_pbr_topo1.py +++ b/tests/topotests/pbr_topo1/test_pbr_topo1.py @@ -215,6 +215,8 @@ ftest = [ {"c": "no match dst-port 119", "tN": r"DST Port Match: 119$"}, {"c": "match dscp cs3", "tm": r"DSCP Match: 24$"}, {"c": "no match dscp cs3", "tN": r"DSCP Match: 24$"}, + {"c": "match dscp 5", "tm": r"DSCP Match: 5$"}, + {"c": "no match dscp 5", "tN": r"DSCP Match: 5$"}, {"c": "match ecn 2", "tm": r"ECN Match: 2$"}, {"c": "no match ecn 2", "tN": r"ECN Match: 2$"}, {"c": "match mark 337", "tm": r"MARK Match: 337$"}, @@ -229,8 +231,8 @@ ftest = [ {"c": "no set dst-port 43", "tN": r"Set DST PORT: 43$"}, {"c": "set dscp 24", "tm": r"Set DSCP: 24$"}, {"c": "no set dscp 24", "tN": r"Set DSCP: 24$"}, - {"c": "set dscp cs7", "tm": r"Set DSCP: 14$"}, - {"c": "no set dscp cs7", "tN": r"Set DSCP: 14$"}, + {"c": "set dscp cs7", "tm": r"Set DSCP: 56$"}, + {"c": "no set dscp cs7", "tN": r"Set DSCP: 56$"}, {"c": "set ecn 1", "tm": r"Set ECN: 1$"}, {"c": "no set ecn 1", "tN": r"Set ECN: 1$"}, ] 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/tools/gcc-plugins/Makefile b/tools/gcc-plugins/Makefile index d6edd745ce..2af28fe2b1 100644 --- a/tools/gcc-plugins/Makefile +++ b/tools/gcc-plugins/Makefile @@ -5,11 +5,15 @@ CXX=g++-9 PLUGBASE=`$(CXX) -print-file-name=plugin` CPPFLAGS=-I$(PLUGBASE)/include -I$(PLUGBASE)/include/c-family +# NB: compiler flags must match those used to build gcc, otherwise inlining +# behavior is different and linker errors will result due to missing symbols +# (which should in fact be inlined) + frr-format.so: frr-format.o - $(CXX) -g -shared -o $@ $^ + $(CXX) -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb -shared -o $@ $^ frr-format.o: frr-format.c gcc-common.h - $(CXX) -g $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $< + $(CXX) -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $< install: install -d $(DESTDIR)$(PLUGBASE) diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c index 2240a171b4..a5418e5357 100644 --- a/tools/gcc-plugins/frr-format.c +++ b/tools/gcc-plugins/frr-format.c @@ -3464,7 +3464,7 @@ class frr_range_label_for_type_mismatch : public range_label { } - label_text get_text (unsigned range_idx) const OVERRIDE; + label_text get_text (unsigned range_idx) const override; protected: tree m_labelled_type; @@ -3564,19 +3564,26 @@ class range_label_for_format_type_mismatch { } - label_text get_text (unsigned range_idx) const FINAL OVERRIDE +#if BUILDING_GCC_VERSION >= 13000 +#define text_get(text) text.get() +#define text_return(text, result) return label_text::take(result) +#else +#define text_get(text) text.m_buffer +#define text_return(text, result) text.maybe_free(); return label_take(result) +#endif + + label_text get_text (unsigned range_idx) const final override { label_text text = range_label_for_type_mismatch::get_text (range_idx); - if (text.m_buffer == NULL) + if (text_get(text) == NULL) return text; indirection_suffix suffix (m_pointer_count); char *p = (char *) alloca (suffix.get_buffer_size ()); suffix.fill_buffer (p); - char *result = concat (text.m_buffer, p, NULL); - text.maybe_free (); - return label_take(result); + char *result = concat (text_get(text), p, NULL); + text_return(text, result); } private: diff --git a/tools/gcc-plugins/gcc-common.h b/tools/gcc-plugins/gcc-common.h index 9f59447d63..6eaea9bf74 100644 --- a/tools/gcc-plugins/gcc-common.h +++ b/tools/gcc-plugins/gcc-common.h @@ -111,6 +111,10 @@ #include "varasm.h" #include "stor-layout.h" #include "internal-fn.h" +#if BUILDING_GCC_VERSION >= 13000 +#include "gimple.h" +#include "gimple-iterator.h" +#endif #include "gimple-expr.h" #include "gimple-fold.h" #include "context.h" diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8767b2622c..61a8c6a78a 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -635,8 +635,10 @@ static int netlink_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, struct bridge_vlan_info *vinfo; struct zebra_dplane_bridge_vlan_info bvinfo; - if (!af_spec) + if (!af_spec) { + dplane_ctx_set_ifp_no_afspec(ctx); return 0; + } netlink_bridge_vxlan_vlan_vni_map_update(ctx, af_spec); @@ -644,8 +646,10 @@ static int netlink_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, * only 1 access VLAN is accepted. */ netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, af_spec); - if (!aftb[IFLA_BRIDGE_VLAN_INFO]) + if (!aftb[IFLA_BRIDGE_VLAN_INFO]) { + dplane_ctx_set_ifp_no_bridge_vlan_info(ctx); return 0; + } vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]); bvinfo.flags = vinfo->flags; @@ -1504,6 +1508,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ns_id_t link_nsid = ns_id; ifindex_t master_infindex = IFINDEX_INTERNAL; uint8_t bypass = 0; + uint32_t txqlen = 0; frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); @@ -1582,6 +1587,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) link_nsid = ns_id_get_absolute(ns_id, link_nsid); } + if (tb[IFLA_TXQLEN]) + txqlen = *(uint32_t *)RTA_DATA(tb[IFLA_TXQLEN]); + struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); dplane_ctx_set_ns_id(ctx, ns_id); dplane_ctx_set_ifp_link_nsid(ctx, link_nsid); @@ -1590,6 +1598,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) dplane_ctx_set_ifname(ctx, name); dplane_ctx_set_ifp_startup(ctx, startup); dplane_ctx_set_ifp_family(ctx, ifi->ifi_family); + dplane_ctx_set_intf_txqlen(ctx, txqlen); /* We are interested in some AF_BRIDGE notifications. */ #ifndef AF_BRIDGE diff --git a/zebra/interface.c b/zebra/interface.c index 10839e2106..5c01e64e0f 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); @@ -1853,9 +1859,15 @@ static void interface_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, struct zebra_if *zif = ifp->info; const struct zebra_dplane_bridge_vlan_info *bvinfo; + if (dplane_ctx_get_ifp_no_afspec(ctx)) + return; + if (IS_ZEBRA_VXLAN_IF_SVD(zif)) interface_bridge_vxlan_vlan_vni_map_update(ctx, ifp); + if (dplane_ctx_get_ifp_no_bridge_vlan_info(ctx)) + return; + bvinfo = dplane_ctx_get_ifp_bridge_vlan_info(ctx); if (!(bvinfo->flags & DPLANE_BRIDGE_VLAN_INFO_PVID)) @@ -2048,6 +2060,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) ifp->metric = 0; ifp->speed = kernel_get_speed(ifp, NULL); ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); /* Set interface type */ zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); @@ -2130,6 +2143,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) set_ifindex(ifp, ifindex, zns); ifp->mtu6 = ifp->mtu = mtu; ifp->metric = 0; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); /* * Update interface type - NOTE: Only slave_type can @@ -2774,8 +2788,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) return; } - vty_out(vty, " index %d metric %d mtu %d speed %u ", ifp->ifindex, - ifp->metric, ifp->mtu, ifp->speed); + vty_out(vty, " index %d metric %d mtu %d speed %u txqlen %u", + ifp->ifindex, ifp->metric, ifp->mtu, ifp->speed, ifp->txqlen); if (ifp->mtu6 != ifp->mtu) vty_out(vty, "mtu6 %d ", ifp->mtu6); vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags)); @@ -3162,6 +3176,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, if (ifp->mtu6 != ifp->mtu) json_object_int_add(json_if, "mtu6", ifp->mtu6); json_object_int_add(json_if, "speed", ifp->speed); + json_object_int_add(json_if, "txqlen", ifp->txqlen); json_object_string_add(json_if, "flags", if_flag_dump(ifp->flags)); /* Hardware address. */ 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/zapi_msg.c b/zebra/zapi_msg.c index f6afb006b7..6bed6d8727 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -71,6 +71,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp) stream_putc(s, ifp->ptm_status); stream_putl(s, ifp->metric); stream_putl(s, ifp->speed); + stream_putl(s, ifp->txqlen); stream_putl(s, ifp->mtu); stream_putl(s, ifp->mtu6); stream_putl(s, ifp->bandwidth); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e527d93610..03d7bb88a2 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -197,6 +197,8 @@ struct dplane_intf_info { bool startup; uint8_t family; struct zebra_vxlan_vni_array *vniarray; + bool no_bvinfo_avail; + bool no_afspec_avail; struct zebra_dplane_bridge_vlan_info bvinfo; struct zebra_dplane_bridge_vlan_info_array *bvarray; @@ -214,6 +216,8 @@ struct dplane_intf_info { uint32_t rc_bitfield; + uint32_t txqlen; + uint32_t metric; uint32_t flags; @@ -1355,6 +1359,34 @@ dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx) return ctx->u.intf.vniarray; } +void dplane_ctx_set_ifp_no_afspec(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.no_afspec_avail = true; +} + +bool dplane_ctx_get_ifp_no_afspec(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.no_afspec_avail; +} + +void dplane_ctx_set_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.no_bvinfo_avail = true; +} + +bool dplane_ctx_get_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.no_bvinfo_avail; +} + void dplane_ctx_set_ifp_bridge_vlan_info( struct zebra_dplane_ctx *ctx, struct zebra_dplane_bridge_vlan_info *bvinfo) @@ -2626,6 +2658,20 @@ void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) } } +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.txqlen = txqlen; +} + +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.txqlen; +} + /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx) { diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 79248a4ae4..4d4a17bbae 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -429,6 +429,10 @@ struct zebra_dplane_bridge_vlan_info { uint16_t flags; uint16_t vid; }; +void dplane_ctx_set_ifp_no_afspec(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_get_ifp_no_afspec(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_get_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx); void dplane_ctx_set_ifp_bridge_vlan_info( struct zebra_dplane_ctx *ctx, struct zebra_dplane_bridge_vlan_info *bvinfo); @@ -668,6 +672,8 @@ void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx, bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label); +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen); +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx); /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 39c1319f31..4f7a1cd4ce 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -383,7 +383,8 @@ void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, assert(zif); /* This would be called only in non svd case */ - assert(IS_ZEBRA_VXLAN_IF_VNI(zif)); + if (!IS_ZEBRA_VXLAN_IF_VNI(zif)) + return; old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan; ; 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; } |
