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 #ifndef VTYSH_EXTRACT_PL
33 #include "pathd/path_ted_clippy.c"
36 static struct ls_ted
*path_ted_create_ted(void);
37 static void path_ted_register_vty(void);
38 static void path_ted_unregister_vty(void);
39 static uint32_t path_ted_start_importing_igp(const char *daemon_str
);
40 static uint32_t path_ted_stop_importing_igp(void);
41 static enum zclient_send_status
path_ted_link_state_sync(void);
42 static int path_ted_timer_handler_sync(struct thread
*thread
);
43 static int path_ted_timer_handler_refresh(struct thread
*thread
);
44 static int path_ted_cli_debug_config_write(struct vty
*vty
);
45 static int path_ted_cli_debug_set_all(uint32_t flags
, bool set
);
47 extern struct zclient
*zclient
;
49 struct ted_state ted_state_g
= {};
52 * path_path_ted public API function implementations
55 void path_ted_init(struct thread_master
*master
)
57 ted_state_g
.main
= master
;
58 ted_state_g
.link_state_delay_interval
= TIMER_RETRY_DELAY
;
59 ted_state_g
.segment_list_refresh_interval
= TIMER_RETRY_DELAY
;
60 path_ted_register_vty();
61 path_ted_segment_list_refresh();
64 uint32_t path_ted_teardown(void)
66 PATH_TED_DEBUG("%s : TED [%p]", __func__
, ted_state_g
.ted
);
67 path_ted_unregister_vty();
68 path_ted_stop_importing_igp();
69 ls_ted_del_all(ted_state_g
.ted
);
70 path_ted_timer_sync_cancel();
71 path_ted_timer_refresh_cancel();
76 * Set all needed to receive igp data.
81 uint32_t path_ted_start_importing_igp(const char *daemon_str
)
85 if (strcmp(daemon_str
, "ospfv2") == 0)
86 ted_state_g
.import
= IMPORT_OSPFv2
;
87 else if (strcmp(daemon_str
, "ospfv3") == 0) {
88 ted_state_g
.import
= IMPORT_UNKNOWN
;
90 } else if (strcmp(daemon_str
, "isis") == 0)
91 ted_state_g
.import
= IMPORT_ISIS
;
93 ted_state_g
.import
= IMPORT_UNKNOWN
;
97 if (ls_register(zclient
, false /*client*/) != 0) {
98 PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State",
100 ted_state_g
.import
= IMPORT_UNKNOWN
;
103 if (path_ted_link_state_sync() != -1) {
104 PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON",
106 PATH_TED_IGP_PRINT(ted_state_g
.import
));
108 PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF",
110 PATH_TED_IGP_PRINT(ted_state_g
.import
));
111 ted_state_g
.import
= IMPORT_UNKNOWN
;
118 * Unset all needed to receive igp data.
123 uint32_t path_ted_stop_importing_igp(void)
127 if (ted_state_g
.import
!= IMPORT_UNKNOWN
) {
128 if (ls_unregister(zclient
, false /*client*/) != 0) {
130 "%s: PATHD-TED: Unable to unregister Link State",
134 ted_state_g
.import
= IMPORT_UNKNOWN
;
135 PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF",
138 path_ted_timer_sync_cancel();
143 * Check for ted status
148 bool path_ted_is_initialized(void)
150 if (ted_state_g
.ted
== NULL
) {
151 PATH_TED_WARN("PATHD TED ls_ted not initialized");
159 * Creates an empty ted
163 * @return Ptr to ted or NULL
165 struct ls_ted
*path_ted_create_ted()
167 struct ls_ted
*ted
= ls_ted_new(TED_KEY
, TED_NAME
, TED_ASN
);
170 PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]",
171 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
173 PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]",
174 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
180 uint32_t path_ted_rcvd_message(struct ls_message
*msg
)
182 if (!path_ted_is_initialized())
186 PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ",
191 if (path_ted_get_current_igp(msg
->data
.node
->adv
.origin
))
195 case LS_MSG_TYPE_NODE
:
196 ls_msg2vertex(ted_state_g
.ted
, msg
, true /*hard delete*/);
199 case LS_MSG_TYPE_ATTRIBUTES
:
200 ls_msg2edge(ted_state_g
.ted
, msg
, true /*ĥard delete*/);
203 case LS_MSG_TYPE_PREFIX
:
204 ls_msg2subnet(ted_state_g
.ted
, msg
, true /*hard delete*/);
209 "%s: [rcv ted] TED received unknown message type [%d]",
210 __func__
, msg
->type
);
216 uint32_t path_ted_query_type_f(struct ipaddr
*local
, struct ipaddr
*remote
)
218 uint32_t sid
= MPLS_LABEL_NONE
;
219 struct ls_edge
*edge
;
222 if (!path_ted_is_initialized())
223 return MPLS_LABEL_NONE
;
225 if (!local
|| !remote
)
226 return MPLS_LABEL_NONE
;
228 switch (local
->ipa_type
) {
230 /* We have local and remote ip */
231 /* so check all attributes in ted */
232 key
= ((uint64_t)ntohl(local
->ip
._v4_addr
.s_addr
)) & 0xffffffff;
233 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
235 if (edge
->attributes
->standard
.remote
.s_addr
236 == remote
->ip
._v4_addr
.s_addr
237 && CHECK_FLAG(edge
->attributes
->flags
,
239 sid
= edge
->attributes
->adj_sid
[0]
240 .sid
; /* from primary */
246 key
= (uint64_t)(local
->ip
._v6_addr
.s6_addr32
[0] & 0xffffffff)
247 | ((uint64_t)local
->ip
._v6_addr
.s6_addr32
[1] << 32);
248 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
250 if ((memcmp(&edge
->attributes
->standard
.remote6
,
251 &remote
->ip
._v6_addr
,
252 sizeof(remote
->ip
._v6_addr
))
253 && CHECK_FLAG(edge
->attributes
->flags
,
255 sid
= edge
->attributes
->adj_sid
[0]
256 .sid
; /* from primary */
268 uint32_t path_ted_query_type_c(struct prefix
*prefix
, uint8_t algo
)
270 uint32_t sid
= MPLS_LABEL_NONE
;
271 struct ls_subnet
*subnet
;
273 if (!path_ted_is_initialized())
274 return MPLS_LABEL_NONE
;
277 return MPLS_LABEL_NONE
;
279 switch (prefix
->family
) {
282 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
284 if ((CHECK_FLAG(subnet
->ls_pref
->flags
, LS_PREF_SR
))
285 && (subnet
->ls_pref
->sr
.algo
== algo
))
286 sid
= subnet
->ls_pref
->sr
.sid
;
296 uint32_t path_ted_query_type_e(struct prefix
*prefix
, uint32_t iface_id
)
298 uint32_t sid
= MPLS_LABEL_NONE
;
299 struct ls_subnet
*subnet
;
300 struct listnode
*lst_node
;
301 struct ls_edge
*edge
;
303 if (!path_ted_is_initialized())
304 return MPLS_LABEL_NONE
;
307 return MPLS_LABEL_NONE
;
309 switch (prefix
->family
) {
312 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
313 if (subnet
&& subnet
->vertex
314 && subnet
->vertex
->outgoing_edges
) {
315 /* from the vertex linked in subnet */
316 /* loop over outgoing edges */
317 for (ALL_LIST_ELEMENTS_RO(
318 subnet
->vertex
->outgoing_edges
, lst_node
,
320 /* and look for ifaceid */
321 /* so get sid of attribute */
322 if (CHECK_FLAG(edge
->attributes
->flags
,
324 && edge
->attributes
->standard
.local_id
326 sid
= subnet
->ls_pref
->sr
.sid
;
339 DEFPY (debug_path_ted
,
341 "[no] debug pathd mpls-te",
347 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
348 bool no_debug
= (no
!= NULL
);
350 DEBUG_MODE_SET(&ted_state_g
.dbg
, mode
, !no
);
351 DEBUG_FLAGS_SET(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
, !no_debug
);
356 * Followings are vty command functions.
358 /* clang-format off */
363 "Enable the TE database (TED) functionality\n")
364 /* clang-format on */
367 if (ted_state_g
.enabled
) {
368 PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__
);
372 ted_state_g
.ted
= path_ted_create_ted();
373 ted_state_g
.enabled
= true;
374 PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__
);
379 /* clang-format off */
385 "Disable the TE Database functionality\n")
386 /* clang-format on */
388 if (ted_state_g
.enabled
) {
389 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__
);
394 ls_ted_del_all(ted_state_g
.ted
);
395 ted_state_g
.enabled
= false;
396 PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__
);
397 ted_state_g
.import
= IMPORT_UNKNOWN
;
398 if (ls_unregister(zclient
, false /*client*/) != 0) {
399 vty_out(vty
, "Unable to unregister Link State\n");
406 /* clang-format off */
407 DEFPY(path_ted_import
,
409 "mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
410 "Enable the TE database (TED) fill with remote igp data\n"
415 /* clang-format on */
418 if (ted_state_g
.enabled
)
419 if (path_ted_start_importing_igp(import_daemon
)) {
420 vty_out(vty
, "Unable to start importing\n");
426 /* clang-format off */
427 DEFUN (no_path_ted_import
,
428 no_path_ted_import_cmd
,
432 "Disable the TE Database fill with remote igp data\n")
433 /* clang-format on */
436 if (ted_state_g
.import
) {
437 if (path_ted_stop_importing_igp()) {
438 vty_out(vty
, "Unable to stop importing\n");
442 "%s: PATHD-TED: Importing igp data already OFF",
449 /* clang-format off */
450 DEFPY (show_pahtd_ted_db
,
451 show_pathd_ted_db_cmd
,
452 "show pathd ted database <verbose|json>$ver_json ",
458 "Show complete received TED database\n")
459 /* clang-format on */
461 bool st_json
= false;
462 json_object
*json
= NULL
;
464 if (!ted_state_g
.enabled
) {
465 vty_out(vty
, "PATHD TED database is not enabled\n");
468 if (strcmp(ver_json
, "json") == 0) {
470 json
= json_object_new_object();
472 /* Show the complete TED */
473 ls_show_ted(ted_state_g
.ted
, vty
, json
, !st_json
);
476 json_object_to_json_string_ext(
477 json
, JSON_C_TO_STRING_PRETTY
));
478 json_object_free(json
);
484 * Config Write functions
487 int path_ted_cli_debug_config_write(struct vty
*vty
)
489 if (DEBUG_MODE_CHECK(&ted_state_g
.dbg
, DEBUG_MODE_CONF
)) {
490 if (DEBUG_FLAGS_CHECK(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
))
491 vty_out(vty
, "debug pathd mpls-te\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 int path_ted_timer_handler_sync(struct thread
*thread
)
612 struct ted_state
*data
= THREAD_ARG(thread
);
614 assert(data
!= NULL
);
616 return 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 int path_ted_timer_handler_refresh(struct thread
*thread
)
648 if (!path_ted_is_initialized())
649 return MPLS_LABEL_NONE
;
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();
666 * @return void status
668 void path_ted_timer_sync_cancel(void)
670 if (ted_state_g
.t_link_state_sync
!= NULL
) {
671 thread_cancel(&ted_state_g
.t_link_state_sync
);
672 ted_state_g
.t_link_state_sync
= NULL
;
677 * Cancel refresh timer
681 * @return void status
683 void path_ted_timer_refresh_cancel(void)
685 if (ted_state_g
.t_segment_list_refresh
!= NULL
) {
686 thread_cancel(&ted_state_g
.t_segment_list_refresh
);
687 ted_state_g
.t_segment_list_refresh
= NULL
;
692 * Check which igp is configured
694 * @param igp who want to check against config-
698 uint32_t path_ted_get_current_igp(uint32_t igp
)
703 if (ted_state_g
.import
!= IMPORT_ISIS
) {
705 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
707 PATH_TED_IGP_PRINT(ted_state_g
.import
),
713 if (ted_state_g
.import
!= IMPORT_OSPFv2
) {
715 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
717 PATH_TED_IGP_PRINT(ted_state_g
.import
),