diff options
author | Javier Garcia <javier.garcia@voltanet.io> | 2021-05-21 09:15:52 +0200 |
---|---|---|
committer | Javier Garcia <javier.garcia@voltanet.io> | 2021-06-22 12:04:03 +0200 |
commit | 56634922390ff08d2ae06ecb0c32f94c07028561 (patch) | |
tree | 2c1fb1080e2b0dbd5397c8bbfba2d668d9fb116a /pathd/path_pcep_pcc.c | |
parent | pceplib: Extract fields needed for PcInitiated with Cisco pce. (1/4) (diff) | |
download | frr-56634922390ff08d2ae06ecb0c32f94c07028561.tar.xz frr-56634922390ff08d2ae06ecb0c32f94c07028561.zip |
pathd: Handle PCInitiated messages, thread controller. (2/4)
Co-authored-by: Javier Garcia <javier.garcia@voltanet.io>
Signed-off-by: Sebastien Merle <sebastien@netdef.org>
Signed-off-by: Javier Garcia <javier.garcia@voltanet.io>
Diffstat (limited to 'pathd/path_pcep_pcc.c')
-rw-r--r-- | pathd/path_pcep_pcc.c | 157 |
1 files changed, 136 insertions, 21 deletions
diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 779c400b8..81a338ac6 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -93,7 +93,8 @@ static void send_pcep_message(struct pcc_state *pcc_state, struct pcep_message *msg); static void send_pcep_error(struct pcc_state *pcc_state, enum pcep_error_type error_type, - enum pcep_error_value error_value); + enum pcep_error_value error_value, + struct path *trigger_path); static void send_report(struct pcc_state *pcc_state, struct path *path); static void send_comp_request(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, @@ -541,8 +542,8 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, return; } - PCEP_DEBUG("%s Send report for candidate path %s", pcc_state->tag, - path->name); + PCEP_DEBUG("(%s)%s Send report for candidate path %s", __func__, + pcc_state->tag, path->name); /* ODL and Cisco requires the first reported * LSP to have a DOWN status, the later status changes @@ -555,6 +556,8 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, /* If no update is expected and the real status wasn't down, we need to * send a second report with the real status */ if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) { + PCEP_DEBUG("(%s)%s Send report for candidate path (!DOWN) %s", + __func__, pcc_state->tag, path->name); path->srp_id = 0; path->status = real_status; send_report(pcc_state, path); @@ -564,6 +567,19 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, } +void pcep_pcc_send_error(struct ctrl_state *ctrl_state, + struct pcc_state *pcc_state, struct pcep_error *error, + bool sub_type) +{ + + PCEP_DEBUG("(%s) Send error after PcInitiated ", __func__); + + + send_pcep_error(pcc_state, error->error_type, error->error_value, + error->path); + pcep_free_path(error->path); + XFREE(MTYPE_PCEP, error); +} /* ------------ Timeout handler ------------ */ void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state, @@ -651,6 +667,9 @@ void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state, PCEP_DEBUG("%s Candidate path %s removed", pcc_state->tag, path->name); path->was_removed = true; + /* Removed as response to a PcInitiated 'R'emove*/ + /* RFC 8281 #5.4 LSP Deletion*/ + path->do_remove = path->was_removed; if (pcc_state->caps.is_stateful) send_report(pcc_state, path); return; @@ -1203,14 +1222,113 @@ void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg) { - PCEP_DEBUG("%s Received LSP initiate, not supported yet", - pcc_state->tag); + char err[MAX_ERROR_MSG_SIZE] = ""; + struct path *path; + + path = pcep_lib_parse_path(msg); + + if (!pcc_state->pce_opts->config_opts.pce_initiated) { + /* PCE Initiated is not enabled */ + flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, + "Not allowed PCE initiated path received: %s", + format_pcep_message(msg)); + send_pcep_error(pcc_state, PCEP_ERRT_LSP_INSTANTIATE_ERROR, + PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR, path); + return; + } - /* TODO when we support both PCC and PCE initiated sessions, - * we should first check the session type before - * rejecting this message. */ - send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION, - PCEP_ERRV_LSP_NOT_PCE_INITIATED); + if (path->do_remove) { + // lookup in nbkey sequential as no endpoint + struct nbkey_map_data *key; + char endpoint[46]; + + frr_each (nbkey_map, &pcc_state->nbkey_map, key) { + ipaddr2str(&key->nbkey.endpoint, endpoint, + sizeof(endpoint)); + flog_warn( + EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, + "FOR_EACH nbkey [color (%d) endpoint (%s)] path [plsp_id (%d)] ", + key->nbkey.color, endpoint, path->plsp_id); + if (path->plsp_id == key->plspid) { + flog_warn( + EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, + "FOR_EACH MATCH nbkey [color (%d) endpoint (%s)] path [plsp_id (%d)] ", + key->nbkey.color, endpoint, + path->plsp_id); + path->nbkey = key->nbkey; + break; + } + } + } else { + if (path->first_hop == NULL /*ero sets first_hop*/) { + /* If the PCC receives a PCInitiate message without an + * ERO and the R flag in the SRP object != zero, then it + * MUST send a PCErr message with Error-type=6 + * (Mandatory Object missing) and Error-value=9 (ERO + * object missing). */ + flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, + "ERO object missing or incomplete : %s", + format_pcep_message(msg)); + send_pcep_error(pcc_state, + PCEP_ERRT_LSP_INSTANTIATE_ERROR, + PCEP_ERRV_INTERNAL_ERROR, path); + return; + } + + if (path->plsp_id != 0) { + /* If the PCC receives a PCInitiate message with a + * non-zero PLSP-ID and the R flag in the SRP object set + * to zero, then it MUST send a PCErr message with + * Error-type=19 (Invalid Operation) and Error-value=8 + * (Non-zero PLSP-ID in the LSP Initiate Request) */ + flog_warn( + EC_PATH_PCEP_PROTOCOL_ERROR, + "PCE initiated path with non-zero PLSP ID: %s", + format_pcep_message(msg)); + send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION, + PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID, + path); + return; + } + + if (path->name == NULL) { + /* If the PCC receives a PCInitiate message without a + * SYMBOLIC-PATH-NAME TLV, then it MUST send a PCErr + * message with Error-type=10 (Reception of an invalid + * object) and Error-value=8 (SYMBOLIC-PATH-NAME TLV + * missing) */ + flog_warn( + EC_PATH_PCEP_PROTOCOL_ERROR, + "PCE initiated path without symbolic name: %s", + format_pcep_message(msg)); + send_pcep_error( + pcc_state, PCEP_ERRT_RECEPTION_OF_INV_OBJECT, + PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING, path); + return; + } + } + + /* TODO: If there is a conflict with the symbolic path name of an + * existing LSP, the PCC MUST send a PCErr message with Error-type=23 + * (Bad Parameter value) and Error-value=1 (SYMBOLIC-PATH-NAME in + * use) */ + + specialize_incoming_path(pcc_state, path); + /* TODO: Validate the PCC address received from the PCE is valid */ + PCEP_DEBUG("%s Received LSP initiate", pcc_state->tag); + PCEP_DEBUG_PATH("%s", format_path(path)); + + if (validate_incoming_path(pcc_state, path, err, sizeof(err))) { + pcep_thread_initiate_path(ctrl_state, pcc_state->id, path); + } else { + /* FIXME: Monitor the amount of errors from the PCE and + * possibly disconnect and blacklist */ + flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, + "Unsupported PCEP protocol feature: %s", err); + pcep_free_path(path); + send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION, + PCEP_ERRV_LSP_NOT_PCE_INITIATED, path); + } } void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, @@ -1232,7 +1350,7 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, pcc_state->tag, path->req_id); PCEP_DEBUG_PATH("%s", format_path(path)); send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF, - PCEP_ERRV_UNASSIGNED); + PCEP_ERRV_UNASSIGNED, NULL); return; } @@ -1447,13 +1565,14 @@ void send_pcep_message(struct pcc_state *pcc_state, struct pcep_message *msg) void send_pcep_error(struct pcc_state *pcc_state, enum pcep_error_type error_type, - enum pcep_error_value error_value) + enum pcep_error_value error_value, + struct path *trigger_path) { struct pcep_message *msg; PCEP_DEBUG("%s Sending PCEP error type %s (%d) value %s (%d)", pcc_state->tag, pcep_error_type_name(error_type), error_type, pcep_error_value_name(error_type, error_value), error_value); - msg = pcep_lib_format_error(error_type, error_value); + msg = pcep_lib_format_error(error_type, error_value, trigger_path); send_pcep_message(pcc_state, msg); } @@ -1504,7 +1623,8 @@ void specialize_outgoing_path(struct pcc_state *pcc_state, struct path *path) /* Updates the path for the PCC */ void specialize_incoming_path(struct pcc_state *pcc_state, struct path *path) { - set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr); + if (IS_IPADDR_NONE(&path->pcc_addr)) + set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr); path->sender = pcc_state->pce_opts->addr; path->pcc_id = pcc_state->id; path->update_origin = SRTE_ORIGIN_PCEP; @@ -1538,7 +1658,7 @@ bool validate_incoming_path(struct pcc_state *pcc_state, struct path *path, } if (err_type != 0) { - send_pcep_error(pcc_state, err_type, err_value); + send_pcep_error(pcc_state, err_type, err_value, NULL); return false; } @@ -1564,7 +1684,6 @@ void send_comp_request(struct ctrl_state *ctrl_state, if (!pcc_state->is_best) { return; } - /* TODO: Add a timer to retry the computation request ? */ specialize_outgoing_path(pcc_state, req->path); @@ -1579,10 +1698,7 @@ void send_comp_request(struct ctrl_state *ctrl_state, send_pcep_message(pcc_state, msg); req->was_sent = true; - /* TODO: Enable this back when the pcep config changes are merged back - */ - // timeout = pcc_state->pce_opts->config_opts.pcep_request_time_seconds; - timeout = 30; + timeout = pcc_state->pce_opts->config_opts.pcep_request_time_seconds; pcep_thread_schedule_timeout(ctrl_state, pcc_state->id, TO_COMPUTATION_REQUEST, timeout, (void *)req, &req->t_retry); @@ -1641,7 +1757,6 @@ void set_pcc_address(struct pcc_state *pcc_state, struct lsp_nb_key *nbkey, } } - /* ------------ Data Structure Helper Functions ------------ */ void lookup_plspid(struct pcc_state *pcc_state, struct path *path) |