diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index a86c457b62..328e3a0eb0 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1197,15 +1197,20 @@ int bgp_stop(struct peer *peer) !CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) { gr_info = &bgp->gr_info[afi][safi]; - if (gr_info && gr_info->eor_required) + + if (gr_info && (gr_info->eor_required)) gr_info->eor_required--; - if (BGP_DEBUG(update, UPDATE_OUT)) - zlog_debug("peer %s, EOR %d", + + if (gr_info && BGP_DEBUG(update, + UPDATE_OUT)) + zlog_debug( + "peer %s, EOR %d", peer->host, gr_info->eor_required); /* There is no pending EOR message */ - if (gr_info->eor_required == 0) { + if (gr_info && gr_info->eor_required + == 0) { BGP_TIMER_OFF( gr_info->t_select_deferral); gr_info->eor_received = 0; @@ -1813,7 +1818,15 @@ static int bgp_establish(struct peer *peer) if (status < 0) zlog_debug("Error in updating graceful restart for %s", get_afi_safi_str(afi, - safi, false)); + safi, false)); + } else { + if (BGP_PEER_GRACEFUL_RESTART_CAPABLE( + peer) && + BGP_PEER_RESTARTING_MODE(peer) + && bgp_flag_check(peer->bgp, + BGP_FLAG_GR_PRESERVE_FWD)) + peer->bgp->gr_info[afi][safi] + .eor_required++; } } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 88b95496e6..d6510dfaf2 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -449,14 +449,20 @@ int bgp_generate_updgrp_packets(struct thread *thread) /* If EOR is disabled, * the message is not sent */ - if (!bgp_flag_check(peer->bgp, - BGP_FLAG_GR_DISABLE_EOR - )) { + if (BGP_SEND_EOR(peer->bgp, + afi, safi)) { SET_FLAG( peer->af_sflags [afi][safi], PEER_STATUS_EOR_SEND); + /* Update EOR + * send time + */ + peer->eor_stime + [afi][safi] = + monotime(NULL); + BGP_UPDATE_EOR_PKT( peer, afi, safi, s); @@ -465,6 +471,10 @@ int bgp_generate_updgrp_packets(struct thread *thread) } continue; } + + /* Update packet send time */ + peer->pkt_stime[afi][safi] = monotime(NULL); + /* Found a packet template to send, overwrite * packet with appropriate attributes from peer * and advance peer */ @@ -2422,3 +2432,14 @@ int bgp_process_packet(struct thread *thread) return 0; } + +/* Send EOR when routes are processed by selection deferral timer */ +void bgp_send_delayed_eor(struct bgp *bgp) +{ + struct peer *peer; + struct listnode *node, *nnode; + + /* EOR message sent in bgp_write_proceed_actions */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_write_proceed_actions(peer); +} diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 1c2bafcb74..0242abab26 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -81,4 +81,5 @@ extern int bgp_packet_set_size(struct stream *s); extern int bgp_generate_updgrp_packets(struct thread *); extern int bgp_process_packet(struct thread *); +extern void bgp_send_delayed_eor(struct bgp *bgp); #endif /* _QUAGGA_BGP_PACKET_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 75963def86..217e73adf0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2736,7 +2736,6 @@ int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Process the route list */ node = listhead(bgp->gr_info[afi][safi].route_list); - node = listhead(bgp->gr_info[afi][safi].route_list); while (node) { rn = listgetdata(node); nnode = node->next; @@ -2753,8 +2752,11 @@ int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) node = nnode; } - if (list_isempty(bgp->gr_info[afi][safi].route_list)) + /* Send EOR message when all routes are processed */ + if (list_isempty(bgp->gr_info[afi][safi].route_list)) { + bgp_send_delayed_eor(bgp); return 0; + } thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info)); if (thread_info == NULL) { @@ -3055,8 +3057,6 @@ void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi, if (delete_route) { if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) { UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER); - UNSET_FLAG(rn->flags, - BGP_NODE_PROCESS_SCHEDULED); bgp = pi->peer->bgp; if ((rn->rt_node) && (bgp->gr_info[afi][safi] diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 01efab8f2d..2ef272b571 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -141,12 +141,13 @@ void bgp_delete_listnode(struct bgp_node *node) */ if (CHECK_FLAG(node->flags, BGP_NODE_SELECT_DEFER)) { table = bgp_node_table(node); - if (table) - bgp = table->bgp; - rn = bgp_node_to_rnode(node); - afi = table->afi; - safi = table->safi; + if (table) { + bgp = table->bgp; + afi = table->afi; + safi = table->safi; + } + rn = bgp_node_to_rnode(node); if (bgp && rn && rn->lock == 1) { /* Delete the route from the selection pending list */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 71a41cd688..c4689989c7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9474,6 +9474,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( json_object *json_afi_safi = NULL; json_object *json_timer = NULL; json_object *json_endofrib_status = NULL; + bool eor_flag = false; for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { @@ -9490,6 +9491,12 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( json_object_new_object(); } + if (peer->eor_stime[afi][safi] >= + peer->pkt_stime[afi][safi]) + eor_flag = true; + else + eor_flag = false; + if (!use_json) { vty_out(vty, " %s :\n", get_afi_safi_str(afi, safi, false)); @@ -9555,22 +9562,32 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( if (CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)) { - if (use_json) { json_object_boolean_true_add( json_endofrib_status, "endOfRibSend"); + + PRINT_EOR_JSON(eor_flag); } else { vty_out(vty, "Yes\n"); - } + vty_out(vty, + " EoRSentAfterUpdate : "); + PRINT_EOR(eor_flag); + } } else { if (use_json) { json_object_boolean_false_add( json_endofrib_status, "endOfRibSend"); + json_object_boolean_false_add( + json_endofrib_status, + "endOfRibSentAfterUpdate"); } else { vty_out(vty, "No\n"); + vty_out(vty, + " EoRSentAfterUpdate : "); + vty_out(vty, "No\n"); } } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 3f60c7719c..3dc639ea76 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -68,6 +68,27 @@ struct bgp; vty, p, use_json, json); \ } while (0) + +#define PRINT_EOR(_eor_flag) \ + do { \ + if (eor_flag) \ + vty_out(vty, "Yes\n"); \ + else \ + vty_out(vty, "No\n"); \ + } while (0) + +#define PRINT_EOR_JSON(_eor_flag) \ + do { \ + if (eor_flag) \ + json_object_boolean_true_add( \ + json_endofrib_status, \ + "endOfRibSentAfterUpdate"); \ + else \ + json_object_boolean_false_add( \ + json_endofrib_status, \ + "endOfRibSentAfterUpdate"); \ + } while (0) + extern void bgp_vty_init(void); extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9b4f8d3eb4..3c9f9cb595 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -232,6 +232,11 @@ enum bgp_instance_type { BGP_INSTANCE_TYPE_VIEW }; +#define BGP_SEND_EOR(bgp, afi, safi) \ + (!bgp_flag_check(bgp, BGP_FLAG_GR_DISABLE_EOR) && \ + ((bgp->gr_info[afi][safi].t_select_deferral == NULL) || \ + (bgp->gr_info[afi][safi].eor_required == \ + bgp->gr_info[afi][safi].eor_received))) /* BGP GR Global ds */ @@ -1061,6 +1066,10 @@ struct peer { /* NSF mode (graceful restart) */ uint8_t nsf[AFI_MAX][SAFI_MAX]; + /* EOR Send time */ + time_t eor_stime[AFI_MAX][SAFI_MAX]; + /* Last update packet sent time */ + time_t pkt_stime[AFI_MAX][SAFI_MAX]; /* Peer Per AF flags */ /*