diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c index 64d77158c6e0..dc8f3414a1d6 100644 --- a/pathd/path_pcep.c +++ b/pathd/path_pcep.c @@ -407,20 +407,12 @@ DEFUN_NOSH( DEFUN(pcep_cli_no_pcc, pcep_cli_no_pcc_cmd, "no pcc", NO_STR "PCC configuration\n") { - pcep_ctrl_remove_pcc(pcep_g->fpt, 1); - if (pcep_g->pce_opts[0] != NULL) { - XFREE(MTYPE_PCEP, pcep_g->pce_opts[0]); - pcep_g->pce_opts[0] = NULL; - } - if (pcep_g->pcc_opts != NULL) { - XFREE(MTYPE_PCEP, pcep_g->pcc_opts); - pcep_g->pcc_opts = NULL; - } + pcep_ctrl_remove_pcc(pcep_g->fpt, NULL); return CMD_SUCCESS; } DEFUN(pcep_cli_pce, pcep_cli_pce_cmd, - "pce [port (1024-65535)] [sr-draft07]", + "pce [port (1024-65535)] [sr-draft07] [precedence (0-255)]", "PCE configuration\n" "PCE IPv4 address\n" "Remote PCE server IPv4 address\n" @@ -428,14 +420,17 @@ DEFUN(pcep_cli_pce, pcep_cli_pce_cmd, "Remote PCE server IPv6 address\n" "Remote PCE server port\n" "Remote PCE server port value\n" - "Use the draft 07 of PCEP segemnt routing\n") + "Use the draft 07 of PCEP segment routing\n" + "Priority when multiple pce, the lower the more precedence\n" + "Priority value , (default 255)\n") { /* TODO: Add support for multiple PCE */ struct ipaddr pce_addr; uint32_t pce_port = PCEP_DEFAULT_PORT; - struct pce_opts *pce_opts, *pce_opts_copy; + struct pce_opts *pce_opts; bool draft07 = false; + uint8_t pce_precedence = PCE_DEFAULT_PRECEDENCE; int i = 1; /* Get the first argument, should be either ip or ipv6 */ @@ -479,6 +474,14 @@ DEFUN(pcep_cli_pce, pcep_cli_pce_cmd, i++; continue; } + if (strcmp("precedence", argv[i]->arg) == 0) { + i++; + if (i >= argc) + return CMD_ERR_NO_MATCH; + pce_precedence = atoi(argv[i]->arg); + i++; + continue; + } return CMD_ERR_NO_MATCH; } @@ -486,15 +489,13 @@ DEFUN(pcep_cli_pce, pcep_cli_pce_cmd, IPADDR_COPY(&pce_opts->addr, &pce_addr); pce_opts->port = pce_port; pce_opts->draft07 = draft07; + pce_opts->precedence = pce_precedence; - if (pcep_ctrl_update_pce_options(pcep_g->fpt, 1, pce_opts)) +#define NO_USE 0 + if (pcep_ctrl_update_pce_options(pcep_g->fpt, NO_USE /*current_pcc_id*/, + pce_opts)) return CMD_WARNING; - if (pcep_g->pce_opts[0] != NULL) - XFREE(MTYPE_PCEP, pcep_g->pce_opts[0]); - pce_opts_copy = XCALLOC(MTYPE_PCEP, sizeof(*pce_opts)); - pce_opts_copy = memcpy(pce_opts_copy, pce_opts, sizeof(*pce_opts)); - pcep_g->pce_opts[0] = pce_opts_copy; return CMD_SUCCESS; } @@ -511,12 +512,34 @@ DEFUN(pcep_cli_no_pce, pcep_cli_no_pce_cmd, "Remote PCE server port value\n") { /* TODO: Add support for multiple PCE */ + int i = 2; + static struct ipaddr pce_addr; + pce_addr.ipa_type = IPADDR_V4; + SET_IPADDR_V4(&pce_addr); + if (strcmp("ipv6", argv[i]->arg) == 0) { + SET_IPADDR_V6(&pce_addr); + } else if (strcmp("ip", argv[i]->arg) != 0) { + return CMD_ERR_NO_MATCH; + } - pcep_ctrl_remove_pcc(pcep_g->fpt, 1); - if (pcep_g->pce_opts[0] != NULL) { - XFREE(MTYPE_PCEP, pcep_g->pce_opts[0]); - pcep_g->pce_opts[0] = NULL; + /* Get the first argument value */ + i++; + if (i >= argc) { + return CMD_ERR_NO_MATCH; } + if (IS_IPADDR_V6(&pce_addr)) { + if (!inet_pton(AF_INET6, argv[i]->arg, &pce_addr.ipaddr_v6)) { + return CMD_ERR_INCOMPLETE; + } + } else { + if (!inet_pton(AF_INET, argv[i]->arg, &pce_addr.ipaddr_v4)) { + return CMD_ERR_INCOMPLETE; + } + } + + + pcep_ctrl_remove_pcc(pcep_g->fpt, &pce_addr /*current_pcc_id*/); + return CMD_SUCCESS; } @@ -625,6 +648,12 @@ int pcep_cli_pcc_config_write(struct vty *vty) csnprintfrr(buff, sizeof(buff), " sr-draft07"); } + if (pce_opts->precedence + != PCE_DEFAULT_PRECEDENCE) { + csnprintfrr(buff, sizeof(buff), + " precedence %d", + pce_opts->precedence); + } if (IS_IPADDR_V6(&pce_opts->addr)) { vty_out(vty, " pce ipv6 %pI6%s\n", &pce_opts->addr.ipaddr_v6, diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h index 7fc1e9400d44..0677671253d1 100644 --- a/pathd/path_pcep.h +++ b/pathd/path_pcep.h @@ -28,9 +28,10 @@ #include "pathd/pathd.h" #include "pathd/path_pcep_memory.h" +#define PCE_DEFAULT_PRECEDENCE 255 #define PCC_DEFAULT_MSD 4 #define PCEP_DEFAULT_PORT 4189 -#define MAX_PCC 1 +#define MAX_PCC 3 #define MAX_TAG_SIZE 50 #define PCEP_DEBUG_MODE_BASIC 0x01 #define PCEP_DEBUG_MODE_PATH 0x02 @@ -84,6 +85,9 @@ struct pce_opts { struct ipaddr addr; short port; bool draft07; + uint8_t precedence; + bool is_best; + bool previous_best; }; struct pcc_opts { diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index d8779e270613..7995f156c8df 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -45,11 +45,15 @@ _a <= _b ? _a : _b; \ }) +#define MAX_RETRIES_BEFORE_LOST_PRECEDENCE 5 + /* Event handling data structures */ enum pcep_ctrl_event_type { EV_UPDATE_PCC_OPTS = 1, EV_UPDATE_PCE_OPTS, + EV_UPDATE_BEST_PCE, + EV_UPDATE_TIMER_BEST_PCE, EV_REMOVE_PCC, EV_PATHD_EVENT, EV_SYNC_PATH, @@ -124,11 +128,16 @@ static int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id, static int pcep_thread_event_handler(struct thread *thread); static int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, struct pcc_opts *opts); +static int pcep_thread_event_update_best_pce(struct ctrl_state *ctrl_state, + int pcc_id); static int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, int pcc_id, struct pce_opts *opts); +static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state, + int pcc_id); +static int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state); static int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, - int pcc_id); + struct ipaddr *pce_addr); static int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id, struct path *path); static int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, @@ -233,11 +242,19 @@ int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, int pcc_id, struct ctrl_state *ctrl_state = get_ctrl_state(fpt); return send_to_thread(ctrl_state, pcc_id, EV_UPDATE_PCE_OPTS, 0, opts); } - -int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, int pcc_id) +int pcep_ctrl_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id) +{ + return send_to_thread(ctrl_state, pcc_id, EV_UPDATE_BEST_PCE, 0, NULL); +} +int pcep_ctrl_update_timer_best_pce(struct ctrl_state *ctrl_state, int pcc_id) +{ + return send_to_thread(ctrl_state, pcc_id, EV_UPDATE_TIMER_BEST_PCE, 0, + NULL); +} +int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct ipaddr *pce_addr) { struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - return send_to_thread(ctrl_state, pcc_id, EV_REMOVE_PCC, 0, NULL); + return send_to_thread(ctrl_state, 0, EV_REMOVE_PCC, 0, pce_addr); } int pcep_ctrl_pathd_event(struct frr_pthread *fpt, @@ -307,6 +324,15 @@ void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id, path); } +void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state, + int pcc_id, int delay, + struct thread **thread) +{ + + schedule_thread_timer(ctrl_state, pcc_id, TM_CALCULATE_BEST_PCE, delay, + NULL, thread); +} + void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id, int retry_count, struct thread **thread) { @@ -356,9 +382,11 @@ int pcep_thread_finish_event_handler(struct thread *thread) assert(ctrl_state != NULL); - for (i = 0; i < ctrl_state->pcc_count; i++) { - pcep_pcc_finalize(ctrl_state, ctrl_state->pcc[i]); - ctrl_state->pcc[i] = NULL; + for (i = 0; i < MAX_PCC; i++) { + if (ctrl_state->pcc[i]) { + pcep_pcc_finalize(ctrl_state, ctrl_state->pcc[i]); + ctrl_state->pcc[i] = NULL; + } } XFREE(MTYPE_PCEP, ctrl_state->pcc_opts); @@ -377,7 +405,7 @@ int pcep_thread_get_counters_callback(struct thread *t) assert(ctrl_state != NULL); struct pcc_state *pcc_state; - if (args->pcc_id <= ctrl_state->pcc_count) { + if (args->pcc_id <= MAX_PCC) { pcc_state = get_pcc_state(ctrl_state, args->pcc_id); args->counters = pcep_lib_copy_counters(pcc_state->sess); return 0; @@ -396,9 +424,12 @@ int pcep_thread_send_report_callback(struct thread *t) struct pcc_state *pcc_state; if (args->pcc_id == 0) { - for (int i = 0; i < ctrl_state->pcc_count; i++) { - pcep_pcc_send_report(ctrl_state, ctrl_state->pcc[i], - args->path); + for (int i = 0; i < MAX_PCC; i++) { + if (ctrl_state->pcc[i]) { + pcep_pcc_send_report(ctrl_state, + ctrl_state->pcc[i], + args->path); + } } } else { pcc_state = get_pcc_state(ctrl_state, args->pcc_id); @@ -454,13 +485,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); + assert(pcc_state != NULL); switch (type) { case TM_RECONNECT_PCC: + if (pcc_state->retry_count == 1) { + + pcep_ctrl_update_timer_best_pce(ctrl_state, 0); + } 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: + pcep_ctrl_update_best_pce(ctrl_state, pcc_id); + break; default: flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, "Unknown controller timer triggered: %u", type); @@ -479,12 +518,15 @@ int pcep_thread_pcep_event(struct thread *thread) XFREE(MTYPE_PCEP, data); int i; - for (i = 0; i < ctrl_state->pcc_count; i++) { - struct pcc_state *pcc_state = ctrl_state->pcc[i]; - if (pcc_state->sess != event->session) - continue; - pcep_pcc_pcep_event_handler(ctrl_state, pcc_state, event); - break; + for (i = 0; i < MAX_PCC; i++) { + if (ctrl_state->pcc[i]) { + struct pcc_state *pcc_state = ctrl_state->pcc[i]; + if (pcc_state->sess != event->session) + continue; + pcep_pcc_pcep_event_handler(ctrl_state, pcc_state, + event); + break; + } } destroy_pcep_event(event); @@ -598,6 +640,9 @@ int pcep_thread_event_handler(struct thread *thread) struct path *path = NULL; struct pcc_opts *pcc_opts = NULL; struct pce_opts *pce_opts = NULL; + struct ipaddr *pce_addr = NULL; + + int previous_best_pcc_id = -1; switch (type) { case EV_UPDATE_PCC_OPTS: @@ -612,8 +657,29 @@ int pcep_thread_event_handler(struct thread *thread) ret = pcep_thread_event_update_pce_options(ctrl_state, pcc_id, pce_opts); break; + case EV_UPDATE_BEST_PCE: + ret = pcep_thread_event_update_best_pce(ctrl_state, pcc_id); + break; + case EV_UPDATE_TIMER_BEST_PCE: + if (!pcc_id) { + // resync whatever were new best + pcc_id = calculate_best_pce(ctrl_state); + if (pcc_id) { + struct pcc_state *pcc_state = + get_pcc_state(ctrl_state, pcc_id); + pcep_thread_schedule_sync_best_pce( + ctrl_state, pcc_id, 30 /*delay*/, + &pcc_state->t_reconnect); + } + } else { + // resync previous best + ret = pcep_thread_event_update_best_pce(ctrl_state, + pcc_id); + } + break; case EV_REMOVE_PCC: - ret = pcep_thread_event_remove_pcc(ctrl_state, pcc_id); + pce_addr = (struct ipaddr *)payload; + ret = pcep_thread_event_remove_pcc(ctrl_state, pce_addr); break; case EV_PATHD_EVENT: assert(payload != NULL); @@ -625,6 +691,15 @@ 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 + != -1) { // Have to resync the previous best + pcep_ctrl_update_best_pce(ctrl_state, + previous_best_pcc_id); + } + } ret = pcep_thread_event_sync_path(ctrl_state, pcc_id, path); break; case EV_SYNC_DONE: @@ -650,18 +725,62 @@ int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, ctrl_state->pcc_opts = opts; return 0; } - +int pcep_thread_event_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->pce_opts->previous_best + != best_pcc_state->pce_opts->is_best) { + PCEP_DEBUG(" %s Resynchro best (%i) previous best (%i)", + best_pcc_state->tag, best_pcc_state->id, + best_pcc_state->pce_opts->previous_best); + best_pcc_state->status = PCEP_PCC_SYNCHRONIZING; + best_pcc_state->retry_count = 0; + best_pcc_state->synchronized = false; + pcep_thread_start_sync(ctrl_state, best_pcc_state->id); + } else { + PCEP_DEBUG( + " %s No Resynchro best (%i) previous best (%i)", + best_pcc_state->tag, best_pcc_state->id, + best_pcc_state->pce_opts->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) { + if (!pce_opts || !ctrl_state) { + return 0; + } struct pcc_state *pcc_state; struct pcc_opts *pcc_opts; + struct pce_opts *pce_opts_copy; + int current_pcc_id = get_pcc_id_by_ip(pcep_g->fpt, &pce_opts->addr); + if (!current_pcc_id) { + current_pcc_id = pcep_ctrl_get_free_pcc_id(pcep_g->fpt); + } + if (pcep_g->pce_opts[current_pcc_id - 1] != NULL) + XFREE(MTYPE_PCEP, pcep_g->pce_opts[0]); + pce_opts_copy = XCALLOC(MTYPE_PCEP, sizeof(*pce_opts)); + pce_opts_copy = memcpy(pce_opts_copy, pce_opts, sizeof(*pce_opts)); + pcep_g->pce_opts[current_pcc_id - 1] = pce_opts_copy; + pcc_id = current_pcc_id; + if (pcc_id > ctrl_state->pcc_count) { pcc_state = pcep_pcc_initialize(ctrl_state, pcc_id); set_pcc_state(ctrl_state, pcc_state); } else { pcc_state = get_pcc_state(ctrl_state, pcc_id); + if (!pcc_state) { + pcc_state = pcep_pcc_initialize(ctrl_state, pcc_id); + set_pcc_state(ctrl_state, pcc_state); + } } /* Copy the pcc options to delegate it to the update function */ @@ -673,17 +792,57 @@ int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, "failed to update PCC configuration"); } + calculate_best_pce(ctrl_state); return 0; } -int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, int pcc_id) +int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state, + int pcc_id) { - struct pcc_state *pcc_state; + if (pcc_id) { + if (pcep_g->pce_opts[pcc_id - 1] != NULL) { + XFREE(MTYPE_PCEP, pcep_g->pce_opts[pcc_id - 1]); + pcep_g->pce_opts[pcc_id - 1] = NULL; + } + struct pcc_state *pcc_state = get_pcc_state(ctrl_state, pcc_id); + if (pcc_state) { + remove_pcc_state(ctrl_state, pcc_state); + pcep_pcc_finalize(ctrl_state, pcc_state); + } + } + return 0; +} +int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state) +{ + if (!ctrl_state) { + return 0; + } - if (pcc_id <= ctrl_state->pcc_count) { - pcc_state = get_pcc_state(ctrl_state, pcc_id); - remove_pcc_state(ctrl_state, pcc_state); - pcep_pcc_finalize(ctrl_state, pcc_state); + for (int i = 0; i < MAX_PCC; i++) { + pcep_thread_event_remove_pcc_by_id(ctrl_state, i + 1); + } + if (pcep_g->pcc_opts != NULL) { + XFREE(MTYPE_PCEP, pcep_g->pcc_opts); + pcep_g->pcc_opts = NULL; + } + return 0; +} +int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, + struct ipaddr *pce_addr) +{ + if (!ctrl_state) { + return 0; + } + + if (pce_addr) { + int pcc_id = get_pcc_id_by_ip(pcep_g->fpt, pce_addr); + if (pcc_id) { + pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id); + } else { + return -1; + } + } else { + pcep_thread_event_remove_pcc_all(ctrl_state); } return 0; @@ -711,9 +870,12 @@ int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state, { int i; - for (i = 0; i < ctrl_state->pcc_count; i++) { - struct pcc_state *pcc_state = ctrl_state->pcc[i]; - pcep_pcc_pathd_event_handler(ctrl_state, pcc_state, type, path); + for (i = 0; i < MAX_PCC; i++) { + if (ctrl_state->pcc[i]) { + struct pcc_state *pcc_state = ctrl_state->pcc[i]; + pcep_pcc_pathd_event_handler(ctrl_state, pcc_state, + type, path); + } } pcep_free_path(path); @@ -756,7 +918,162 @@ int pcep_main_event_handler(struct thread *thread) /* ------------ Helper functions ------------ */ +bool is_best_pce(struct ctrl_state *ctrl_state, int pce) +{ + if (ctrl_state && ctrl_state->pcc[pce]) { + return ctrl_state->pcc[pce]->pce_opts->is_best; + } else { + return false; + } +} +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]->pce_opts->previous_best == true + && pcc[i]->status != PCEP_PCC_DISCONNECTED) { + previous_best_pce = i; + break; + } + } + return previous_best_pce != -1 ? previous_best_pce + 1 : -1; +} +int calculate_best_pce(struct ctrl_state *ctrl_state) +{ + int best_precedence = PCE_DEFAULT_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]->pce_opts->is_best == true) { + step_0_best = i; + } + if (pcc[i]->pce_opts->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]->pce_opts->is_best, + pcc[i]->pce_opts->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]->pce_opts->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]->pce_opts->is_best = false; + } + if (step_0_previous != -1) { + pcc[step_0_previous]->pce_opts->previous_best = false; + } + // Set previous + if (previous_best_pce != -1) { + pcc[previous_best_pce]->pce_opts->previous_best = true; + zlog_debug("previous best pce (%i) ", + previous_best_pce + 1); + } + + + // Set best + if (best_pce != -1) { + pcc[best_pce]->pce_opts->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]->pce_opts->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]->pce_opts->is_best = + true; + zlog_debug( + "(disconnected) best pce (default) (%i) ", + i + 1); + break; + } + } + } + } + } + + + return best_pce + 1; +} +int pcep_ctrl_get_free_pcc_id(struct frr_pthread *fpt) +{ + struct ctrl_state *ctrl_state = get_ctrl_state(fpt); + if (ctrl_state->pcc_count == 0) { + return 1; + } + + for (int pcc_id = 0; pcc_id < MAX_PCC; pcc_id++) { + if (ctrl_state->pcc[pcc_id] == NULL) { + zlog_debug("new pcc_id (%d)", pcc_id + 1); + return pcc_id + 1; + } + } + + return 0; +} void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state) { assert(fpt != NULL); @@ -774,6 +1091,24 @@ struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt) return ctrl_state; } +int get_pcc_id_by_ip(struct frr_pthread *fpt, struct ipaddr *pce_ip) +{ + struct ctrl_state *ctrl_state = get_ctrl_state(fpt); + for (int pcc_id = 0; pcc_id < MAX_PCC; pcc_id++) { + if (ctrl_state->pcc[pcc_id]) { + if (ipaddr_cmp((const struct ipaddr *)&ctrl_state + ->pcc[pcc_id] + ->pce_opts->addr, + (const struct ipaddr *)pce_ip) + == 0) { + zlog_debug("found pcc_id (%d)", pcc_id + 1); + return pcc_id + 1; + } + } + } + return 0; +} + struct pcc_state *get_pcc_state(struct ctrl_state *ctrl_state, int pcc_id) { assert(ctrl_state != NULL); @@ -781,11 +1116,10 @@ struct pcc_state *get_pcc_state(struct ctrl_state *ctrl_state, int pcc_id) assert(pcc_id <= MAX_PCC); struct pcc_state *pcc_state; - if (pcc_id > ctrl_state->pcc_count) + if (pcc_id > MAX_PCC) return NULL; pcc_state = ctrl_state->pcc[pcc_id - 1]; - assert(pcc_state != NULL); return pcc_state; } @@ -794,11 +1128,10 @@ void set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) assert(ctrl_state != NULL); assert(pcc_state->id >= 0); assert(pcc_state->id <= MAX_PCC); - assert(pcc_state->id > ctrl_state->pcc_count); - assert(ctrl_state->pcc[pcc_state->id - 1] == NULL); ctrl_state->pcc[pcc_state->id - 1] = pcc_state; - ctrl_state->pcc_count = pcc_state->id; + ctrl_state->pcc_count++; + zlog_debug("added pce pcc_id (%d)", pcc_state->id); } void remove_pcc_state(struct ctrl_state *ctrl_state, @@ -809,11 +1142,11 @@ void remove_pcc_state(struct ctrl_state *ctrl_state, assert(pcc_state->id <= MAX_PCC); /* FIXME: Can only remove the last PCC for now, * we have only one anyway */ - assert(pcc_state->id == ctrl_state->pcc_count); - assert(ctrl_state->pcc[pcc_state->id - 1] != NULL); + // assert(ctrl_state->pcc[pcc_state->id - 1] != NULL); ctrl_state->pcc[pcc_state->id - 1] = NULL; ctrl_state->pcc_count--; + zlog_debug("removed pce pcc_id (%d)", pcc_state->id); } uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count) diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h index 0cf58e37d92c..bd49823a4a43 100644 --- a/pathd/path_pcep_controller.h +++ b/pathd/path_pcep_controller.h @@ -50,7 +50,11 @@ struct ctrl_state { /* Timer handling data structures */ -enum pcep_ctrl_timer_type { TM_RECONNECT_PCC, TM_PCEPLIB_TIMER }; +enum pcep_ctrl_timer_type { + TM_RECONNECT_PCC, + TM_PCEPLIB_TIMER, + TM_CALCULATE_BEST_PCE +}; struct pcep_ctrl_timer_data { struct ctrl_state *ctrl_state; @@ -75,15 +79,22 @@ struct pcep_ctrl_socket_data { typedef int (*pcep_ctrl_thread_callback)(struct thread *); /* Functions called from the main thread */ +int calculate_best_pce(struct ctrl_state *ctrl_state); +bool is_best_pce(struct ctrl_state *ctrl_state, int pce); +int get_previous_best_pce(struct ctrl_state *ctrl_state); +int get_pcc_id_by_ip(struct frr_pthread *fpt, struct ipaddr *pce_ip); +int pcep_ctrl_get_free_pcc_id(struct frr_pthread *fpt); int pcep_ctrl_initialize(struct thread_master *main_thread, struct frr_pthread **fpt, pcep_main_event_handler_t event_handler); int pcep_ctrl_finalize(struct frr_pthread **fpt); int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt, struct pcc_opts *opts); +int pcep_ctrl_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id); +int pcep_ctrl_update_timer_best_pce(struct ctrl_state *ctrl_state, int pcc_id); int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, int pcc_id, struct pce_opts *opts); -int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, int pcc_id); +int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct ipaddr *pce_addr); int pcep_ctrl_pathd_event(struct frr_pthread *fpt, enum pcep_pathd_event_type type, struct path *path); int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path); @@ -102,6 +113,9 @@ void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id, void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id, int retry_count, struct thread **thread); +void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state, + int pcc_id, int delay, + struct thread **thread); void pcep_thread_schedule_pceplib_timer(struct ctrl_state *ctrl_state, int delay, void *payload, struct thread **thread, pcep_ctrl_thread_callback cb); diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c index 3fa9384004ec..55c307ff9fb2 100644 --- a/pathd/path_pcep_debug.c +++ b/pathd/path_pcep_debug.c @@ -744,9 +744,11 @@ void _format_ctrl_state(int ps, struct ctrl_state *state) } PCEP_FORMAT("%*spcc_count: %d\n", ps2, "", state->pcc_count); PCEP_FORMAT("%*spcc:\n", ps2, ""); - for (i = 0; i < state->pcc_count; i++) { - PCEP_FORMAT("%*s- ", ps3 - 2, ""); - _format_pcc_state(ps3, state->pcc[i]); + for (i = 0; i < MAX_PCC; i++) { + if (state->pcc[i]) { + PCEP_FORMAT("%*s- ", ps3 - 2, ""); + _format_pcc_state(ps3, state->pcc[i]); + } } } } diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 61126cde2d3e..0bceb4d6e6c7 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -226,6 +226,11 @@ int compare_pce_opts(struct pce_opts *lhs, struct pce_opts *rhs) return 1; } + retval = lhs->precedence - rhs->precedence; + if (retval != 0) { + return retval; + } + retval = memcmp(&lhs->addr, &rhs->addr, sizeof(lhs->addr)); if (retval != 0) { return retval; @@ -519,9 +524,11 @@ void pcep_pcc_pcep_event_handler(struct ctrl_state *ctrl_state, PCEP_DEBUG_PCEP("%s PCEP message: %s", pcc_state->tag, format_pcep_message(event->message)); break; + case PCE_DEAD_TIMER_EXPIRED: + PCEP_DEBUG("%s PCE_DEAD_TIMER_EXPIRED %d", pcc_state->tag, + pcc_state->retry_count); case PCE_CLOSED_SOCKET: case PCE_SENT_PCEP_CLOSE: - case PCE_DEAD_TIMER_EXPIRED: case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED: case PCC_PCEP_SESSION_CLOSED: case PCC_RCVD_MAX_INVALID_MSGS: @@ -766,7 +773,8 @@ void specialize_output_path(struct pcc_state *pcc_state, struct path *path) path->sender = pcc_state->pcc_addr_tr; if ((path->originator == NULL) - || (strcmp(path->originator, pcc_state->originator) == 0)) { + || (strcmp(path->originator, pcc_state->originator) == 0) + || pcc_state->pce_opts->is_best) { is_delegated = path->type == SRTE_CANDIDATE_TYPE_DYNAMIC; /* it seems the PCE consider updating an LSP a creation ?!? at least Cisco does... */ @@ -774,8 +782,8 @@ void specialize_output_path(struct pcc_state *pcc_state, struct path *path) } path->pcc_id = pcc_state->id; - path->go_active = is_delegated; - path->is_delegated = is_delegated; + path->go_active = (is_delegated & pcc_state->pce_opts->is_best); + path->is_delegated = (is_delegated & pcc_state->pce_opts->is_best); path->was_created = was_created; }