diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index f476b161884a..f0e74dedec94 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -63,6 +63,7 @@ unsigned long conf_bgp_debug_vpn; unsigned long conf_bgp_debug_flowspec; unsigned long conf_bgp_debug_labelpool; unsigned long conf_bgp_debug_pbr; +unsigned long conf_bgp_debug_graceful_restart; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_neighbor_events; @@ -80,6 +81,7 @@ unsigned long term_bgp_debug_vpn; unsigned long term_bgp_debug_flowspec; unsigned long term_bgp_debug_labelpool; unsigned long term_bgp_debug_pbr; +unsigned long term_bgp_debug_graceful_restart; struct list *bgp_debug_neighbor_events_peers = NULL; struct list *bgp_debug_keepalive_peers = NULL; @@ -1644,6 +1646,23 @@ DEFUN (debug_bgp_zebra, return CMD_SUCCESS; } +DEFUN (debug_bgp_graceful_restart, + debug_bgp_graceful_restart_cmd, + "debug bgp graceful-restart", + DEBUG_STR + BGP_STR + GR_DEBUG) +{ + if (vty->node == CONFIG_NODE) { + DEBUG_ON(graceful_restart, GRACEFUL_RESTART); + } else { + TERM_DEBUG_ON(graceful_restart, GRACEFUL_RESTART); + vty_out(vty, "BGP Graceful Restart debugging is on\n"); + } + return CMD_SUCCESS; +} + + DEFUN (debug_bgp_zebra_prefix, debug_bgp_zebra_prefix_cmd, "debug bgp zebra prefix ", @@ -1702,6 +1721,23 @@ DEFUN (no_debug_bgp_zebra, return CMD_SUCCESS; } +DEFUN (no_debug_bgp_graceful_restart, + no_debug_bgp_graceful_restart_cmd, + "no debug bgp graceful-restart", + DEBUG_STR + BGP_STR + GR_DEBUG + NO_STR) +{ + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + } else { + TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + vty_out(vty, "BGP Graceful Restart debugging is on\n"); + } + return CMD_SUCCESS; +} + DEFUN (no_debug_bgp_zebra_prefix, no_debug_bgp_zebra_prefix_cmd, "no debug bgp zebra prefix ", @@ -2039,6 +2075,8 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(labelpool, LABELPOOL); TERM_DEBUG_OFF(pbr, PBR); TERM_DEBUG_OFF(pbr, PBR_ERROR); + TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + vty_out(vty, "All possible debugging has been turned off\n"); return CMD_SUCCESS; @@ -2094,7 +2132,11 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(zebra, ZEBRA)) bgp_debug_list_print(vty, " BGP zebra debugging is on", - bgp_debug_zebra_prefixes); + bgp_debug_zebra_prefixes); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + vty_out(vty, + " BGP graceful-restart debugging is on"); if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) vty_out(vty, " BGP allow martian next hop debugging is on\n"); @@ -2229,6 +2271,13 @@ static int bgp_config_write_debug(struct vty *vty) vty_out(vty, "debug bgp pbr error\n"); write++; } + + if (CONF_BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { + vty_out(vty, "debug bgp graceful-restart\n"); + write++; + + } + return write; } @@ -2262,6 +2311,11 @@ void bgp_debug_init(void) install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd); install_element(CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd); + install_element(ENABLE_NODE, &debug_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &debug_bgp_graceful_restart_cmd); + + + /* debug bgp updates (in|out) */ install_element(ENABLE_NODE, &debug_bgp_update_direct_cmd); install_element(CONFIG_NODE, &debug_bgp_update_direct_cmd); @@ -2327,6 +2381,9 @@ void bgp_debug_init(void) install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd); install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_graceful_restart_cmd); + install_element(ENABLE_NODE, &debug_bgp_vpn_cmd); install_element(CONFIG_NODE, &debug_bgp_vpn_cmd); install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 0be8becbabc5..0362121f4c9f 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1068,6 +1068,7 @@ int bgp_stop(struct peer *peer) safi_t safi; char orf_name[BUFSIZ]; int ret = 0; + peer->nsf_af_count = 0; if (peer_dynamic_neighbor(peer) && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { @@ -1090,6 +1091,7 @@ int bgp_stop(struct peer *peer) /* bgp log-neighbor-changes of neighbor Down */ if (bgp_flag_check(peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) { struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id); + zlog_info( "%%ADJCHANGE: neighbor %s(%s) in vrf %s Down %s", peer->host, @@ -1638,6 +1640,8 @@ static int bgp_establish(struct peer *peer) } } + peer->nsf_af_count = nsf_af_count; + if (nsf_af_count) SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); else { @@ -2054,3 +2058,392 @@ int bgp_event_update(struct peer *peer, int event) return ret; } +/* BGP GR Code */ + +int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, + enum global_mode global_new_state, + enum global_mode global_old_state) +{ + struct peer *peer = {0}; + struct listnode *node = {0}; + struct listnode *nnode = {0}; + enum peer_mode peer_old_state = PEER_INVALID; + + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + peer_old_state = PEER_INVALID; + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: %s ---> Peer: (%s) :", + __func__, peer->host); + + peer_old_state = bgp_peer_gr_mode_get(peer); + + if (peer_old_state == PEER_GLOBAL_INHERIT) { + + /* + *Reset only these peers and send a + *new open message with the change capabilities. + *Considering the mode to be "global_new_state" and + *do all operation accordingly + */ + + switch (global_new_state) { + + case GLOBAL_HELPER: + + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + case GLOBAL_GR: + + BGP_PEER_GR_ENABLE(peer); + break; + case GLOBAL_DISABLE: + + BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: + + zlog_debug( + "BGP_GR:: ERROR: %s :GLOBAL_INVALID", + __func__); + return BGP_ERR_GR_OPERATION_FAILED; + default: + + zlog_debug( + "BGP_GR:: %s :Global unknown ERROR", + __func__); + return BGP_ERR_GR_OPERATION_FAILED; + } + } + } + + bgp->global_gr_present_state = global_new_state; + + /* debug Trace msg */ + return BGP_GR_SUCCESS; +} + +int bgp_gr_update_all(struct bgp *bgp, int global_GR_Cmd) +{ + enum global_mode global_new_state = GLOBAL_INVALID; + enum global_mode global_old_state = GLOBAL_INVALID; + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR::%s:START ---> global_GR_Cmd :%d:", + __func__, global_GR_Cmd); + + + global_old_state = bgp_global_gr_mode_get(bgp); + + if (global_old_state != GLOBAL_INVALID) { + + global_new_state = + bgp->GLOBAL_GR_FSM[global_old_state][global_GR_Cmd]; + } else { + /* Trace msg */ + zlog_debug("BGP_GR::%s:global_old_state == GLOBAL_INVALID", + __func__); + return BGP_ERR_GR_OPERATION_FAILED; + } + + if (global_new_state == GLOBAL_INVALID) { + /* Trace msg */ + zlog_debug( + "BGP_GR::%s: global_new_state == GLOBAL_INVALID", + __func__); + return BGP_ERR_GR_INVALID_CMD; + } + if (global_new_state == global_old_state) { + /* Trace msg */ + zlog_debug( + "BGP_GR::%s : global_new_state == global_old_state", + __func__); + return BGP_GR_NO_OPERATION; + } + + return bgp_gr_lookup_n_update_all_peer(bgp, + global_new_state, + global_old_state); +} + +enum global_mode bgp_global_gr_mode_get(struct bgp *bgp) +{ + return bgp->global_gr_present_state; +} + +enum peer_mode bgp_peer_gr_mode_get(struct peer *peer) +{ + return peer->peer_gr_present_state; +} + + +int bgp_neighbor_graceful_restart(struct peer *peer, + int peer_GR_Cmd) +{ + + enum peer_mode peer_new_state = PEER_INVALID; + enum peer_mode peer_old_state = PEER_INVALID; + struct bgp_peer_gr peer_state = {0}; + int result = BGP_GR_FAILURE; + + /* + * fetch peer_old_state from peer structure also + * fetch global_old_state from bgp structure, + * peer had a back pointer to bgpo struct ; + */ + + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: %s:START--->Peer: (%s) : peer_GR_Cmd :%d:", + __func__, peer->host, peer_GR_Cmd); + + peer_old_state = bgp_peer_gr_mode_get(peer); + + if (peer_old_state == PEER_INVALID) { + /* debug Trace msg */ + zlog_debug( + "BGP_GR:: peer_old_state ==Invalid state !"); + return BGP_ERR_GR_OPERATION_FAILED; + } + + peer_state = peer->PEER_GR_FSM[peer_old_state][peer_GR_Cmd]; + peer_new_state = peer_state.next_state; + + if (peer_new_state == PEER_INVALID) { + /* debug Trace msg */ + zlog_debug( + "BGP_GR:: Invalid bgp graceful restart command used !"); + return BGP_ERR_GR_INVALID_CMD; + } + + if (peer_new_state != peer_old_state) { + result = peer_state.action_fun(peer, + peer_old_state, + peer_new_state); + } else { + /* debug Trace msg */ + zlog_debug( + "BGP_GR:: peer_old_state == peer_new_state !"); + return BGP_GR_NO_OPERATION; + } + + if (result == BGP_GR_SUCCESS) { + + /* Update the mode i.e peer_new_state into the peer structure */ + peer->peer_gr_present_state = peer_new_state; + /* debug Trace msg */ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("BGP_GR:: Succesfully change the state of the peer to : %d : !", + peer_new_state); + + return BGP_GR_SUCCESS; + } + return result; +} + +unsigned int bgp_peer_gr_action(struct peer *peer, + int old_peer_state, int new_peer_state) +{ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: %s : Move peer from old_peer_state :%d: to old_peer_state :%d: !!!!", + __func__, old_peer_state, new_peer_state); + + int bgp_gr_global_mode = GLOBAL_INVALID; + unsigned int ret = BGP_GR_FAILURE; + + if (old_peer_state == new_peer_state) { + /* Nothing to do over here as the present and old state is the same */ + /* debug Trace msg */ + return BGP_GR_NO_OPERATION; + } + if ((old_peer_state == PEER_INVALID) || + (new_peer_state == PEER_INVALID)) { + /* something bad happend , print error message */ + return BGP_ERR_GR_INVALID_CMD; + } + + bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); + + if ((old_peer_state == PEER_GLOBAL_INHERIT) && + (new_peer_state != PEER_GLOBAL_INHERIT)) { + + /* fetch the Mode running in the Global state machine + *from the bgp structure into a variable called + *bgp_gr_global_mode + */ + + /* Here we are checking if the + *1. peer_new_state == global_mode == helper_mode + *2. peer_new_state == global_mode == GR_mode + *3. peer_new_state == global_mode == disabled_mode + */ + + BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); + + if (new_peer_state == bgp_gr_global_mode) { + /*This is incremental updates i.e no tear down + *of the existing session + *as the peer is already working in the same mode. + */ + /* debug Trace msg */ + ret = BGP_GR_SUCCESS; + } else { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: Peer state changed from :%d =>", + old_peer_state); + + bgp_peer_move_to_gr_mode(peer, new_peer_state); + + ret = BGP_GR_SUCCESS; + } + } + /* In the case below peer is going into Global inherit mode i.e. + * the peer would work as the mode configured at the global level + */ + else if ((new_peer_state == PEER_GLOBAL_INHERIT) && + (old_peer_state != PEER_GLOBAL_INHERIT)) { + /* Here in this case it would be destructive + * in all the cases except one case when, + * Global GR is configured Disabled + * and present_peer_state is not disable + */ + + BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); + + if (old_peer_state == bgp_gr_global_mode) { + + /* This is incremental updates + *i.e no tear down of the existing session + *as the peer is already working in the same mode. + */ + ret = BGP_GR_SUCCESS; + } else { + /* Destructive always */ + /* Tear down the old session + * and send the new capability + * as per the bgp_gr_global_mode + */ + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("BGP_GR:: Peer state changed from :%d ==>", + old_peer_state); + + bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + + ret = BGP_GR_SUCCESS; + } + } else { + /* + *This else case, it include all the cases except --> + *(new_peer_state != Peer_Global) && + *( old_peer_state != Peer_Global ) + */ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("BGP_GR:: Peer state changed from :%d ===>", + old_peer_state); + + bgp_peer_move_to_gr_mode(peer, new_peer_state); + + ret = BGP_GR_SUCCESS; + } + return ret; +} + + +inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) + +{ + int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + + switch (new_state) { + + case PEER_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + + case PEER_GR: + BGP_PEER_GR_ENABLE(peer); + break; + + case PEER_DISABLE: + BGP_PEER_GR_DISABLE(peer); + break; + + case PEER_GLOBAL_INHERIT: + BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); + + if (bgp_global_gr_mode == GLOBAL_HELPER) { + BGP_PEER_GR_HELPER_ENABLE(peer); + } else if (bgp_global_gr_mode == GLOBAL_GR) { + BGP_PEER_GR_ENABLE(peer); + } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { + BGP_PEER_GR_DISABLE(peer); + } else { + zlog_debug( + "BGP_GR:: Default switch inherit mode ::: SOMETHING IS WORONG !!!"); + } + break; + default: + zlog_debug("BGP_GR:: Default switch mode ::: SOMETHING IS WORONG !!!"); + break; + } + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("BGP_GR:: Peer state changed --to--> : %d : !", + new_state); +} + +void bgp_peer_gr_flags_update(struct peer *peer) +{ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: %s called !", + __func__); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) + bgp_peer_flag_set(peer, + PEER_FLAG_GRACEFUL_RESTART_HELPER); + else + bgp_peer_flag_unset(peer, + PEER_FLAG_GRACEFUL_RESTART_HELPER); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", + peer->host, + (bgp_peer_flag_check(peer, + PEER_FLAG_GRACEFUL_RESTART_HELPER) ? + "Set" : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) + bgp_peer_flag_set(peer, + PEER_FLAG_GRACEFUL_RESTART); + else + bgp_peer_flag_unset(peer, + PEER_FLAG_GRACEFUL_RESTART); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", + peer->host, + (bgp_peer_flag_check(peer, + PEER_FLAG_GRACEFUL_RESTART) ? + "Set" : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) + bgp_peer_flag_set(peer, + PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + else + bgp_peer_flag_unset(peer, + PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", + peer->host, + (bgp_peer_flag_check(peer, + PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) ? + "Set" : "UnSet")); +} diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 49f7337d7653..dbb092ad4f39 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1177,7 +1177,118 @@ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer) return peer; } +/* BGP GR changes */ + +int bgp_global_gr_init(struct bgp *bgp) +{ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s called ..", __func__); + + int local_GLOBAL_GR_FSM[GLOBAL_MODE][EVENT_CMD] = { + /* GLOBAL_HELPER Mode */ + { + /*Event -> */ + /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/ + GLOBAL_GR, GLOBAL_INVALID, + /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/ + GLOBAL_DISABLE, GLOBAL_INVALID + }, + /* GLOBAL_GR Mode */ + { + /*Event -> */ + /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/ + GLOBAL_INVALID, GLOBAL_HELPER, + /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/ + GLOBAL_DISABLE, GLOBAL_INVALID + }, + /* GLOBAL_DISABLE Mode */ + { + /*Event -> */ + /*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/ + GLOBAL_GR, GLOBAL_INVALID, + /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/ + GLOBAL_INVALID, GLOBAL_HELPER + }, + /* GLOBAL_INVALID Mode */ + { + /*Event -> */ + /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/ + GLOBAL_INVALID, GLOBAL_INVALID, + /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/ + GLOBAL_INVALID, GLOBAL_INVALID + } + }; + memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, + sizeof(local_GLOBAL_GR_FSM)); + + bgp->global_gr_present_state = GLOBAL_HELPER; + + return BGP_GR_SUCCESS; +} + + +int bgp_peer_gr_init(struct peer *peer) +{ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s called ..", __func__); + + struct bgp_peer_gr local_Peer_GR_FSM[PEER_MODE][PEER_EVENT_CMD] = { + { + /* PEER_HELPER Mode */ + /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ + { PEER_GR, bgp_peer_gr_action }, {PEER_INVALID, NULL }, + /* Event-> */ /* PEER_DISABLE_cmd */ /* NO_PEER_DISABLE_CMD */ + {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL }, + /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ + { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT, + bgp_peer_gr_action } + }, + { + /* PEER_GR Mode */ + /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ + { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + bgp_peer_gr_action }, + /* Event-> */ /* PEER_DISABLE_cmd */ /* NO_PEER_DISABLE_CMD */ + {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ + { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } + }, + { + /* PEER_DISABLE Mode */ + /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ + { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_DISABLE_cmd */ /* NO_PEER_DISABLE_CMD */ + { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + bgp_peer_gr_action }, + /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ + { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } + }, + { + /* PEER_INVALID Mode */ + /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ + { PEER_INVALID, NULL }, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_DISABLE_cmd */ /* NO_PEER_DISABLE_CMD */ + { PEER_INVALID, NULL }, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ + { PEER_INVALID, NULL }, { PEER_INVALID, NULL }, + }, + { + /* PEER_GLOBAL_INHERIT Mode */ + /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ + { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_DISABLE_cmd */ /* NO_PEER_DISABLE_CMD */ + { PEER_DISABLE, bgp_peer_gr_action}, { PEER_INVALID, NULL }, + /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ + { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } + } + }; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, + sizeof(local_Peer_GR_FSM)); + peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); + return BGP_GR_SUCCESS; +} /* Allocate new peer object, implicitely locked. */ struct peer *peer_new(struct bgp *bgp) { @@ -1228,6 +1339,9 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + /* Initialize per peer bgp GR FSM */ + bgp_peer_gr_init(peer); + /* Create buffers. */ peer->ibuf = stream_fifo_new(); peer->obuf = stream_fifo_new(); @@ -1609,6 +1723,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, else if (!active && peer_active(peer)) bgp_timer_set(peer); + bgp_peer_gr_flags_update(peer); return peer; } @@ -3052,6 +3167,9 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_evpn_init(bgp); bgp_pbr_init(bgp); + + /*initilize global GR FSM */ + bgp_global_gr_init(bgp); return bgp; } @@ -7024,7 +7142,6 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } } } - /* local-as */ if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) { vty_out(vty, " neighbor %s local-as %u", addr, @@ -7165,6 +7282,33 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* strict-capability-match */ if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH)) vty_out(vty, " neighbor %s strict-capability-match\n", addr); + + if (!CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) { + + if (CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) { + + vty_out(vty, + " neighbor %s graceful-restart-helper\n", addr); + + } else if (CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) { + + vty_out(vty, + " neighbor %s graceful-restart\n", addr); + + } else if ((!(CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) + && !(CHECK_FLAG(peer->peer_gr_new_status_flag, + PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) { + + vty_out(vty, + " neighbor %s graceful-restart-disable\n", + addr); + + } + } } /* BGP peer configuration display function. */ @@ -7681,12 +7825,17 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " bgp graceful-restart stalepath-time %u\n", bgp->stalepath_time); + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) vty_out(vty, " bgp graceful-restart restart-time %u\n", bgp->restart_time); - if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART)) + + if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) vty_out(vty, " bgp graceful-restart\n"); + if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) + vty_out(vty, " bgp graceful-restart-disable\n"); + /* BGP graceful-shutdown */ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, " bgp graceful-shutdown\n"); @@ -7755,8 +7904,12 @@ int bgp_config_write(struct vty *vty) /* Normal neighbor configuration. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) { + zlog_debug( + "\n\nPeer :%s: PEER_FLAG_CONFIG_NODE :set:\n\n", + peer->host); bgp_config_write_peer_global(vty, bgp, peer); + } } /* listen range and limit for dynamic BGP neighbors */ @@ -8111,3 +8264,37 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, return peer; } + +/* BGP peer flag manipulation. */ +int bgp_peer_flag_set(struct peer *peer, int flag) +{ + SET_FLAG(peer->flags, flag); + return 0; +} + +int bgp_peer_flag_unset(struct peer *peer, int flag) +{ + UNSET_FLAG(peer->flags, flag); + return 0; +} + +int bgp_peer_flag_check(struct peer *peer, int flag) +{ + return CHECK_FLAG(peer->flags, flag); +} + +void bgp_gr_apply_running_config(void) +{ + struct peer *peer = NULL; + struct bgp *bgp = NULL; + struct listnode *node, *nnode; + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug( + "BGP_GR:: %s called !", + __func__); + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_peer_gr_flags_update(peer); +}