2 * Copyright (C) 2020 Volta Networks, Inc
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 #include "pathd/path_errors.h"
30 #include "pathd/path_ted.h"
32 #include "pathd/path_ted_clippy.c"
34 static struct ls_ted
*path_ted_create_ted(void);
35 static void path_ted_register_vty(void);
36 static void path_ted_unregister_vty(void);
37 static uint32_t path_ted_start_importing_igp(const char *daemon_str
);
38 static uint32_t path_ted_stop_importing_igp(void);
39 static enum zclient_send_status
path_ted_link_state_sync(void);
40 static void path_ted_timer_handler_sync(struct thread
*thread
);
41 static void path_ted_timer_handler_refresh(struct thread
*thread
);
42 static int path_ted_cli_debug_config_write(struct vty
*vty
);
43 static int path_ted_cli_debug_set_all(uint32_t flags
, bool set
);
45 extern struct zclient
*zclient
;
47 struct ted_state ted_state_g
= {};
50 * path_path_ted public API function implementations
53 void path_ted_init(struct thread_master
*master
)
55 ted_state_g
.main
= master
;
56 ted_state_g
.link_state_delay_interval
= TIMER_RETRY_DELAY
;
57 ted_state_g
.segment_list_refresh_interval
= TIMER_RETRY_DELAY
;
58 path_ted_register_vty();
59 path_ted_segment_list_refresh();
62 uint32_t path_ted_teardown(void)
64 PATH_TED_DEBUG("%s : TED [%p]", __func__
, ted_state_g
.ted
);
65 path_ted_unregister_vty();
66 path_ted_stop_importing_igp();
67 ls_ted_del_all(&ted_state_g
.ted
);
68 path_ted_timer_sync_cancel();
69 path_ted_timer_refresh_cancel();
74 * Set all needed to receive igp data.
79 uint32_t path_ted_start_importing_igp(const char *daemon_str
)
83 if (strcmp(daemon_str
, "ospfv2") == 0)
84 ted_state_g
.import
= IMPORT_OSPFv2
;
85 else if (strcmp(daemon_str
, "ospfv3") == 0) {
86 ted_state_g
.import
= IMPORT_UNKNOWN
;
88 } else if (strcmp(daemon_str
, "isis") == 0)
89 ted_state_g
.import
= IMPORT_ISIS
;
91 ted_state_g
.import
= IMPORT_UNKNOWN
;
95 if (ls_register(zclient
, false /*client*/) != 0) {
96 PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State",
98 ted_state_g
.import
= IMPORT_UNKNOWN
;
101 if (path_ted_link_state_sync() != -1) {
102 PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON",
104 PATH_TED_IGP_PRINT(ted_state_g
.import
));
106 PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF",
108 PATH_TED_IGP_PRINT(ted_state_g
.import
));
109 ted_state_g
.import
= IMPORT_UNKNOWN
;
116 * Unset all needed to receive igp data.
121 uint32_t path_ted_stop_importing_igp(void)
125 if (ted_state_g
.import
!= IMPORT_UNKNOWN
) {
126 if (ls_unregister(zclient
, false /*client*/) != 0) {
128 "%s: PATHD-TED: Unable to unregister Link State",
132 ted_state_g
.import
= IMPORT_UNKNOWN
;
133 PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF",
136 path_ted_timer_sync_cancel();
141 * Check for ted status
146 bool path_ted_is_initialized(void)
148 if (ted_state_g
.ted
== NULL
) {
149 PATH_TED_WARN("PATHD TED ls_ted not initialized");
157 * Creates an empty ted
161 * @return Ptr to ted or NULL
163 struct ls_ted
*path_ted_create_ted(void)
165 struct ls_ted
*ted
= ls_ted_new(TED_KEY
, TED_NAME
, TED_ASN
);
168 PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]",
169 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
171 PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]",
172 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
178 uint32_t path_ted_rcvd_message(struct ls_message
*msg
)
180 if (!path_ted_is_initialized())
184 PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ",
189 if (path_ted_get_current_igp(msg
->data
.node
->adv
.origin
))
193 case LS_MSG_TYPE_NODE
:
194 ls_msg2vertex(ted_state_g
.ted
, msg
, true /*hard delete*/);
197 case LS_MSG_TYPE_ATTRIBUTES
:
198 ls_msg2edge(ted_state_g
.ted
, msg
, true /*ĥard delete*/);
201 case LS_MSG_TYPE_PREFIX
:
202 ls_msg2subnet(ted_state_g
.ted
, msg
, true /*hard delete*/);
207 "%s: [rcv ted] TED received unknown message type [%d]",
208 __func__
, msg
->type
);
214 uint32_t path_ted_query_type_f(struct ipaddr
*local
, struct ipaddr
*remote
)
216 uint32_t sid
= MPLS_LABEL_NONE
;
217 struct ls_edge
*edge
;
220 if (!path_ted_is_initialized())
221 return MPLS_LABEL_NONE
;
223 if (!local
|| !remote
)
224 return MPLS_LABEL_NONE
;
226 switch (local
->ipa_type
) {
228 /* We have local and remote ip */
229 /* so check all attributes in ted */
230 key
= ((uint64_t)ntohl(local
->ip
._v4_addr
.s_addr
)) & 0xffffffff;
231 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
233 if (edge
->attributes
->standard
.remote
.s_addr
234 == remote
->ip
._v4_addr
.s_addr
235 && CHECK_FLAG(edge
->attributes
->flags
,
237 sid
= edge
->attributes
->adj_sid
[0]
238 .sid
; /* from primary */
244 key
= (uint64_t)ntohl(local
->ip
._v6_addr
.s6_addr32
[2]) << 32 |
245 (uint64_t)ntohl(local
->ip
._v6_addr
.s6_addr32
[3]);
246 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
248 if ((0 == memcmp(&edge
->attributes
->standard
.remote6
,
249 &remote
->ip
._v6_addr
,
250 sizeof(remote
->ip
._v6_addr
)) &&
251 CHECK_FLAG(edge
->attributes
->flags
,
252 LS_ATTR_ADJ_SID6
))) {
253 sid
= edge
->attributes
->adj_sid
[ADJ_PRI_IPV6
]
254 .sid
; /* from primary */
266 uint32_t path_ted_query_type_c(struct prefix
*prefix
, uint8_t algo
)
268 uint32_t sid
= MPLS_LABEL_NONE
;
269 struct ls_subnet
*subnet
;
271 if (!path_ted_is_initialized())
272 return MPLS_LABEL_NONE
;
275 return MPLS_LABEL_NONE
;
277 switch (prefix
->family
) {
280 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
282 if ((CHECK_FLAG(subnet
->ls_pref
->flags
, LS_PREF_SR
))
283 && (subnet
->ls_pref
->sr
.algo
== algo
))
284 sid
= subnet
->ls_pref
->sr
.sid
;
294 uint32_t path_ted_query_type_e(struct prefix
*prefix
, uint32_t iface_id
)
296 uint32_t sid
= MPLS_LABEL_NONE
;
297 struct ls_subnet
*subnet
;
298 struct listnode
*lst_node
;
299 struct ls_edge
*edge
;
301 if (!path_ted_is_initialized())
302 return MPLS_LABEL_NONE
;
305 return MPLS_LABEL_NONE
;
307 switch (prefix
->family
) {
310 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
311 if (subnet
&& subnet
->vertex
312 && subnet
->vertex
->outgoing_edges
) {
313 /* from the vertex linked in subnet */
314 /* loop over outgoing edges */
315 for (ALL_LIST_ELEMENTS_RO(
316 subnet
->vertex
->outgoing_edges
, lst_node
,
318 /* and look for ifaceid */
319 /* so get sid of attribute */
320 if (CHECK_FLAG(edge
->attributes
->flags
,
322 && edge
->attributes
->standard
.local_id
324 sid
= subnet
->ls_pref
->sr
.sid
;
337 DEFPY (debug_path_ted
,
339 "[no] debug pathd mpls-te",
345 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
346 bool no_debug
= (no
!= NULL
);
348 DEBUG_MODE_SET(&ted_state_g
.dbg
, mode
, !no
);
349 DEBUG_FLAGS_SET(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
, !no_debug
);
354 * Following are vty command functions.
356 /* clang-format off */
361 "Enable the TE database (TED) functionality\n")
362 /* clang-format on */
365 if (ted_state_g
.enabled
) {
366 PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__
);
370 ted_state_g
.ted
= path_ted_create_ted();
371 ted_state_g
.enabled
= true;
372 PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__
);
377 /* clang-format off */
383 "Disable the TE Database functionality\n")
384 /* clang-format on */
386 if (!ted_state_g
.enabled
) {
387 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__
);
392 ls_ted_del_all(&ted_state_g
.ted
);
393 ted_state_g
.enabled
= false;
394 PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__
);
395 ted_state_g
.import
= IMPORT_UNKNOWN
;
396 if (ls_unregister(zclient
, false /*client*/) != 0) {
397 vty_out(vty
, "Unable to unregister Link State\n");
404 /* clang-format off */
405 DEFPY(path_ted_import
,
407 "mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
408 "Enable the TE database (TED) fill with remote igp data\n"
413 /* clang-format on */
416 if (ted_state_g
.enabled
)
417 if (path_ted_start_importing_igp(import_daemon
)) {
418 vty_out(vty
, "Unable to start importing\n");
424 /* clang-format off */
425 DEFUN (no_path_ted_import
,
426 no_path_ted_import_cmd
,
430 "Disable the TE Database fill with remote igp data\n")
431 /* clang-format on */
434 if (ted_state_g
.import
) {
435 if (path_ted_stop_importing_igp()) {
436 vty_out(vty
, "Unable to stop importing\n");
440 "%s: PATHD-TED: Importing igp data already OFF",
447 /* clang-format off */
448 DEFPY (show_pathd_ted_db
,
449 show_pathd_ted_db_cmd
,
450 "show pathd ted database <verbose|json>$ver_json ",
456 "Show complete received TED database\n")
457 /* clang-format on */
459 bool st_json
= false;
460 json_object
*json
= NULL
;
462 if (!ted_state_g
.enabled
) {
463 vty_out(vty
, "Traffic Engineering database is not enabled\n");
466 if (strcmp(ver_json
, "json") == 0) {
468 json
= json_object_new_object();
470 /* Show the complete TED */
471 ls_show_ted(ted_state_g
.ted
, vty
, json
, !st_json
);
478 * Config Write functions
481 int path_ted_cli_debug_config_write(struct vty
*vty
)
483 if (DEBUG_MODE_CHECK(&ted_state_g
.dbg
, DEBUG_MODE_CONF
)) {
484 if (DEBUG_FLAGS_CHECK(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
))
485 vty_out(vty
, "debug pathd mpls-te\n");
491 void path_ted_show_debugging(struct vty
*vty
)
493 if (DEBUG_FLAGS_CHECK(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
))
494 vty_out(vty
, " Path TED debugging is on\n");
497 int path_ted_cli_debug_set_all(uint32_t flags
, bool set
)
499 DEBUG_FLAGS_SET(&ted_state_g
.dbg
, flags
, set
);
501 /* If all modes have been turned off, don't preserve options. */
502 if (!DEBUG_MODE_CHECK(&ted_state_g
.dbg
, DEBUG_MODE_ALL
))
503 DEBUG_CLEAR(&ted_state_g
.dbg
);
509 * Help fn to show ted related configuration
515 uint32_t path_ted_config_write(struct vty
*vty
)
518 if (ted_state_g
.enabled
) {
519 vty_out(vty
, " mpls-te on\n");
520 switch (ted_state_g
.import
) {
522 vty_out(vty
, " mpls-te import isis\n");
525 vty_out(vty
, " mpls-te import ospfv2\n");
528 vty_out(vty
, " mpls-te import ospfv3\n");
538 * Register the fn's for CLI and hook for config show
543 static void path_ted_register_vty(void)
545 install_element(VIEW_NODE
, &show_pathd_ted_db_cmd
);
546 install_element(SR_TRAFFIC_ENG_NODE
, &path_ted_on_cmd
);
547 install_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_cmd
);
548 install_element(SR_TRAFFIC_ENG_NODE
, &path_ted_import_cmd
);
549 install_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_import_cmd
);
551 install_element(CONFIG_NODE
, &debug_path_ted_cmd
);
552 install_element(ENABLE_NODE
, &debug_path_ted_cmd
);
554 hook_register(nb_client_debug_config_write
,
555 path_ted_cli_debug_config_write
);
556 hook_register(nb_client_debug_set_all
, path_ted_cli_debug_set_all
);
560 * UnRegister the fn's for CLI and hook for config show
565 static void path_ted_unregister_vty(void)
567 uninstall_element(VIEW_NODE
, &show_pathd_ted_db_cmd
);
568 uninstall_element(SR_TRAFFIC_ENG_NODE
, &path_ted_on_cmd
);
569 uninstall_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_cmd
);
570 uninstall_element(SR_TRAFFIC_ENG_NODE
, &path_ted_import_cmd
);
571 uninstall_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_import_cmd
);
575 * Ask igp for a complete TED so far
579 * @return zclient status
581 enum zclient_send_status
path_ted_link_state_sync(void)
583 enum zclient_send_status status
;
585 status
= ls_request_sync(zclient
);
588 "%s: PATHD-TED: Opaque error asking for TED sync ",
592 PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
595 thread_add_timer(ted_state_g
.main
, path_ted_timer_handler_sync
,
596 &ted_state_g
, ted_state_g
.link_state_delay_interval
,
597 &ted_state_g
.t_link_state_sync
);
603 * Timer cb for check link state sync
605 * @param thread Current thread
609 void path_ted_timer_handler_sync(struct thread
*thread
)
612 struct ted_state
*data
= THREAD_ARG(thread
);
614 assert(data
!= NULL
);
616 path_ted_link_state_sync();
620 * refresg segment list and create timer to keep up updated
626 int path_ted_segment_list_refresh(void)
630 path_ted_timer_refresh_cancel();
631 thread_add_timer(ted_state_g
.main
, path_ted_timer_handler_refresh
,
633 ted_state_g
.segment_list_refresh_interval
,
634 &ted_state_g
.t_segment_list_refresh
);
640 * Timer cb for refreshing sid in segment lists
646 void path_ted_timer_handler_refresh(struct thread
*thread
)
648 if (!path_ted_is_initialized())
651 PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__
);
653 struct ted_state
*data
= THREAD_ARG(thread
);
655 assert(data
!= NULL
);
657 srte_policy_update_ted_sid();
665 * @return void status
667 void path_ted_timer_sync_cancel(void)
669 if (ted_state_g
.t_link_state_sync
!= NULL
) {
670 thread_cancel(&ted_state_g
.t_link_state_sync
);
671 ted_state_g
.t_link_state_sync
= NULL
;
676 * Cancel refresh timer
680 * @return void status
682 void path_ted_timer_refresh_cancel(void)
684 if (ted_state_g
.t_segment_list_refresh
!= NULL
) {
685 thread_cancel(&ted_state_g
.t_segment_list_refresh
);
686 ted_state_g
.t_segment_list_refresh
= NULL
;
691 * Check which igp is configured
693 * @param igp who want to check against config-
697 uint32_t path_ted_get_current_igp(uint32_t igp
)
702 if (ted_state_g
.import
!= IMPORT_ISIS
) {
704 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
706 PATH_TED_IGP_PRINT(ted_state_g
.import
),
712 if (ted_state_g
.import
!= IMPORT_OSPFv2
) {
714 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
716 PATH_TED_IGP_PRINT(ted_state_g
.import
),