From fec1288ecf9f539b7c55776d5892b32d3568ba2b Mon Sep 17 00:00:00 2001 From: Brady Johnson Date: Tue, 7 Jul 2020 15:50:22 +0200 Subject: [PATCH] Improve Multi-PCE encapsulation - Multi-PCE functions that work on pcc_state have been moved to path_pcep_pcc.c Signed-off-by: Brady Johnson --- pathd/path_pcep_cli.c | 26 ++- pathd/path_pcep_controller.c | 397 +++++------------------------------ pathd/path_pcep_controller.h | 4 +- pathd/path_pcep_pcc.c | 330 ++++++++++++++++++++++++++++- pathd/path_pcep_pcc.h | 18 +- 5 files changed, 411 insertions(+), 364 deletions(-) diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 5d8beba93761..c5463723301e 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -602,7 +602,8 @@ static int path_pcep_cli_pcc_peer_delete(struct vty *vty, return CMD_WARNING; } - if (pcep_ctrl_pcc_has_pce(pcep_g->fpt, pcc_peer_name)) { + if (pcep_pcc_pcc_has_pce(pcep_ctrl_get_state_by_fpt(pcep_g->fpt), + pcc_peer_name)) { vty_out(vty, "%% Cannot delete PCC peer, since it is in use by a PCC.\n"); return CMD_WARNING; @@ -818,11 +819,11 @@ static int path_pcep_cli_peer_timers( PCEP_VTYSH_INT_ARG_CHECK(max_peer_keep_alive_str, max_peer_keep_alive, config_group->max_keep_alive_seconds, 59, 241); PCEP_VTYSH_INT_ARG_CHECK(dead_timer_str, dead_timer, - config_group->dead_timer_seconds, 0, 241); + config_group->dead_timer_seconds, 0, 961); PCEP_VTYSH_INT_ARG_CHECK(min_peer_dead_timer_str, min_peer_dead_timer, config_group->min_dead_timer_seconds, 3, 61); PCEP_VTYSH_INT_ARG_CHECK(max_peer_dead_timer_str, max_peer_dead_timer, - config_group->max_dead_timer_seconds, 59, 481); + config_group->max_dead_timer_seconds, 59, 961); PCEP_VTYSH_INT_ARG_CHECK(pcep_request_str, pcep_request, config_group->pcep_request_time_seconds, 0, 121); @@ -909,7 +910,8 @@ static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name, struct pce_opts *pce_opts = &pce_opts_cli->pce_opts; /* Check if the pcc-peer is duplicated */ - if (pcep_ctrl_pcc_has_pce(pcep_g->fpt, peer_name)) { + if (pcep_pcc_pcc_has_pce(pcep_ctrl_get_state_by_fpt(pcep_g->fpt), + peer_name)) { vty_out(vty, "%% The peer [%s] has already been configured.\n", peer_name); return CMD_WARNING; @@ -952,7 +954,8 @@ static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty, long precedence) { /* Check if the pcc-peer is connected to the PCC */ - if (!pcep_ctrl_pcc_has_pce(pcep_g->fpt, peer_name)) { + if (!pcep_pcc_pcc_has_pce(pcep_ctrl_get_state_by_fpt(pcep_g->fpt), + peer_name)) { vty_out(vty, "%% The peer [%s] is not connected to the PCC.\n", peer_name); return CMD_WARNING; @@ -1132,7 +1135,8 @@ static int path_pcep_cli_show_pcep_session(struct vty *vty, return CMD_WARNING; } - pcc_state = pcep_ctrl_get_pcc_state(pcep_g->fpt, pcc_peer); + pcc_state = pcep_pcc_get_pcc_by_name( + pcep_ctrl_get_state_by_fpt(pcep_g->fpt), pcc_peer); if (pcc_state == NULL) { vty_out(vty, "%% PCC is not connected to PCE [%s]\n", pcc_peer); @@ -1152,8 +1156,9 @@ static int path_pcep_cli_show_pcep_session(struct vty *vty, continue; } - pcc_state = pcep_ctrl_get_pcc_state( - pcep_g->fpt, pce_opts_cli->pce_opts.pce_name); + pcc_state = pcep_pcc_get_pcc_by_name( + pcep_ctrl_get_state_by_fpt(pcep_g->fpt), + pce_opts_cli->pce_opts.pce_name); if (pcc_state == NULL) { continue; } @@ -1253,8 +1258,9 @@ int pcep_cli_pcc_config_write(struct vty *vty) } /* Only show the PCEs configured in the pcc sub-command */ - if (!pcep_ctrl_pcc_has_pce(pcep_g->fpt, - pce_opts_cli->pce_opts.pce_name)) { + if (!pcep_pcc_pcc_has_pce( + pcep_ctrl_get_state_by_fpt(pcep_g->fpt), + pce_opts_cli->pce_opts.pce_name)) { continue; } diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index 945b169f208e..cdb579c5fcea 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -94,8 +94,6 @@ static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res); static int pcep_thread_finish_event_handler(struct thread *thread); static int pcep_thread_get_counters_callback(struct thread *t); static int pcep_thread_send_report_callback(struct thread *t); -static int pcep_thread_update_best_pce(struct ctrl_state *ctrl_state, - int pcc_id); /* Controller Thread Timer Handler */ static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, @@ -108,7 +106,6 @@ static int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, struct thread **thread, pcep_ctrl_thread_callback timer_cb); static int pcep_thread_timer_handler(struct thread *thread); -static int pcep_thread_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id); /* Controller Thread Socket read/write Handler */ static int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id, @@ -152,22 +149,11 @@ static int pcep_main_event_handler(struct thread *thread); static void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state); static struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt); -static struct pcc_state *get_pcc_state(struct ctrl_state *ctrl_state, - int pcc_id); -static int set_pcc_state(struct ctrl_state *ctrl_state, - struct pcc_state *pcc_state); -static void remove_pcc_state(struct ctrl_state *ctrl_state, - struct pcc_state *pcc_state); +int get_next_id(struct ctrl_state *ctrl_state); +int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state); +void remove_pcc_state(struct ctrl_state *ctrl_state, + struct pcc_state *pcc_state); static uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t attempt); -static int calculate_best_pce(struct ctrl_state *ctrl_state); -static int get_next_id(struct ctrl_state *ctrl_state); -static int get_previous_best_pce(struct ctrl_state *ctrl_state); -static int get_pcc_id_by_ip_port(struct ctrl_state *ctrl_state, - struct pce_opts *pce_opts); -static int get_pcc_idx_by_id(struct ctrl_state *ctrl_state, int id); -static int get_pcc_id_by_idx(struct ctrl_state *ctrl_state, int idx); -static struct pcc_state *get_pcc_by_id(struct ctrl_state *ctrl_state, int id); -static int get_free_pcc_idx(struct ctrl_state *ctrl_state); /* ------------ API Functions Called from Main Thread ------------ */ @@ -201,7 +187,7 @@ int pcep_ctrl_initialize(struct thread_master *main_thread, } frr_pthread_wait_running(*fpt); - /* Initialise the thread state */ + /* Initialize the thread state */ ctrl_state = XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state)); ctrl_state->main = main_thread; ctrl_state->self = (*fpt)->master; @@ -284,41 +270,6 @@ struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, return args.counters; } -struct pcc_state *pcep_ctrl_get_pcc_state(struct frr_pthread *fpt, - const char *pce_name) -{ - struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - for (int i = 0; i < MAX_PCE; i++) { - if (ctrl_state->pcc[i] == NULL) { - continue; - } - - if (strcmp(ctrl_state->pcc[i]->pce_opts->pce_name, pce_name) - == 0) { - return ctrl_state->pcc[i]; - } - } - - return NULL; -} - -bool pcep_ctrl_pcc_has_pce(struct frr_pthread *fpt, const char *pce_name) -{ - struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - for (int i = 0; i < MAX_PCC; i++) { - if (ctrl_state->pcc[i] == NULL) { - continue; - } - - if (strcmp(ctrl_state->pcc[i]->pce_opts->pce_name, pce_name) - == 0) { - return true; - } - } - - return false; -} - void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, struct path *path) { @@ -330,6 +281,16 @@ void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, &args, 0); } +struct pcc_state **pcep_ctrl_get_state_by_fpt(struct frr_pthread *fpt) +{ + struct ctrl_state *ctrl_state = get_ctrl_state(fpt); + if (ctrl_state == NULL) { + return NULL; + } + + return ctrl_state->pcc; +} + /* ------------ Internal Functions Called from Main Thread ------------ */ int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res) @@ -437,10 +398,9 @@ int pcep_thread_get_counters_callback(struct thread *t) assert(ctrl_state != NULL); struct pcc_state *pcc_state; - pcc_state = get_pcc_state(ctrl_state, args->pcc_id); - if (pcc_state) { - args->counters = - pcep_lib_copy_counters(pcc_state->sess); + pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id); + if (pcc_state) { + args->counters = pcep_lib_copy_counters(pcc_state->sess); } return 0; @@ -465,7 +425,8 @@ int pcep_thread_send_report_callback(struct thread *t) } } } else { - pcc_state = get_pcc_state(ctrl_state, args->pcc_id); + pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id); pcep_pcc_send_report(ctrl_state, pcc_state, args->path); } @@ -505,20 +466,6 @@ int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, pcep_thread_timer_handler); } -int pcep_thread_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id) -{ - int ret=0; - // resync whatever were new best - int best_id = calculate_best_pce(ctrl_state); - if (best_id) { - struct pcc_state *pcc_state = - get_pcc_state(ctrl_state, best_id); - ret = pcep_thread_update_best_pce(ctrl_state, pcc_state->id); - } - - return ret; -} - int pcep_thread_timer_handler(struct thread *thread) { /* data unpacking */ @@ -532,18 +479,21 @@ int pcep_thread_timer_handler(struct thread *thread) int ret = 0; struct pcc_state *pcc_state = NULL; - pcc_state = get_pcc_state(ctrl_state, pcc_id); + pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); if (!pcc_state) { return ret; } switch (type) { case TM_RECONNECT_PCC: - pcc_state = get_pcc_state(ctrl_state, pcc_id); if (pcc_state) pcep_pcc_reconnect(ctrl_state, pcc_state); break; - case TM_CALCULATE_BEST_PCE://Previous best disconnect so new best should be synced - ret = pcep_thread_timer_update_best_pce(ctrl_state, pcc_id); + case TM_CALCULATE_BEST_PCE: + /* Previous best disconnect so new best should be synced */ + if (!ctrl_state->pcc_count) { + ret = pcep_pcc_timer_update_best_pce(ctrl_state, + pcc_id); + } break; default: flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, @@ -686,9 +636,6 @@ int pcep_thread_event_handler(struct thread *thread) struct pcc_opts *pcc_opts = NULL; struct pce_opts *pce_opts = NULL; - int previous_best_pcc_id = -1; - int new_best_pcc_id = -1; - switch (type) { case EV_UPDATE_PCC_OPTS: assert(payload != NULL); @@ -705,10 +652,9 @@ int pcep_thread_event_handler(struct thread *thread) case EV_REMOVE_PCC: pce_opts = (struct pce_opts *)payload; ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts); - new_best_pcc_id = calculate_best_pce(ctrl_state); - if (new_best_pcc_id) { - ret = pcep_thread_update_best_pce( - ctrl_state, new_best_pcc_id); + if (ret == 0) { + ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state, + ctrl_state->pcc); } break; case EV_PATHD_EVENT: @@ -721,16 +667,9 @@ int pcep_thread_event_handler(struct thread *thread) case EV_SYNC_PATH: assert(payload != NULL); path = (struct path *)payload; - if (pcc_id == calculate_best_pce(ctrl_state)) { - previous_best_pcc_id = - get_previous_best_pce(ctrl_state); - if (previous_best_pcc_id - != 0) { //while adding new pce, path have to resync the previous best - pcep_thread_update_best_pce(ctrl_state, - previous_best_pcc_id); - } - } - ret = pcep_thread_event_sync_path(ctrl_state, pcc_id, path); + pcep_pcc_multi_pce_sync_path(ctrl_state, pcc_id, + ctrl_state->pcc); + pcep_thread_event_sync_path(ctrl_state, pcc_id, path); break; case EV_SYNC_DONE: ret = pcep_thread_event_sync_done(ctrl_state, pcc_id); @@ -756,29 +695,6 @@ int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, return 0; } -int pcep_thread_update_best_pce(struct ctrl_state *ctrl_state, int best) -{ - PCEP_DEBUG(" recalculating pce precedence "); - if (best) { - struct pcc_state *best_pcc_state = - get_pcc_state(ctrl_state, best); - if (best_pcc_state->previous_best != best_pcc_state->is_best) { - PCEP_DEBUG(" %s Resynchro best (%i) previous best (%i)", - best_pcc_state->tag, best_pcc_state->id, - best_pcc_state->previous_best); - pcep_pcc_start_sync(ctrl_state, best_pcc_state); - } else { - PCEP_DEBUG( - " %s No Resynchro best (%i) previous best (%i)", - best_pcc_state->tag, best_pcc_state->id, - best_pcc_state->previous_best); - } - } else { - PCEP_DEBUG(" None best pce , all pce seem disconnected"); - } - return 0; -} - int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, int pcc_id, struct pce_opts *pce_opts) { @@ -788,9 +704,11 @@ int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state; struct pcc_opts *pcc_opts; - int current_pcc_id = get_pcc_id_by_ip_port(ctrl_state, pce_opts); + int current_pcc_id = + pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, pce_opts); if (current_pcc_id) { - pcc_state = get_pcc_state(ctrl_state, current_pcc_id); + pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, current_pcc_id); } else { pcc_state = pcep_pcc_initialize(ctrl_state, get_next_id(ctrl_state)); @@ -809,7 +727,8 @@ int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, "failed to update PCC configuration"); } - calculate_best_pce(ctrl_state); + pcep_pcc_calculate_best_pce(ctrl_state->pcc); + return 0; } @@ -817,7 +736,8 @@ int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state, int pcc_id) { if (pcc_id) { - struct pcc_state *pcc_state = get_pcc_state(ctrl_state, pcc_id); + struct pcc_state *pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); if (pcc_state) { remove_pcc_state(ctrl_state, pcc_state); pcep_pcc_finalize(ctrl_state, pcc_state); @@ -832,7 +752,8 @@ int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state) for (int i = 0; i < MAX_PCC; i++) { pcep_thread_event_remove_pcc_by_id( - ctrl_state, get_pcc_id_by_idx(ctrl_state, i)); + ctrl_state, + pcep_pcc_get_pcc_id_by_idx(ctrl_state->pcc, i)); } return 0; } @@ -843,7 +764,8 @@ int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, assert(ctrl_state != NULL); if (pce_opts) { - int pcc_id = get_pcc_id_by_ip_port(ctrl_state, pce_opts); + int pcc_id = pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, + pce_opts); if (pcc_id) { pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id); } else { @@ -860,7 +782,8 @@ int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id, struct path *path) { - struct pcc_state *pcc_state = get_pcc_state(ctrl_state, pcc_id); + struct pcc_state *pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); pcep_pcc_sync_path(ctrl_state, pcc_state, path); pcep_free_path(path); return 0; @@ -868,7 +791,8 @@ int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id, int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, int pcc_id) { - struct pcc_state *pcc_state = get_pcc_state(ctrl_state, pcc_id); + struct pcc_state *pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); pcep_pcc_sync_done(ctrl_state, pcc_state); return 0; } @@ -927,156 +851,6 @@ int pcep_main_event_handler(struct thread *thread) /* ------------ Helper functions ------------ */ -int get_next_id(struct ctrl_state *ctrl_state) -{ - return ++ctrl_state->pcc_last_id; -} - -int get_previous_best_pce(struct ctrl_state *ctrl_state) -{ - if (!ctrl_state || !ctrl_state->pcc_count) - return 0; - - int previous_best_pce = -1; - struct pcc_state **pcc = &ctrl_state->pcc[0]; - for (int i = 0; i < MAX_PCC; i++) { - if (pcc[i] && pcc[i]->pce_opts && pcc[i]->previous_best == true - && pcc[i]->status != PCEP_PCC_DISCONNECTED) { - previous_best_pce = i; - break; - } - } - return previous_best_pce != -1 ? pcc[previous_best_pce]->id : 0; -} - -int calculate_best_pce(struct ctrl_state *ctrl_state) -{ - int best_precedence = 255; // DEFAULT_PCE_PRECEDENCE; - int best_pce = -1; - int one_connected_pce = -1; - int previous_best_pce = -1; - int step_0_best = -1; - int step_0_previous = -1; - - if (!ctrl_state || !ctrl_state->pcc_count) - return 0; - - struct pcc_state **pcc = &ctrl_state->pcc[0]; - - // Get state - for (int i = 0; i < MAX_PCC; i++) { - if (pcc[i] && pcc[i]->pce_opts) { - if (pcc[i]->is_best == true) { - step_0_best = i; - } - if (pcc[i]->previous_best == true) { - step_0_previous = i; - } - } - } - for (int i = 0; i < MAX_PCC; i++) { - if (pcc[i] && pcc[i]->pce_opts) { - zlog_debug( - "calculate all : i (%i) is_best (%i) previous_best (%i) ", - i, pcc[i]->is_best, pcc[i]->previous_best); - } - } - - // Calculate best - for (int i = 0; i < MAX_PCC; i++) { - if (pcc[i] && pcc[i]->pce_opts - && pcc[i]->status != PCEP_PCC_DISCONNECTED) { - one_connected_pce = i; // In case none better - if (pcc[i]->pce_opts->precedence <= best_precedence) { - if (best_pce != -1 - && pcc[best_pce]->pce_opts->precedence - == pcc[i]->pce_opts->precedence - && ipaddr_cmp( - &pcc[i]->pce_opts->addr, - &pcc[best_pce]->pce_opts->addr) - > 0) { - // collide of precedences so compare ip - best_pce = i; - } else { - if (!pcc[i]->previous_best) { - best_precedence = - pcc[i]->pce_opts - ->precedence; - best_pce = i; - } - } - } - } - } - - zlog_debug("calculate data : sb (%i) sp (%i) oc (%i) b (%i) ", - step_0_best, step_0_previous, one_connected_pce, best_pce); - - // Changed of state so ... - if (step_0_best != best_pce) { - // Calculate previous - previous_best_pce = step_0_best; - // Clean state - if (step_0_best != -1) { - pcc[step_0_best]->is_best = false; - } - if (step_0_previous != -1) { - pcc[step_0_previous]->previous_best = false; - } - - // Set previous - if (previous_best_pce != -1) { - pcc[previous_best_pce]->previous_best = true; - zlog_debug("previous best pce (%i) ", - previous_best_pce + 1); - } - - - // Set best - if (best_pce != -1) { - pcc[best_pce]->is_best = true; - zlog_debug("best pce (%i) ", best_pce + 1); - } else { - if (one_connected_pce != -1) { - best_pce = one_connected_pce; - pcc[one_connected_pce]->is_best = true; - zlog_debug( - "one connected best pce (default) (%i) ", - one_connected_pce + 1); - } else { - for (int i = 0; i < MAX_PCC; i++) { - if (pcc[i] && pcc[i]->pce_opts) { - best_pce = i; - pcc[i]->is_best = true; - zlog_debug( - "(disconnected) best pce (default) (%i) ", - i + 1); - break; - } - } - } - } - } - - - return best_pce == -1 ? 0 : pcc[best_pce]->id; -} - -int get_free_pcc_idx(struct ctrl_state *ctrl_state) -{ - assert(ctrl_state != NULL); - - struct pcc_state **pcc_state = &ctrl_state->pcc[0]; - for (int idx = 0; idx < MAX_PCC; idx++) { - if (pcc_state[idx] == NULL) { - zlog_debug("new pcc_idx (%d)", idx); - return idx; - } - } - - return -1; -} - void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state) { assert(fpt != NULL); @@ -1094,74 +868,9 @@ struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt) return ctrl_state; } -int get_pcc_id_by_ip_port(struct ctrl_state *ctrl_state, - struct pce_opts *pce_opts) -{ - for (int idx = 0; idx < MAX_PCC; idx++) { - if (ctrl_state->pcc[idx]) { - if ((ipaddr_cmp((const struct ipaddr *)&ctrl_state - ->pcc[idx] - ->pce_opts->addr, - (const struct ipaddr *)&pce_opts->addr) - == 0) - && ctrl_state->pcc[idx]->pce_opts->port - == pce_opts->port) { - zlog_debug("found pcc_id (%d) idx (%d)", - ctrl_state->pcc[idx]->id, idx); - return ctrl_state->pcc[idx]->id; - } - } - } - return 0; -} - -int get_pcc_id_by_idx(struct ctrl_state *ctrl_state, int idx) -{ - if (idx>=0) { - return ctrl_state->pcc[idx]?ctrl_state->pcc[idx]->id:0; - } else { - return 0; - } -} - -struct pcc_state *get_pcc_by_id(struct ctrl_state *ctrl_state, int id) -{ - for (int i = 0; i < MAX_PCC; i++) { - if (ctrl_state->pcc[i]) { - if (ctrl_state->pcc[i]->id == id) { - zlog_debug("found id (%d) pcc_idx (%d)", - ctrl_state->pcc[i]->id, i); - return ctrl_state->pcc[i]; - } - } - } - return NULL; -} - -int get_pcc_idx_by_id(struct ctrl_state *ctrl_state, int id) -{ - for (int idx = 0; idx < MAX_PCC; idx++) { - if (ctrl_state->pcc[idx]) { - if (ctrl_state->pcc[idx]->id == id) { - zlog_debug("found pcc_id (%d) array_idx (%d)", - ctrl_state->pcc[idx]->id, idx); - return idx; - } - } - } - return -1; -} - -struct pcc_state *get_pcc_state(struct ctrl_state *ctrl_state, int id) +int get_next_id(struct ctrl_state *ctrl_state) { - assert(ctrl_state != NULL); - struct pcc_state *pcc_state; - - if (!id) - return NULL; - - pcc_state = get_pcc_by_id(ctrl_state, id); - return pcc_state; + return ++ctrl_state->pcc_last_id; } int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) @@ -1169,7 +878,7 @@ int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) assert(ctrl_state != NULL); assert(pcc_state->id != 0); - int current_pcc_idx = get_free_pcc_idx(ctrl_state); + int current_pcc_idx = pcep_pcc_get_free_pcc_idx(ctrl_state->pcc); if (current_pcc_idx >= 0) { ctrl_state->pcc[current_pcc_idx] = pcc_state; ctrl_state->pcc_count++; @@ -1189,7 +898,7 @@ void remove_pcc_state(struct ctrl_state *ctrl_state, assert(pcc_state->id != 0); int idx = 0; - idx = get_pcc_idx_by_id(ctrl_state, pcc_state->id); + idx = pcep_pcc_get_pcc_idx_by_id(ctrl_state->pcc, pcc_state->id); if (idx != -1) { ctrl_state->pcc[idx] = NULL; ctrl_state->pcc_count--; diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h index 46ea6b9c4d3c..a6b7184e3bcb 100644 --- a/pathd/path_pcep_controller.h +++ b/pathd/path_pcep_controller.h @@ -95,9 +95,7 @@ int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path); int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id); struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, int pcc_id); -bool pcep_ctrl_pcc_has_pce(struct frr_pthread *fpt, const char *pce_name); -struct pcc_state *pcep_ctrl_get_pcc_state(struct frr_pthread *fpt, - const char *pce_name); +struct pcc_state **pcep_ctrl_get_state_by_fpt(struct frr_pthread *fpt); /* Synchronously send a report, the caller is responsible to free the path, * If `pcc_id` is `0` the report is sent by all PCCs */ void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index f444368acbb4..fe9d33b8be33 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -98,6 +98,8 @@ static void set_pcc_address(struct pcc_state *pcc_state, struct lsp_nb_key *nbkey, struct ipaddr *addr); static int compare_pcc_opts(struct pcc_opts *lhs, struct pcc_opts *rhs); static int compare_pce_opts(struct pce_opts *lhs, struct pce_opts *rhs); +static int get_previous_best_pce(struct pcc_state **pcc); +static bool update_best_pce(struct pcc_state **pcc, int best); /* Data Structure Helper Functions */ static void lookup_plspid(struct pcc_state *pcc_state, struct path *path); @@ -481,10 +483,6 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, } } -void pcep_pcc_start_sync(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) -{ - pcep_thread_start_sync(ctrl_state, pcc_state->id); -} /* ------------ Pathd event handler ------------ */ void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state, @@ -590,6 +588,330 @@ void pcep_pcc_pcep_event_handler(struct ctrl_state *ctrl_state, } } + +/*------------------ Multi-PCE --------------------- */ + +/* Internal util function, returns true if sync is necessary, false otherwise */ +bool update_best_pce(struct pcc_state **pcc, int best) +{ + PCEP_DEBUG(" recalculating pce precedence "); + if (best) { + struct pcc_state *best_pcc_state = + pcep_pcc_get_pcc_by_id(pcc, best); + if (best_pcc_state->previous_best != best_pcc_state->is_best) { + PCEP_DEBUG(" %s Resynch best (%i) previous best (%i)", + best_pcc_state->tag, best_pcc_state->id, + best_pcc_state->previous_best); + return true; + } else { + PCEP_DEBUG( + " %s No Resynch best (%i) previous best (%i)", + best_pcc_state->tag, best_pcc_state->id, + best_pcc_state->previous_best); + } + } else { + PCEP_DEBUG(" No best pce available, all pce seem disconnected"); + } + + return false; +} + +int get_previous_best_pce(struct pcc_state **pcc) +{ + int previous_best_pce = -1; + + for (int i = 0; i < MAX_PCC; i++) { + if (pcc[i] && pcc[i]->pce_opts && pcc[i]->previous_best == true + && pcc[i]->status != PCEP_PCC_DISCONNECTED) { + previous_best_pce = i; + break; + } + } + return previous_best_pce != -1 ? pcc[previous_best_pce]->id : 0; +} + +/* Called by path_pcep_controller EV_REMOVE_PCC + * Event handler when a PCC is removed. */ +int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state, + struct pcc_state **pcc) +{ + int new_best_pcc_id = -1; + new_best_pcc_id = pcep_pcc_calculate_best_pce(pcc); + if (new_best_pcc_id) { + if (update_best_pce(ctrl_state->pcc, new_best_pcc_id) == true) { + pcep_thread_start_sync(ctrl_state, new_best_pcc_id); + } + } + + return 0; +} + +/* Called by path_pcep_controller EV_SYNC_PATH + * Event handler when a path is sync'd. */ +int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id, + struct pcc_state **pcc) +{ + int previous_best_pcc_id = -1; + + if (pcc_id == pcep_pcc_calculate_best_pce(pcc)) { + previous_best_pcc_id = get_previous_best_pce(pcc); + if (previous_best_pcc_id != 0) { + /* while adding new pce, path has to resync to the + * previous best. pcep_thread_start_sync() will be + * called by the calling function */ + if (update_best_pce(ctrl_state->pcc, + previous_best_pcc_id) + == true) { + pcep_thread_start_sync(ctrl_state, + previous_best_pcc_id); + } + } + } + + return 0; +} + +/* Called by path_pcep_controller when the TM_CALCULATE_BEST_PCE + * timer expires */ +int pcep_pcc_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id) +{ + int ret = 0; + /* resync whatever was the new best */ + int best_id = pcep_pcc_calculate_best_pce(ctrl_state->pcc); + if (best_id) { + struct pcc_state *pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, best_id); + ret = update_best_pce(ctrl_state->pcc, pcc_state->id); + } + + return ret; +} + +/* Called by path_pcep_controller::pcep_thread_event_update_pce_options() + * Returns the best PCE id */ +int pcep_pcc_calculate_best_pce(struct pcc_state **pcc) +{ + int best_precedence = 255; // DEFAULT_PCE_PRECEDENCE; + int best_pce = -1; + int one_connected_pce = -1; + int previous_best_pce = -1; + int step_0_best = -1; + int step_0_previous = -1; + int pcc_count = 0; + + // Get state + for (int i = 0; i < MAX_PCC; i++) { + if (pcc[i] && pcc[i]->pce_opts) { + zlog_debug( + "multi-pce: calculate all : i (%i) is_best (%i) previous_best (%i) ", + i, pcc[i]->is_best, pcc[i]->previous_best); + pcc_count++; + + if (pcc[i]->is_best == true) { + step_0_best = i; + } + if (pcc[i]->previous_best == true) { + step_0_previous = i; + } + } + } + + if (!pcc_count) { + return 0; + } + + // Calculate best + for (int i = 0; i < MAX_PCC; i++) { + if (pcc[i] && pcc[i]->pce_opts + && pcc[i]->status != PCEP_PCC_DISCONNECTED) { + one_connected_pce = i; // In case none better + if (pcc[i]->pce_opts->precedence <= best_precedence) { + if (best_pce != -1 + && pcc[best_pce]->pce_opts->precedence + == pcc[i]->pce_opts->precedence + && ipaddr_cmp( + &pcc[i]->pce_opts->addr, + &pcc[best_pce]->pce_opts->addr) + > 0) { + // collide of precedences so compare ip + best_pce = i; + } else { + if (!pcc[i]->previous_best) { + best_precedence = + pcc[i]->pce_opts + ->precedence; + best_pce = i; + } + } + } + } + } + + zlog_debug( + "multi-pce: calculate data : sb (%i) sp (%i) oc (%i) b (%i) ", + step_0_best, step_0_previous, one_connected_pce, best_pce); + + // Changed of state so ... + if (step_0_best != best_pce) { + // Calculate previous + previous_best_pce = step_0_best; + // Clean state + if (step_0_best != -1) { + pcc[step_0_best]->is_best = false; + } + if (step_0_previous != -1) { + pcc[step_0_previous]->previous_best = false; + } + + // Set previous + if (previous_best_pce != -1) { + pcc[previous_best_pce]->previous_best = true; + zlog_debug("multi-pce: previous best pce (%i) ", + previous_best_pce + 1); + } + + + // Set best + if (best_pce != -1) { + pcc[best_pce]->is_best = true; + zlog_debug("multi-pce: best pce (%i) ", best_pce + 1); + } else { + if (one_connected_pce != -1) { + best_pce = one_connected_pce; + pcc[one_connected_pce]->is_best = true; + zlog_debug( + "multi-pce: one connected best pce (default) (%i) ", + one_connected_pce + 1); + } else { + for (int i = 0; i < MAX_PCC; i++) { + if (pcc[i] && pcc[i]->pce_opts) { + best_pce = i; + pcc[i]->is_best = true; + zlog_debug( + "(disconnected) best pce (default) (%i) ", + i + 1); + break; + } + } + } + } + } + + return ((best_pce == -1) ? 0 : pcc[best_pce]->id); +} + +int pcep_pcc_get_pcc_id_by_ip_port(struct pcc_state **pcc, + struct pce_opts *pce_opts) +{ + if (pcc == NULL) { + return 0; + } + + for (int idx = 0; idx < MAX_PCC; idx++) { + if (pcc[idx]) { + if ((ipaddr_cmp((const struct ipaddr *)&pcc[idx] + ->pce_opts->addr, + (const struct ipaddr *)&pce_opts->addr) + == 0) + && pcc[idx]->pce_opts->port == pce_opts->port) { + zlog_debug("found pcc_id (%d) idx (%d)", + pcc[idx]->id, idx); + return pcc[idx]->id; + } + } + } + return 0; +} + +int pcep_pcc_get_pcc_id_by_idx(struct pcc_state **pcc, int idx) +{ + if (pcc == NULL || idx < 0) { + return 0; + } + + return pcc[idx] ? pcc[idx]->id : 0; +} + +struct pcc_state *pcep_pcc_get_pcc_by_id(struct pcc_state **pcc, int id) +{ + if (pcc == NULL || id < 0) { + return NULL; + } + + for (int i = 0; i < MAX_PCC; i++) { + if (pcc[i]) { + if (pcc[i]->id == id) { + zlog_debug("found id (%d) pcc_idx (%d)", + pcc[i]->id, i); + return pcc[i]; + } + } + } + + return NULL; +} + +struct pcc_state *pcep_pcc_get_pcc_by_name(struct pcc_state **pcc, + const char *pce_name) +{ + if (pcc == NULL || pce_name == NULL) { + return NULL; + } + + for (int i = 0; i < MAX_PCE; i++) { + if (pcc[i] == NULL) { + continue; + } + + if (strcmp(pcc[i]->pce_opts->pce_name, pce_name) == 0) { + return pcc[i]; + } + } + + return NULL; +} + +int pcep_pcc_get_pcc_idx_by_id(struct pcc_state **pcc, int id) +{ + if (pcc == NULL) { + return -1; + } + + for (int idx = 0; idx < MAX_PCC; idx++) { + if (pcc[idx]) { + if (pcc[idx]->id == id) { + zlog_debug("found pcc_id (%d) array_idx (%d)", + pcc[idx]->id, idx); + return idx; + } + } + } + + return -1; +} + +int pcep_pcc_get_free_pcc_idx(struct pcc_state **pcc) +{ + assert(pcc != NULL); + + for (int idx = 0; idx < MAX_PCC; idx++) { + if (pcc[idx] == NULL) { + zlog_debug("new pcc_idx (%d)", idx); + return idx; + } + } + + return -1; +} + +bool pcep_pcc_pcc_has_pce(struct pcc_state **pcc, const char *pce_name) +{ + return (pcep_pcc_get_pcc_by_name(pcc, pce_name) != NULL); +} + + +/*------------------ PCEP Message handlers --------------------- */ + void handle_pcep_open(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg) { diff --git a/pathd/path_pcep_pcc.h b/pathd/path_pcep_pcc.h index 99f5204c577a..709e01797749 100644 --- a/pathd/path_pcep_pcc.h +++ b/pathd/path_pcep_pcc.h @@ -114,8 +114,20 @@ void pcep_pcc_sync_done(struct ctrl_state *ctrl_state, void pcep_pcc_send_report(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct path *path); -void pcep_pcc_start_sync(struct ctrl_state *ctrl_state, - struct pcc_state *pcc_state); - +int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id, + struct pcc_state **pcc_state_list); +int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state, + struct pcc_state **pcc_state_list); +int pcep_pcc_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id); +int pcep_pcc_calculate_best_pce(struct pcc_state **pcc); +int pcep_pcc_get_pcc_id_by_ip_port(struct pcc_state **pcc, + struct pce_opts *pce_opts); +int pcep_pcc_get_pcc_id_by_idx(struct pcc_state **pcc, int idx); +struct pcc_state *pcep_pcc_get_pcc_by_id(struct pcc_state **pcc, int id); +struct pcc_state *pcep_pcc_get_pcc_by_name(struct pcc_state **pcc, + const char *pce_name); +int pcep_pcc_get_pcc_idx_by_id(struct pcc_state **pcc, int id); +int pcep_pcc_get_free_pcc_idx(struct pcc_state **pcc); +bool pcep_pcc_pcc_has_pce(struct pcc_state **pcc, const char *pce_name); #endif // _PATH_PCEP_PCC_H_