Skip to content

Commit

Permalink
Support for multiple pce's
Browse files Browse the repository at this point in the history
Signed-off-by: Javier Garcia <javier.garcia@voltanet.io>
  • Loading branch information
Javier Garcia committed Jun 12, 2020
1 parent ef87269 commit 81d7feb
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 26 deletions.
83 changes: 70 additions & 13 deletions pathd/path_pcep.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,22 +417,25 @@ DEFUN(pcep_cli_no_pcc, pcep_cli_no_pcc_cmd, "no pcc",
}

DEFUN(pcep_cli_pce, pcep_cli_pce_cmd,
"pce <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] [sr-draft07]",
"pce <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] [sr-draft07] [precedence (0-255)]",
"PCE configuration\n"
"PCE IPv4 address\n"
"Remote PCE server IPv4 address\n"
"PCE IPv6 address\n"
"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;
bool draft07 = false;
uint8_t pce_precedence = PCE_DEFAULT_PRECEDENCE;
int i = 1;

/* Get the first argument, should be either ip or ipv6 */
Expand Down Expand Up @@ -476,22 +479,42 @@ 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;
}

pce_opts = XCALLOC(MTYPE_PCEP, sizeof(*pce_opts));
IPADDR_COPY(&pce_opts->addr, &pce_addr);
pce_opts->port = pce_port;
pce_opts->draft07 = draft07;

if (pcep_ctrl_update_pce_options(pcep_g->fpt, 1, pce_opts))
pce_opts->precedence = pce_precedence;

/*
int current_pcc_id = get_pcc_id_by_ip(pcep_g->fpt, &pce_addr);
if (!current_pcc_id) {
current_pcc_id = pcep_ctrl_get_free_pcc_id(pcep_g->fpt);
}
*/
#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;
/*
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;
*/

return CMD_SUCCESS;
}
Expand All @@ -508,11 +531,39 @@ 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;
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;
}
}


int current_pcc_id = get_pcc_id_by_ip(pcep_g->fpt, &pce_addr);
if (current_pcc_id) {
pcep_ctrl_remove_pcc(pcep_g->fpt, current_pcc_id);
if (pcep_g->pce_opts[current_pcc_id - 1] != NULL) {
XFREE(MTYPE_PCEP, pcep_g->pce_opts[current_pcc_id - 1]);
pcep_g->pce_opts[current_pcc_id - 1] = NULL;
}
}
return CMD_SUCCESS;
}
Expand Down Expand Up @@ -622,6 +673,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,
Expand Down
5 changes: 4 additions & 1 deletion pathd/path_pcep.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -84,6 +85,8 @@ struct pce_opts {
struct ipaddr addr;
short port;
bool draft07;
uint8_t precedence;
bool is_best;
};

struct pcc_opts {
Expand Down
131 changes: 122 additions & 9 deletions pathd/path_pcep_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
_a <= _b ? _a : _b; \
})

#define MAX_RETRIES_BEFORE_LOST_PRECEDENCE 5


/* Event handling data structures */
enum pcep_ctrl_event_type {
Expand Down Expand Up @@ -191,6 +193,7 @@ int pcep_ctrl_initialize(struct thread_master *main_thread,
ctrl_state->pcc_count = 0;
ctrl_state->pcc_opts =
XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state->pcc_opts));
memset(ctrl_state->pcc, 0, sizeof(ctrl_state->pcc[0]) * MAX_PCC);
/* Default to no PCC address defined */
UNSET_FLAG(ctrl_state->pcc_opts->flags, F_PCC_OPTS_IPV4);
UNSET_FLAG(ctrl_state->pcc_opts->flags, F_PCC_OPTS_IPV6);
Expand Down Expand Up @@ -452,6 +455,14 @@ 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);
if (pcc_state->retry_count < MAX_RETRIES_BEFORE_LOST_PRECEDENCE) {
PCEP_DEBUG("%s wait and keep pce precedence ", pcc_state->tag);
} else {
PCEP_DEBUG("%s recalculating pce precedence ", pcc_state->tag);
calculate_best_pce(ctrl_state);
}

switch (type) {
case TM_RECONNECT_PCC:
Expand Down Expand Up @@ -654,11 +665,27 @@ int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state,
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 */
Expand All @@ -670,18 +697,17 @@ 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)
{
struct pcc_state *pcc_state;

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);
}

return 0;
}
Expand Down Expand Up @@ -710,6 +736,7 @@ int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,

for (i = 0; i < ctrl_state->pcc_count; i++) {
struct pcc_state *pcc_state = ctrl_state->pcc[i];
// path->is_delegated = is_best_pce(ctrl_state, i);
pcep_pcc_pathd_event_handler(ctrl_state, pcc_state, type, path);
}

Expand Down Expand Up @@ -753,7 +780,78 @@ 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 calculate_best_pce(struct ctrl_state *ctrl_state)
{
bool is_best = false;
int best_precedence = PCE_DEFAULT_PRECEDENCE;
int best_pce = -1;
int default_pce = 0;

if (!ctrl_state || !ctrl_state->pcc_count)
return 0;

struct pcc_state **pcc = &ctrl_state->pcc[0];

for (int i = 0; i < ctrl_state->pcc_count; i++) {
if (pcc[i] && pcc[i]->pce_opts
&& pcc[i]->status != PCEP_PCC_DISCONNECTED) {
default_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 {
best_precedence =
pcc[i]->pce_opts->precedence;
best_pce = i;
}
}
}
}

for (int i = 0; i < ctrl_state->pcc_count; i++) {
pcc[best_pce]->pce_opts->is_best = false;
}
if (best_pce != -1) {
pcc[best_pce]->pce_opts->is_best = true;
zlog_debug("best pce (%i) ", best_pce + 1);
} else {
pcc[default_pce]->pce_opts->is_best = true;
zlog_debug("best (default) pce (%i) ", default_pce);
}

return best_pce;
}
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);
Expand All @@ -771,16 +869,32 @@ 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);
assert(pcc_id >= 0);
assert(pcc_id <= MAX_PCC);
assert(pcc_id <= ctrl_state->pcc_count);

struct pcc_state *pcc_state;
pcc_state = ctrl_state->pcc[pcc_id - 1];
assert(pcc_state != NULL);
return pcc_state;
}

Expand All @@ -789,11 +903,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,
Expand All @@ -804,11 +917,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)
Expand Down
4 changes: 4 additions & 0 deletions pathd/path_pcep_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ 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_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);
Expand Down
Loading

0 comments on commit 81d7feb

Please sign in to comment.