1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 Volta Networks, Inc
5 * You should have received a copy of the GNU Lesser General Public License
6 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 #include "pathd/path_errors.h"
21 #include "pathd/path_ted.h"
23 #include "pathd/path_ted_clippy.c"
25 static struct ls_ted
*path_ted_create_ted(void);
26 static void path_ted_register_vty(void);
27 static void path_ted_unregister_vty(void);
28 static uint32_t path_ted_start_importing_igp(const char *daemon_str
);
29 static uint32_t path_ted_stop_importing_igp(void);
30 static enum zclient_send_status
path_ted_link_state_sync(void);
31 static void path_ted_timer_handler_sync(struct thread
*thread
);
32 static void path_ted_timer_handler_refresh(struct thread
*thread
);
33 static int path_ted_cli_debug_config_write(struct vty
*vty
);
34 static int path_ted_cli_debug_set_all(uint32_t flags
, bool set
);
36 extern struct zclient
*zclient
;
38 struct ted_state ted_state_g
= {};
41 * path_path_ted public API function implementations
44 void path_ted_init(struct thread_master
*master
)
46 ted_state_g
.main
= master
;
47 ted_state_g
.link_state_delay_interval
= TIMER_RETRY_DELAY
;
48 ted_state_g
.segment_list_refresh_interval
= TIMER_RETRY_DELAY
;
49 path_ted_register_vty();
50 path_ted_segment_list_refresh();
53 uint32_t path_ted_teardown(void)
55 PATH_TED_DEBUG("%s : TED [%p]", __func__
, ted_state_g
.ted
);
56 path_ted_unregister_vty();
57 path_ted_stop_importing_igp();
58 ls_ted_del_all(&ted_state_g
.ted
);
59 path_ted_timer_sync_cancel();
60 path_ted_timer_refresh_cancel();
65 * Set all needed to receive igp data.
70 uint32_t path_ted_start_importing_igp(const char *daemon_str
)
74 if (strcmp(daemon_str
, "ospfv2") == 0)
75 ted_state_g
.import
= IMPORT_OSPFv2
;
76 else if (strcmp(daemon_str
, "ospfv3") == 0) {
77 ted_state_g
.import
= IMPORT_UNKNOWN
;
79 } else if (strcmp(daemon_str
, "isis") == 0)
80 ted_state_g
.import
= IMPORT_ISIS
;
82 ted_state_g
.import
= IMPORT_UNKNOWN
;
86 if (ls_register(zclient
, false /*client*/) != 0) {
87 PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State",
89 ted_state_g
.import
= IMPORT_UNKNOWN
;
92 if (path_ted_link_state_sync() != -1) {
93 PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON",
95 PATH_TED_IGP_PRINT(ted_state_g
.import
));
97 PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF",
99 PATH_TED_IGP_PRINT(ted_state_g
.import
));
100 ted_state_g
.import
= IMPORT_UNKNOWN
;
107 * Unset all needed to receive igp data.
112 uint32_t path_ted_stop_importing_igp(void)
116 if (ted_state_g
.import
!= IMPORT_UNKNOWN
) {
117 if (ls_unregister(zclient
, false /*client*/) != 0) {
119 "%s: PATHD-TED: Unable to unregister Link State",
123 ted_state_g
.import
= IMPORT_UNKNOWN
;
124 PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF",
127 path_ted_timer_sync_cancel();
132 * Check for ted status
137 bool path_ted_is_initialized(void)
139 if (ted_state_g
.ted
== NULL
) {
140 PATH_TED_WARN("PATHD TED ls_ted not initialized");
148 * Creates an empty ted
152 * @return Ptr to ted or NULL
154 struct ls_ted
*path_ted_create_ted(void)
156 struct ls_ted
*ted
= ls_ted_new(TED_KEY
, TED_NAME
, TED_ASN
);
159 PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]",
160 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
162 PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]",
163 __func__
, TED_KEY
, TED_ASN
, TED_NAME
);
169 uint32_t path_ted_rcvd_message(struct ls_message
*msg
)
171 if (!path_ted_is_initialized())
175 PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ",
180 if (path_ted_get_current_igp(msg
->data
.node
->adv
.origin
))
184 case LS_MSG_TYPE_NODE
:
185 ls_msg2vertex(ted_state_g
.ted
, msg
, true /*hard delete*/);
188 case LS_MSG_TYPE_ATTRIBUTES
:
189 ls_msg2edge(ted_state_g
.ted
, msg
, true /*ĥard delete*/);
192 case LS_MSG_TYPE_PREFIX
:
193 ls_msg2subnet(ted_state_g
.ted
, msg
, true /*hard delete*/);
198 "%s: [rcv ted] TED received unknown message type [%d]",
199 __func__
, msg
->type
);
205 uint32_t path_ted_query_type_f(struct ipaddr
*local
, struct ipaddr
*remote
)
207 uint32_t sid
= MPLS_LABEL_NONE
;
208 struct ls_edge
*edge
;
211 if (!path_ted_is_initialized())
212 return MPLS_LABEL_NONE
;
214 if (!local
|| !remote
)
215 return MPLS_LABEL_NONE
;
217 switch (local
->ipa_type
) {
219 /* We have local and remote ip */
220 /* so check all attributes in ted */
221 key
= ((uint64_t)ntohl(local
->ip
._v4_addr
.s_addr
)) & 0xffffffff;
222 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
224 if (edge
->attributes
->standard
.remote
.s_addr
225 == remote
->ip
._v4_addr
.s_addr
226 && CHECK_FLAG(edge
->attributes
->flags
,
228 sid
= edge
->attributes
->adj_sid
[0]
229 .sid
; /* from primary */
235 key
= (uint64_t)ntohl(local
->ip
._v6_addr
.s6_addr32
[2]) << 32 |
236 (uint64_t)ntohl(local
->ip
._v6_addr
.s6_addr32
[3]);
237 edge
= ls_find_edge_by_key(ted_state_g
.ted
, key
);
239 if ((0 == memcmp(&edge
->attributes
->standard
.remote6
,
240 &remote
->ip
._v6_addr
,
241 sizeof(remote
->ip
._v6_addr
)) &&
242 CHECK_FLAG(edge
->attributes
->flags
,
243 LS_ATTR_ADJ_SID6
))) {
244 sid
= edge
->attributes
->adj_sid
[ADJ_PRI_IPV6
]
245 .sid
; /* from primary */
257 uint32_t path_ted_query_type_c(struct prefix
*prefix
, uint8_t algo
)
259 uint32_t sid
= MPLS_LABEL_NONE
;
260 struct ls_subnet
*subnet
;
262 if (!path_ted_is_initialized())
263 return MPLS_LABEL_NONE
;
266 return MPLS_LABEL_NONE
;
268 switch (prefix
->family
) {
271 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
273 if ((CHECK_FLAG(subnet
->ls_pref
->flags
, LS_PREF_SR
))
274 && (subnet
->ls_pref
->sr
.algo
== algo
))
275 sid
= subnet
->ls_pref
->sr
.sid
;
285 uint32_t path_ted_query_type_e(struct prefix
*prefix
, uint32_t iface_id
)
287 uint32_t sid
= MPLS_LABEL_NONE
;
288 struct ls_subnet
*subnet
;
289 struct listnode
*lst_node
;
290 struct ls_edge
*edge
;
292 if (!path_ted_is_initialized())
293 return MPLS_LABEL_NONE
;
296 return MPLS_LABEL_NONE
;
298 switch (prefix
->family
) {
301 subnet
= ls_find_subnet(ted_state_g
.ted
, *prefix
);
302 if (subnet
&& subnet
->vertex
303 && subnet
->vertex
->outgoing_edges
) {
304 /* from the vertex linked in subnet */
305 /* loop over outgoing edges */
306 for (ALL_LIST_ELEMENTS_RO(
307 subnet
->vertex
->outgoing_edges
, lst_node
,
309 /* and look for ifaceid */
310 /* so get sid of attribute */
311 if (CHECK_FLAG(edge
->attributes
->flags
,
313 && edge
->attributes
->standard
.local_id
315 sid
= subnet
->ls_pref
->sr
.sid
;
328 DEFPY (debug_path_ted
,
330 "[no] debug pathd mpls-te",
336 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
337 bool no_debug
= (no
!= NULL
);
339 DEBUG_MODE_SET(&ted_state_g
.dbg
, mode
, !no
);
340 DEBUG_FLAGS_SET(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
, !no_debug
);
345 * Following are vty command functions.
347 /* clang-format off */
352 "Enable the TE database (TED) functionality\n")
353 /* clang-format on */
356 if (ted_state_g
.enabled
) {
357 PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__
);
361 ted_state_g
.ted
= path_ted_create_ted();
362 ted_state_g
.enabled
= true;
363 PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__
);
368 /* clang-format off */
374 "Disable the TE Database functionality\n")
375 /* clang-format on */
377 if (!ted_state_g
.enabled
) {
378 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__
);
383 ls_ted_del_all(&ted_state_g
.ted
);
384 ted_state_g
.enabled
= false;
385 PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__
);
386 ted_state_g
.import
= IMPORT_UNKNOWN
;
387 if (ls_unregister(zclient
, false /*client*/) != 0) {
388 vty_out(vty
, "Unable to unregister Link State\n");
395 /* clang-format off */
396 DEFPY(path_ted_import
,
398 "mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
399 "Enable the TE database (TED) fill with remote igp data\n"
404 /* clang-format on */
407 if (ted_state_g
.enabled
)
408 if (path_ted_start_importing_igp(import_daemon
)) {
409 vty_out(vty
, "Unable to start importing\n");
415 /* clang-format off */
416 DEFUN (no_path_ted_import
,
417 no_path_ted_import_cmd
,
421 "Disable the TE Database fill with remote igp data\n")
422 /* clang-format on */
425 if (ted_state_g
.import
) {
426 if (path_ted_stop_importing_igp()) {
427 vty_out(vty
, "Unable to stop importing\n");
431 "%s: PATHD-TED: Importing igp data already OFF",
438 /* clang-format off */
439 DEFPY (show_pathd_ted_db
,
440 show_pathd_ted_db_cmd
,
441 "show pathd ted database <verbose|json>$ver_json ",
447 "Show complete received TED database\n")
448 /* clang-format on */
450 bool st_json
= false;
451 json_object
*json
= NULL
;
453 if (!ted_state_g
.enabled
) {
454 vty_out(vty
, "Traffic Engineering database is not enabled\n");
457 if (strcmp(ver_json
, "json") == 0) {
459 json
= json_object_new_object();
461 /* Show the complete TED */
462 ls_show_ted(ted_state_g
.ted
, vty
, json
, !st_json
);
469 * Config Write functions
472 int path_ted_cli_debug_config_write(struct vty
*vty
)
474 if (DEBUG_MODE_CHECK(&ted_state_g
.dbg
, DEBUG_MODE_CONF
)) {
475 if (DEBUG_FLAGS_CHECK(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
))
476 vty_out(vty
, "debug pathd mpls-te\n");
482 void path_ted_show_debugging(struct vty
*vty
)
484 if (DEBUG_FLAGS_CHECK(&ted_state_g
.dbg
, PATH_TED_DEBUG_BASIC
))
485 vty_out(vty
, " Path TED debugging is on\n");
488 int path_ted_cli_debug_set_all(uint32_t flags
, bool set
)
490 DEBUG_FLAGS_SET(&ted_state_g
.dbg
, flags
, set
);
492 /* If all modes have been turned off, don't preserve options. */
493 if (!DEBUG_MODE_CHECK(&ted_state_g
.dbg
, DEBUG_MODE_ALL
))
494 DEBUG_CLEAR(&ted_state_g
.dbg
);
500 * Help fn to show ted related configuration
506 uint32_t path_ted_config_write(struct vty
*vty
)
509 if (ted_state_g
.enabled
) {
510 vty_out(vty
, " mpls-te on\n");
511 switch (ted_state_g
.import
) {
513 vty_out(vty
, " mpls-te import isis\n");
516 vty_out(vty
, " mpls-te import ospfv2\n");
519 vty_out(vty
, " mpls-te import ospfv3\n");
529 * Register the fn's for CLI and hook for config show
534 static void path_ted_register_vty(void)
536 install_element(VIEW_NODE
, &show_pathd_ted_db_cmd
);
537 install_element(SR_TRAFFIC_ENG_NODE
, &path_ted_on_cmd
);
538 install_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_cmd
);
539 install_element(SR_TRAFFIC_ENG_NODE
, &path_ted_import_cmd
);
540 install_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_import_cmd
);
542 install_element(CONFIG_NODE
, &debug_path_ted_cmd
);
543 install_element(ENABLE_NODE
, &debug_path_ted_cmd
);
545 hook_register(nb_client_debug_config_write
,
546 path_ted_cli_debug_config_write
);
547 hook_register(nb_client_debug_set_all
, path_ted_cli_debug_set_all
);
551 * UnRegister the fn's for CLI and hook for config show
556 static void path_ted_unregister_vty(void)
558 uninstall_element(VIEW_NODE
, &show_pathd_ted_db_cmd
);
559 uninstall_element(SR_TRAFFIC_ENG_NODE
, &path_ted_on_cmd
);
560 uninstall_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_cmd
);
561 uninstall_element(SR_TRAFFIC_ENG_NODE
, &path_ted_import_cmd
);
562 uninstall_element(SR_TRAFFIC_ENG_NODE
, &no_path_ted_import_cmd
);
566 * Ask igp for a complete TED so far
570 * @return zclient status
572 enum zclient_send_status
path_ted_link_state_sync(void)
574 enum zclient_send_status status
;
576 status
= ls_request_sync(zclient
);
579 "%s: PATHD-TED: Opaque error asking for TED sync ",
583 PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
586 thread_add_timer(ted_state_g
.main
, path_ted_timer_handler_sync
,
587 &ted_state_g
, ted_state_g
.link_state_delay_interval
,
588 &ted_state_g
.t_link_state_sync
);
594 * Timer cb for check link state sync
596 * @param thread Current thread
600 void path_ted_timer_handler_sync(struct thread
*thread
)
603 struct ted_state
*data
= THREAD_ARG(thread
);
605 assert(data
!= NULL
);
607 path_ted_link_state_sync();
611 * refresg segment list and create timer to keep up updated
617 int path_ted_segment_list_refresh(void)
621 path_ted_timer_refresh_cancel();
622 thread_add_timer(ted_state_g
.main
, path_ted_timer_handler_refresh
,
624 ted_state_g
.segment_list_refresh_interval
,
625 &ted_state_g
.t_segment_list_refresh
);
631 * Timer cb for refreshing sid in segment lists
637 void path_ted_timer_handler_refresh(struct thread
*thread
)
639 if (!path_ted_is_initialized())
642 PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__
);
644 struct ted_state
*data
= THREAD_ARG(thread
);
646 assert(data
!= NULL
);
648 srte_policy_update_ted_sid();
656 * @return void status
658 void path_ted_timer_sync_cancel(void)
660 if (ted_state_g
.t_link_state_sync
!= NULL
) {
661 thread_cancel(&ted_state_g
.t_link_state_sync
);
662 ted_state_g
.t_link_state_sync
= NULL
;
667 * Cancel refresh timer
671 * @return void status
673 void path_ted_timer_refresh_cancel(void)
675 if (ted_state_g
.t_segment_list_refresh
!= NULL
) {
676 thread_cancel(&ted_state_g
.t_segment_list_refresh
);
677 ted_state_g
.t_segment_list_refresh
= NULL
;
682 * Check which igp is configured
684 * @param igp who want to check against config-
688 uint32_t path_ted_get_current_igp(uint32_t igp
)
693 if (ted_state_g
.import
!= IMPORT_ISIS
) {
695 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
697 PATH_TED_IGP_PRINT(ted_state_g
.import
),
703 if (ted_state_g
.import
!= IMPORT_OSPFv2
) {
705 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
707 PATH_TED_IGP_PRINT(ted_state_g
.import
),