diff options
author | Javier Garcia <javier.garcia@voltanet.io> | 2021-04-22 15:52:27 +0200 |
---|---|---|
committer | Javier Garcia <javier.garcia@voltanet.io> | 2021-05-10 12:36:46 +0200 |
commit | 75c69d151c8e72e42dfb4b1966428e9cf79cb7f4 (patch) | |
tree | 240ecdf1e026387c787fa33fe8a716750525dd1a | |
parent | Merge pull request #8639 from idryzhov/isis-new-bfd-lib (diff) | |
download | frr-75c69d151c8e72e42dfb4b1966428e9cf79cb7f4.tar.xz frr-75c69d151c8e72e42dfb4b1966428e9cf79cb7f4.zip |
pathd. TED support . Client to link State - [part 1/4]
- pathd will act as a client to for the configured igp.
- pathd must be configured to activate and receive data from igp.
!pathd config snippet
segment-routing
traffic-eng
mpls-te on
mpls-te import ospfv2
Signed-off-by: Javier Garcia <javier.garcia@voltanet.io>
-rw-r--r-- | pathd/path_main.c | 4 | ||||
-rw-r--r-- | pathd/path_ted.c | 726 | ||||
-rw-r--r-- | pathd/path_ted.h | 178 | ||||
-rw-r--r-- | pathd/path_zebra.c | 56 | ||||
-rw-r--r-- | pathd/pathd.c | 15 | ||||
-rw-r--r-- | pathd/pathd.h | 2 | ||||
-rw-r--r-- | pathd/subdir.am | 8 |
7 files changed, 987 insertions, 2 deletions
diff --git a/pathd/path_main.c b/pathd/path_main.c index f54ab736c..8d8847520 100644 --- a/pathd/path_main.c +++ b/pathd/path_main.c @@ -33,6 +33,7 @@ #include "path_nb.h" #include "path_zebra.h" #include "path_errors.h" +#include "path_ted.h" char backup_config_file[256]; @@ -70,6 +71,8 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); + zlog_notice("Unregisterfrom opaque,etc "); + pathd_shutdown(); exit(0); } @@ -146,6 +149,7 @@ int main(int argc, char **argv, char **envp) path_error_init(); path_zebra_init(master); path_cli_init(); + path_ted_init(master); frr_config_fork(); frr_run(master); diff --git a/pathd/path_ted.c b/pathd/path_ted.c new file mode 100644 index 000000000..01ada9225 --- /dev/null +++ b/pathd/path_ted.c @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2020 Volta Networks, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "stdlib.h" + +#include <zebra.h> + +#include "memory.h" +#include "log.h" +#include "command.h" +#include "prefix.h" +#include <lib/json.h> + +#include "pathd.h" +#include "pathd/path_errors.h" +#include "pathd/path_ted.h" + +#ifndef VTYSH_EXTRACT_PL +#include "pathd/path_ted_clippy.c" +#endif + +static struct ls_ted *path_ted_create_ted(void); +static void path_ted_register_vty(void); +static void path_ted_unregister_vty(void); +static uint32_t path_ted_start_importing_igp(const char *daemon_str); +static uint32_t path_ted_stop_importing_igp(void); +static enum zclient_send_status path_ted_link_state_sync(void); +static int path_ted_timer_handler_sync(struct thread *thread); +static int path_ted_timer_handler_refresh(struct thread *thread); +static int path_ted_cli_debug_config_write(struct vty *vty); +static int path_ted_cli_debug_set_all(uint32_t flags, bool set); + +extern struct zclient *zclient; + +struct ted_state ted_state_g = {}; + +/* + * path_path_ted public API function implementations + */ + +void path_ted_init(struct thread_master *master) +{ + ted_state_g.main = master; + ted_state_g.link_state_delay_interval = TIMER_RETRY_DELAY; + ted_state_g.segment_list_refresh_interval = TIMER_RETRY_DELAY; + path_ted_register_vty(); + path_ted_segment_list_refresh(); +} + +uint32_t path_ted_teardown(void) +{ + PATH_TED_DEBUG("%s : TED [%p]", __func__, ted_state_g.ted); + path_ted_unregister_vty(); + path_ted_stop_importing_igp(); + ls_ted_del_all(ted_state_g.ted); + path_ted_timer_sync_cancel(); + path_ted_timer_refresh_cancel(); + return 0; +} + +/** + * Set all needed to receive igp data. + * + * @return true if ok + * + */ +uint32_t path_ted_start_importing_igp(const char *daemon_str) +{ + uint32_t status = 0; + + if (strcmp(daemon_str, "ospfv2") == 0) + ted_state_g.import = IMPORT_OSPFv2; + else if (strcmp(daemon_str, "ospfv3") == 0) { + ted_state_g.import = IMPORT_UNKNOWN; + return 1; + } else if (strcmp(daemon_str, "isis") == 0) + ted_state_g.import = IMPORT_ISIS; + else { + ted_state_g.import = IMPORT_UNKNOWN; + return 1; + } + + if (ls_register(zclient, false /*client*/) != 0) { + PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State", + __func__); + ted_state_g.import = IMPORT_UNKNOWN; + status = 1; + } else { + if (path_ted_link_state_sync() != -1) { + PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON", + __func__, + PATH_TED_IGP_PRINT(ted_state_g.import)); + } else { + PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF", + __func__, + PATH_TED_IGP_PRINT(ted_state_g.import)); + ted_state_g.import = IMPORT_UNKNOWN; + } + } + return status; +} + +/** + * Unset all needed to receive igp data. + * + * @return true if ok + * + */ +uint32_t path_ted_stop_importing_igp(void) +{ + uint32_t status = 0; + + if (ted_state_g.import != IMPORT_UNKNOWN) { + if (ls_unregister(zclient, false /*client*/) != 0) { + PATH_TED_ERROR( + "%s: PATHD-TED: Unable to unregister Link State", + __func__); + status = 1; + } else { + ted_state_g.import = IMPORT_UNKNOWN; + PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF", + __func__); + } + path_ted_timer_sync_cancel(); + } + return status; +} +/** + * Check for ted status + * + * @return true if ok + * + */ +bool path_ted_is_initialized(void) +{ + if (ted_state_g.ted == NULL) { + PATH_TED_WARN("PATHD TED ls_ted not initialized"); + return false; + } + + return true; +} + +/** + * Creates an empty ted + * + * @param void + * + * @return Ptr to ted or NULL + */ +struct ls_ted *path_ted_create_ted() +{ + struct ls_ted *ted = ls_ted_new(TED_KEY, TED_NAME, TED_ASN); + + if (ted == NULL) { + PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]", + __func__, TED_KEY, TED_ASN, TED_NAME); + } else { + PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]", + __func__, TED_KEY, TED_ASN, TED_NAME); + } + + return ted; +} + +uint32_t path_ted_rcvd_message(struct ls_message *msg) +{ + if (!path_ted_is_initialized()) + return 1; + + if (msg == NULL) { + PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ", + __func__); + return 1; + } + + if (path_ted_get_current_igp(msg->data.node->adv.origin)) + return 1; + + switch (msg->type) { + case LS_MSG_TYPE_NODE: + ls_msg2vertex(ted_state_g.ted, msg, true /*hard delete*/); + break; + + case LS_MSG_TYPE_ATTRIBUTES: + ls_msg2edge(ted_state_g.ted, msg, true /*ĥard delete*/); + break; + + case LS_MSG_TYPE_PREFIX: + ls_msg2subnet(ted_state_g.ted, msg, true /*hard delete*/); + break; + + default: + PATH_TED_DEBUG( + "%s: [rcv ted] TED received unknown message type [%d]", + __func__, msg->type); + break; + } + return 0; +} + +uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote) +{ + uint32_t sid = MPLS_LABEL_NONE; + struct ls_edge *edge; + uint64_t key; + + if (!path_ted_is_initialized()) + return MPLS_LABEL_NONE; + + if (!local || !remote) + return MPLS_LABEL_NONE; + + switch (local->ipa_type) { + case IPADDR_V4: + /* We have local and remote ip */ + /* so check all attributes in ted */ + key = ((uint64_t)ntohl(local->ip._v4_addr.s_addr)) & 0xffffffff; + edge = ls_find_edge_by_key(ted_state_g.ted, key); + if (edge) { + if (edge->attributes->standard.remote.s_addr + == remote->ip._v4_addr.s_addr + && CHECK_FLAG(edge->attributes->flags, + LS_ATTR_ADJ_SID)) { + sid = edge->attributes->adj_sid[0] + .sid; /* from primary */ + break; + } + } + break; + case IPADDR_V6: + key = (uint64_t)(local->ip._v6_addr.s6_addr32[0] & 0xffffffff) + | ((uint64_t)local->ip._v6_addr.s6_addr32[1] << 32); + edge = ls_find_edge_by_key(ted_state_g.ted, key); + if (edge) { + if ((memcmp(&edge->attributes->standard.remote6, + &remote->ip._v6_addr, + sizeof(remote->ip._v6_addr)) + && CHECK_FLAG(edge->attributes->flags, + LS_ATTR_ADJ_SID))) { + sid = edge->attributes->adj_sid[0] + .sid; /* from primary */ + break; + } + } + break; + case IPADDR_NONE: + break; + } + + return sid; +} + +uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo) +{ + uint32_t sid = MPLS_LABEL_NONE; + struct ls_subnet *subnet; + + if (!path_ted_is_initialized()) + return MPLS_LABEL_NONE; + + if (!prefix) + return MPLS_LABEL_NONE; + + switch (prefix->family) { + case AF_INET: + case AF_INET6: + subnet = ls_find_subnet(ted_state_g.ted, *prefix); + if (subnet) { + if ((CHECK_FLAG(subnet->ls_pref->flags, LS_PREF_SR)) + && (subnet->ls_pref->sr.algo == algo)) + sid = subnet->ls_pref->sr.sid; + } + break; + default: + break; + } + + return sid; +} + +uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id) +{ + uint32_t sid = MPLS_LABEL_NONE; + struct ls_subnet *subnet; + struct listnode *lst_node; + struct ls_edge *edge; + + if (!path_ted_is_initialized()) + return MPLS_LABEL_NONE; + + if (!prefix) + return MPLS_LABEL_NONE; + + switch (prefix->family) { + case AF_INET: + case AF_INET6: + subnet = ls_find_subnet(ted_state_g.ted, *prefix); + if (subnet && subnet->vertex + && subnet->vertex->outgoing_edges) { + /* from the vertex linked in subnet */ + /* loop over outgoing edges */ + for (ALL_LIST_ELEMENTS_RO( + subnet->vertex->outgoing_edges, lst_node, + edge)) { + /* and look for ifaceid */ + /* so get sid of attribute */ + if (CHECK_FLAG(edge->attributes->flags, + LS_ATTR_LOCAL_ID) + && edge->attributes->standard.local_id + == iface_id) { + sid = subnet->ls_pref->sr.sid; + break; + } + } + } + break; + default: + break; + } + + return sid; +} + +DEFPY (debug_path_ted, + debug_path_ted_cmd, + "[no] debug pathd mpls-te", + NO_STR + DEBUG_STR + "path debugging\n" + "ted debugging\n") +{ + uint32_t mode = DEBUG_NODE2MODE(vty->node); + bool no_debug = (no != NULL); + + DEBUG_MODE_SET(&ted_state_g.dbg, mode, !no); + DEBUG_FLAGS_SET(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC, !no_debug); + return CMD_SUCCESS; +} + +/* + * Followings are vty command functions. + */ +/* clang-format off */ +DEFUN (path_ted_on, + path_ted_on_cmd, + "mpls-te on", + NO_STR + "Enable the TE database (TED) functionality\n") +/* clang-format on */ +{ + + if (ted_state_g.enabled) { + PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__); + return CMD_SUCCESS; + } + + ted_state_g.ted = path_ted_create_ted(); + ted_state_g.enabled = true; + PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__); + + return CMD_SUCCESS; +} + +/* clang-format off */ +DEFUN (no_path_ted, + no_path_ted_cmd, + "no mpls-te [on]", + NO_STR + NO_STR + "Disable the TE Database functionality\n") +/* clang-format on */ +{ + if (ted_state_g.enabled) { + PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__); + return CMD_SUCCESS; + } + + /* Remove TED */ + ls_ted_del_all(ted_state_g.ted); + ted_state_g.enabled = false; + PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__); + ted_state_g.import = IMPORT_UNKNOWN; + if (ls_unregister(zclient, false /*client*/) != 0) { + vty_out(vty, "Unable to unregister Link State\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* clang-format off */ +DEFPY(path_ted_import, + path_ted_import_cmd, + "mpls-te import <ospfv2|ospfv3|isis>$import_daemon", + "Enable the TE database (TED) fill with remote igp data\n" + "import\n" + "Origin ospfv2\n" + "Origin ospfv3\n" + "Origin isis\n") +/* clang-format on */ +{ + + if (ted_state_g.enabled) + if (path_ted_start_importing_igp(import_daemon)) { + vty_out(vty, "Unable to start importing\n"); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* clang-format off */ +DEFUN (no_path_ted_import, + no_path_ted_import_cmd, + "no mpls-te import", + NO_STR + NO_STR + "Disable the TE Database fill with remote igp data\n") +/* clang-format on */ +{ + + if (ted_state_g.import) { + if (path_ted_stop_importing_igp()) { + vty_out(vty, "Unable to stop importing\n"); + return CMD_WARNING; + } else { + PATH_TED_DEBUG( + "%s: PATHD-TED: Importing igp data already OFF", + __func__); + } + } + return CMD_SUCCESS; +} + +/* clang-format off */ +DEFPY (show_pahtd_ted_db, + show_pathd_ted_db_cmd, + "show pathd ted database <verbose|json>$ver_json ", + "show command\n" + "pathd daemon\n" + "traffic eng\n" + "database\n" + "verbose output\n" + "Show complete received TED database\n") +/* clang-format on */ +{ + bool st_json = false; + json_object *json = NULL; + + if (!ted_state_g.enabled) { + vty_out(vty, "PATHD TED database is not enabled\n"); + return CMD_WARNING; + } + if (strcmp(ver_json, "json") == 0) { + st_json = true; + json = json_object_new_object(); + } + /* Show the complete TED */ + ls_show_ted(ted_state_g.ted, vty, json, !st_json); + if (st_json) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; +} + +/* + * Config Write functions + */ + +int path_ted_cli_debug_config_write(struct vty *vty) +{ + if (DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_CONF)) { + if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) + vty_out(vty, "debug pathd mpls-te\n"); + return 1; + } + return 0; +} + +int path_ted_cli_debug_set_all(uint32_t flags, bool set) +{ + DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set); + + /* If all modes have been turned off, don't preserve options. */ + if (!DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_ALL)) + DEBUG_CLEAR(&ted_state_g.dbg); + + return 0; +} + +/** + * Help fn to show ted related configuration + * + * @param vty + * + * @return Status + */ +uint32_t path_ted_config_write(struct vty *vty) +{ + + if (ted_state_g.enabled) { + vty_out(vty, " mpls-te on\n"); + switch (ted_state_g.import) { + case IMPORT_ISIS: + vty_out(vty, " mpls-te import isis\n"); + break; + case IMPORT_OSPFv2: + vty_out(vty, " mpls-te import ospfv2\n"); + break; + case IMPORT_OSPFv3: + vty_out(vty, " mpls-te import ospfv3\n"); + break; + default: + break; + } + } + return 0; +} + +/** + * Register the fn's for CLI and hook for config show + * + * @param void + * + */ +static void path_ted_register_vty(void) +{ + install_element(VIEW_NODE, &show_pathd_ted_db_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd); + + install_element(CONFIG_NODE, &debug_path_ted_cmd); + install_element(ENABLE_NODE, &debug_path_ted_cmd); + + hook_register(nb_client_debug_config_write, + path_ted_cli_debug_config_write); + hook_register(nb_client_debug_set_all, path_ted_cli_debug_set_all); +} + +/** + * UnRegister the fn's for CLI and hook for config show + * + * @param void + * + */ +static void path_ted_unregister_vty(void) +{ + uninstall_element(VIEW_NODE, &show_pathd_ted_db_cmd); + uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd); + uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd); + uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd); + uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd); +} + +/** + * Ask igp for a complete TED so far + * + * @param void + * + * @return zclient status + */ +enum zclient_send_status path_ted_link_state_sync(void) +{ + enum zclient_send_status status; + + status = ls_request_sync(zclient); + if (status == -1) { + PATH_TED_ERROR( + "%s: PATHD-TED: Opaque error asking for TED sync ", + __func__); + return status; + } else { + PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ", + __func__); + } + thread_add_timer(ted_state_g.main, path_ted_timer_handler_sync, + &ted_state_g, ted_state_g.link_state_delay_interval, + &ted_state_g.t_link_state_sync); + + return status; +} + +/** + * Timer cb for check link state sync + * + * @param thread Current thread + * + * @return status + */ +int path_ted_timer_handler_sync(struct thread *thread) +{ + /* data unpacking */ + struct ted_state *data = THREAD_ARG(thread); + + assert(data != NULL); + /* Retry the sync */ + return path_ted_link_state_sync(); +} + +/** + * refresg segment list and create timer to keep up updated + * + * @param void + * + * @return status + */ +int path_ted_segment_list_refresh(void) +{ + int status = 0; + + path_ted_timer_refresh_cancel(); + thread_add_timer(ted_state_g.main, path_ted_timer_handler_refresh, + &ted_state_g, + ted_state_g.segment_list_refresh_interval, + &ted_state_g.t_segment_list_refresh); + + return status; +} + +/** + * Timer cb for refreshing sid in segment lists + * + * @param void + * + * @return status + */ +int path_ted_timer_handler_refresh(struct thread *thread) +{ + if (!path_ted_is_initialized()) + return MPLS_LABEL_NONE; + + PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__); + /* data unpacking */ + struct ted_state *data = THREAD_ARG(thread); + + assert(data != NULL); + + srte_policy_update_ted_sid(); + return 0; +} + +/** + * Cancel sync timer + * + * @param void + * + * @return void status + */ +void path_ted_timer_sync_cancel(void) +{ + if (ted_state_g.t_link_state_sync != NULL) { + thread_cancel(&ted_state_g.t_link_state_sync); + ted_state_g.t_link_state_sync = NULL; + } +} + +/** + * Cancel refresh timer + * + * @param void + * + * @return void status + */ +void path_ted_timer_refresh_cancel(void) +{ + if (ted_state_g.t_segment_list_refresh != NULL) { + thread_cancel(&ted_state_g.t_segment_list_refresh); + ted_state_g.t_segment_list_refresh = NULL; + } +} + +/** + * Check which igp is configured + * + * @param igp who want to check against config- + * + * @return status + */ +uint32_t path_ted_get_current_igp(uint32_t igp) +{ + switch (igp) { + case ISIS_L1: + case ISIS_L2: + if (ted_state_g.import != IMPORT_ISIS) { + PATH_TED_ERROR( + "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ", + __func__, + PATH_TED_IGP_PRINT(ted_state_g.import), + LS_IGP_PRINT(igp)); + return 1; + } + break; + case OSPFv2: + if (ted_state_g.import != IMPORT_OSPFv2) { + PATH_TED_ERROR( + "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ", + __func__, + PATH_TED_IGP_PRINT(ted_state_g.import), + LS_IGP_PRINT(igp)); + return 1; + } + break; + case STATIC: + break; + } + return 0; +} diff --git a/pathd/path_ted.h b/pathd/path_ted.h new file mode 100644 index 000000000..c6897b152 --- /dev/null +++ b/pathd/path_ted.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2020 Volta Networks, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#ifndef _PATH_TED_H +#define _PATH_TED_H + +#ifdef __cplusplus + +extern "C" { +#endif + +#include <zebra.h> + +#include <stdbool.h> + +#include <debug.h> +#include "linklist.h" +#include "log.h" +#include "command.h" +#include "stream.h" +#include "prefix.h" +#include "zclient.h" +#include "link_state.h" + +extern struct ted_state ted_state_g; +#define TIMER_RETRY_DELAY 5 /* Timeout in seconds between ls sync request */ +#define TED_KEY 1 +#define TED_ASN 1 +#define TED_NAME "PATHD TED" + +enum igp_import { + IMPORT_UNKNOWN = 0, + IMPORT_ISIS, + IMPORT_OSPFv2, + IMPORT_OSPFv3 +}; +struct ted_state { + struct thread_master *main; + /* Status of TED: enable or disable */ + bool enabled; + /* From which igp is going to receive data */ + enum igp_import import; + /* The TED itself as in link_state.h */ + struct ls_ted *ted; + /* Timer for ted sync */ + struct thread *t_link_state_sync; + /* Timer for refresh sid in segment list */ + struct thread *t_segment_list_refresh; + /* delay interval in seconds */ + uint32_t link_state_delay_interval; + /* delay interval refresh in seconds */ + uint32_t segment_list_refresh_interval; + struct debug dbg; +}; +/* Debug flags. */ +#define PATH_TED_DEBUG_BASIC 0x01 +#define PATH_TED_DEBUG(fmt, ...) \ + do { \ + if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \ + DEBUGD(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \ + } while (0) + +#define PATH_TED_ERROR(fmt, ...) \ + do { \ + if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \ + DEBUGE(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \ + } while (0) +#define PATH_TED_WARN(fmt, ...) \ + do { \ + if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \ + DEBUGW(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \ + } while (0) +#define PATH_TED_INFO(fmt, ...) \ + do { \ + if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \ + DEBUGI(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \ + } while (0) + +/* TED management functions */ +bool path_ted_is_initialized(void); +void path_ted_init(struct thread_master *master); +uint32_t path_ted_teardown(void); +void path_ted_timer_sync_cancel(void); +void path_ted_timer_refresh_cancel(void); +int path_ted_segment_list_refresh(void); + +/* TED configuration functions */ +uint32_t path_ted_config_write(struct vty *vty); + +/* TED util functions */ +/* clang-format off */ +#define LS_MSG_EVENT_PRINT(event) event == LS_MSG_EVENT_ADD?"add"\ + : event == LS_MSG_EVENT_DELETE?"del"\ + : event == LS_MSG_EVENT_UPDATE?"upd"\ + : event == LS_MSG_EVENT_SYNC?"syn"\ + : event == LS_MSG_EVENT_SYNC?"und" : "none" +#define LS_MSG_TYPE_PRINT(type) type == LS_MSG_TYPE_NODE?"node"\ + : type == LS_MSG_TYPE_ATTRIBUTES?"att"\ + : type == LS_MSG_TYPE_PREFIX?"pre" : "none" +#define LS_IGP_PRINT(type) type == ISIS_L1?"ISIS_L1"\ + : type == ISIS_L2?"ISIS_L2"\ + : type == DIRECT?"DIRECT"\ + : type == STATIC?"STATIC"\ + : type == OSPFv2?"OSPFv2" : "none" +#define PATH_TED_IGP_PRINT(type) type == IMPORT_OSPFv2?"OSPFv2"\ + : type == IMPORT_OSPFv3?"OSPFv3"\ + : type == IMPORT_ISIS?"ISIS" : "none" +/* clang-format on */ + + +uint32_t path_ted_get_current_igp(uint32_t); +/* TED Query functions */ + +/* + * Type of queries from draft-ietf-spring-segment-routing-policy-07 for types + * f,c,e + */ + +/** + * Search for sid based in prefix and optional algo + * + * @param prefix Net prefix to resolv + * @param algo Algorithm for link state + * + * @return sid of attribute + */ +uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo); + +/** + * Search for sid based in prefix and interface id + * + * @param prefix Net prefix to resolv + * @param iface_id The interface id + * + * @return sid of attribute + */ +uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id); + +/** + * Search for sid based in local, remote pair + * + * @param local local ip of attribute + * @param remote remote ip of attribute + * + * @return sid of attribute + */ +uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote); + + +/** + * Handle the received opaque msg + * + * @param msg Holds the ted data + * + * @return sid of attribute + */ +uint32_t path_ted_rcvd_message(struct ls_message *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* _PATH_TED_H */ diff --git a/pathd/path_zebra.c b/pathd/path_zebra.c index 8c9357460..53d834f36 100644 --- a/pathd/path_zebra.c +++ b/pathd/path_zebra.c @@ -32,9 +32,14 @@ #include "typesafe.h" #include "pathd/pathd.h" +#include "pathd/path_ted.h" #include "pathd/path_zebra.h" +#include "lib/command.h" +#include "lib/link_state.h" -static struct zclient *zclient; +static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS); + +struct zclient *zclient; static struct zclient *zclient_sync; /* Global Variables */ @@ -267,6 +272,54 @@ static void path_zebra_label_manager_connect(void) } } +static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS) +{ + int ret = 0; + struct stream *s; + struct zapi_opaque_msg info; + + s = zclient->ibuf; + + if (zclient_opaque_decode(s, &info) != 0) + return -1; + + switch (info.type) { + case LINK_STATE_UPDATE: + case LINK_STATE_SYNC: + /* Start receiving ls data so cancel request sync timer */ + path_ted_timer_sync_cancel(); + + struct ls_message *msg = ls_parse_msg(s); + + if (msg) { + zlog_debug("%s: [rcv ted] ls (%s) msg (%s)-(%s) !", + __func__, + info.type == LINK_STATE_UPDATE + ? "LINK_STATE_UPDATE" + : "LINK_STATE_SYNC", + LS_MSG_TYPE_PRINT(msg->type), + LS_MSG_EVENT_PRINT(msg->event)); + } else { + zlog_err( + "%s: [rcv ted] Could not parse LinkState stream message.", + __func__); + return -1; + } + + ret = path_ted_rcvd_message(msg); + ls_delete_msg(msg); + /* Update local configuration after process update. */ + path_ted_segment_list_refresh(); + break; + default: + zlog_debug("%s: [rcv ted] unknown opaque event (%d) !", + __func__, info.type); + break; + } + + return ret; +} + /** * Initializes Zebra asynchronous connection. * @@ -283,6 +336,7 @@ void path_zebra_init(struct thread_master *master) zclient->zebra_connected = path_zebra_connected; zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status; zclient->router_id_update = path_zebra_router_id_update; + zclient->opaque_msg_handler = path_zebra_opaque_msg_handler; /* Initialize special zclient for synchronous message exchanges. */ zclient_sync = zclient_new(master, &options); diff --git a/pathd/pathd.c b/pathd/pathd.c index ae8218631..62785333e 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -26,6 +26,7 @@ #include "pathd/pathd.h" #include "pathd/path_zebra.h" #include "pathd/path_debug.h" +#include "pathd/path_ted.h" #define HOOK_DELAY 3 @@ -329,6 +330,14 @@ srte_policy_best_candidate(const struct srte_policy *policy) return NULL; } +void srte_clean_zebra(void) +{ + struct srte_policy *policy, *safe_pol; + + RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) + srte_policy_del(policy); +} + /** * Apply changes defined by setting the policies, candidate paths * and segment lists modification flags NEW, MODIFIED and DELETED. @@ -1024,6 +1033,12 @@ const char *srte_origin2str(enum srte_protocol_origin origin) } } +void pathd_shutdown(void) +{ + path_ted_teardown(); + srte_clean_zebra(); +} + void trigger_pathd_candidate_created(struct srte_candidate *candidate) { /* The hook is called asynchronously to let the PCEP module diff --git a/pathd/pathd.h b/pathd/pathd.h index 9c4d256ce..6a5fdb3c2 100644 --- a/pathd/pathd.h +++ b/pathd/pathd.h @@ -372,6 +372,7 @@ struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint); void srte_policy_update_binding_sid(struct srte_policy *policy, uint32_t binding_sid); void srte_apply_changes(void); +void srte_clean_zebra(void); void srte_policy_apply_changes(struct srte_policy *policy); struct srte_candidate *srte_candidate_add(struct srte_policy *policy, uint32_t preference); @@ -408,6 +409,7 @@ srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index); void srte_candidate_status_update(struct srte_candidate *candidate, int status); void srte_candidate_unset_segment_list(const char *originator, bool force); const char *srte_origin2str(enum srte_protocol_origin origin); +void pathd_shutdown(void); /* path_cli.c */ void path_cli_init(void); diff --git a/pathd/subdir.am b/pathd/subdir.am index 0666e8d3c..693afabb3 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -5,7 +5,10 @@ if PATHD noinst_LIBRARIES += pathd/libpath.a sbin_PROGRAMS += pathd/pathd -vtysh_scan += pathd/path_cli.c +vtysh_scan += \ + pathd/path_cli.c \ + pathd/path_ted.c \ + #end vtysh_daemons += pathd # TODO add man page #man8 += $(MANBUILD)/pathd.8 @@ -24,6 +27,7 @@ pathd_libpath_a_SOURCES = \ pathd/path_nb.c \ pathd/path_nb_config.c \ pathd/path_nb_state.c \ + pathd/path_ted.c \ pathd/path_zebra.c \ pathd/pathd.c \ # end @@ -31,6 +35,7 @@ pathd_libpath_a_SOURCES = \ clippy_scan += \ pathd/path_cli.c \ pathd/path_pcep_cli.c \ + pathd/path_ted.c \ # end noinst_HEADERS += \ @@ -44,6 +49,7 @@ noinst_HEADERS += \ pathd/path_pcep_lib.h \ pathd/path_pcep_config.h \ pathd/path_pcep_pcc.h \ + pathd/path_ted.h \ pathd/path_zebra.h \ pathd/pathd.h \ # end |