summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Garcia <javier.garcia@voltanet.io>2021-04-22 15:52:27 +0200
committerJavier Garcia <javier.garcia@voltanet.io>2021-05-10 12:36:46 +0200
commit75c69d151c8e72e42dfb4b1966428e9cf79cb7f4 (patch)
tree240ecdf1e026387c787fa33fe8a716750525dd1a
parentMerge pull request #8639 from idryzhov/isis-new-bfd-lib (diff)
downloadfrr-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.c4
-rw-r--r--pathd/path_ted.c726
-rw-r--r--pathd/path_ted.h178
-rw-r--r--pathd/path_zebra.c56
-rw-r--r--pathd/pathd.c15
-rw-r--r--pathd/pathd.h2
-rw-r--r--pathd/subdir.am8
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