]> git.proxmox.com Git - mirror_frr.git/blame - pathd/path_ted.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pathd / path_ted.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
75c69d15
JG
2/*
3 * Copyright (C) 2020 Volta Networks, Inc
4 *
75c69d15
JG
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/>.
7 */
8
75c69d15
JG
9#include <zebra.h>
10
5b4f4e62
DL
11#include <stdlib.h>
12
75c69d15
JG
13#include "memory.h"
14#include "log.h"
15#include "command.h"
16#include "prefix.h"
17#include <lib/json.h>
18
19#include "pathd.h"
20#include "pathd/path_errors.h"
21#include "pathd/path_ted.h"
22
75c69d15 23#include "pathd/path_ted_clippy.c"
75c69d15
JG
24
25static struct ls_ted *path_ted_create_ted(void);
26static void path_ted_register_vty(void);
27static void path_ted_unregister_vty(void);
28static uint32_t path_ted_start_importing_igp(const char *daemon_str);
29static uint32_t path_ted_stop_importing_igp(void);
30static enum zclient_send_status path_ted_link_state_sync(void);
e6685141
DS
31static void path_ted_timer_handler_sync(struct event *thread);
32static void path_ted_timer_handler_refresh(struct event *thread);
75c69d15
JG
33static int path_ted_cli_debug_config_write(struct vty *vty);
34static int path_ted_cli_debug_set_all(uint32_t flags, bool set);
35
36extern struct zclient *zclient;
37
38struct ted_state ted_state_g = {};
39
40/*
41 * path_path_ted public API function implementations
42 */
43
cd9d0537 44void path_ted_init(struct event_loop *master)
75c69d15
JG
45{
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();
51}
52
53uint32_t path_ted_teardown(void)
54{
55 PATH_TED_DEBUG("%s : TED [%p]", __func__, ted_state_g.ted);
56 path_ted_unregister_vty();
57 path_ted_stop_importing_igp();
aa5ced0a 58 ls_ted_del_all(&ted_state_g.ted);
75c69d15
JG
59 path_ted_timer_sync_cancel();
60 path_ted_timer_refresh_cancel();
61 return 0;
62}
63
64/**
65 * Set all needed to receive igp data.
66 *
67 * @return true if ok
68 *
69 */
70uint32_t path_ted_start_importing_igp(const char *daemon_str)
71{
72 uint32_t status = 0;
73
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;
78 return 1;
79 } else if (strcmp(daemon_str, "isis") == 0)
80 ted_state_g.import = IMPORT_ISIS;
81 else {
82 ted_state_g.import = IMPORT_UNKNOWN;
83 return 1;
84 }
85
86 if (ls_register(zclient, false /*client*/) != 0) {
87 PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State",
88 __func__);
89 ted_state_g.import = IMPORT_UNKNOWN;
90 status = 1;
91 } else {
92 if (path_ted_link_state_sync() != -1) {
93 PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON",
94 __func__,
95 PATH_TED_IGP_PRINT(ted_state_g.import));
96 } else {
97 PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF",
98 __func__,
99 PATH_TED_IGP_PRINT(ted_state_g.import));
100 ted_state_g.import = IMPORT_UNKNOWN;
101 }
102 }
103 return status;
104}
105
106/**
107 * Unset all needed to receive igp data.
108 *
109 * @return true if ok
110 *
111 */
112uint32_t path_ted_stop_importing_igp(void)
113{
114 uint32_t status = 0;
115
116 if (ted_state_g.import != IMPORT_UNKNOWN) {
117 if (ls_unregister(zclient, false /*client*/) != 0) {
118 PATH_TED_ERROR(
119 "%s: PATHD-TED: Unable to unregister Link State",
120 __func__);
121 status = 1;
122 } else {
123 ted_state_g.import = IMPORT_UNKNOWN;
124 PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF",
125 __func__);
126 }
127 path_ted_timer_sync_cancel();
128 }
129 return status;
130}
131/**
132 * Check for ted status
133 *
134 * @return true if ok
135 *
136 */
137bool path_ted_is_initialized(void)
138{
139 if (ted_state_g.ted == NULL) {
140 PATH_TED_WARN("PATHD TED ls_ted not initialized");
141 return false;
142 }
143
144 return true;
145}
146
147/**
148 * Creates an empty ted
149 *
150 * @param void
151 *
152 * @return Ptr to ted or NULL
153 */
d038abcc 154struct ls_ted *path_ted_create_ted(void)
75c69d15
JG
155{
156 struct ls_ted *ted = ls_ted_new(TED_KEY, TED_NAME, TED_ASN);
157
158 if (ted == NULL) {
159 PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]",
160 __func__, TED_KEY, TED_ASN, TED_NAME);
161 } else {
162 PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]",
163 __func__, TED_KEY, TED_ASN, TED_NAME);
164 }
165
166 return ted;
167}
168
169uint32_t path_ted_rcvd_message(struct ls_message *msg)
170{
171 if (!path_ted_is_initialized())
172 return 1;
173
174 if (msg == NULL) {
175 PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ",
176 __func__);
177 return 1;
178 }
179
180 if (path_ted_get_current_igp(msg->data.node->adv.origin))
181 return 1;
182
183 switch (msg->type) {
184 case LS_MSG_TYPE_NODE:
185 ls_msg2vertex(ted_state_g.ted, msg, true /*hard delete*/);
186 break;
187
188 case LS_MSG_TYPE_ATTRIBUTES:
189 ls_msg2edge(ted_state_g.ted, msg, true /*ĥard delete*/);
190 break;
191
192 case LS_MSG_TYPE_PREFIX:
193 ls_msg2subnet(ted_state_g.ted, msg, true /*hard delete*/);
194 break;
195
196 default:
197 PATH_TED_DEBUG(
198 "%s: [rcv ted] TED received unknown message type [%d]",
199 __func__, msg->type);
200 break;
201 }
202 return 0;
203}
204
205uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote)
206{
207 uint32_t sid = MPLS_LABEL_NONE;
208 struct ls_edge *edge;
7f2742b6 209 struct ls_edge_key key;
75c69d15
JG
210
211 if (!path_ted_is_initialized())
212 return MPLS_LABEL_NONE;
213
214 if (!local || !remote)
215 return MPLS_LABEL_NONE;
216
217 switch (local->ipa_type) {
218 case IPADDR_V4:
219 /* We have local and remote ip */
220 /* so check all attributes in ted */
7f2742b6
OD
221 key.family = AF_INET;
222 IPV4_ADDR_COPY(&key.k.addr, &local->ip._v4_addr);
75c69d15
JG
223 edge = ls_find_edge_by_key(ted_state_g.ted, key);
224 if (edge) {
225 if (edge->attributes->standard.remote.s_addr
226 == remote->ip._v4_addr.s_addr
227 && CHECK_FLAG(edge->attributes->flags,
228 LS_ATTR_ADJ_SID)) {
229 sid = edge->attributes->adj_sid[0]
230 .sid; /* from primary */
231 break;
232 }
233 }
234 break;
235 case IPADDR_V6:
7f2742b6
OD
236 key.family = AF_INET6;
237 IPV6_ADDR_COPY(&key.k.addr6, &local->ip._v6_addr);
75c69d15
JG
238 edge = ls_find_edge_by_key(ted_state_g.ted, key);
239 if (edge) {
98654f42
FD
240 if ((0 == memcmp(&edge->attributes->standard.remote6,
241 &remote->ip._v6_addr,
242 sizeof(remote->ip._v6_addr)) &&
243 CHECK_FLAG(edge->attributes->flags,
244 LS_ATTR_ADJ_SID6))) {
245 sid = edge->attributes->adj_sid[ADJ_PRI_IPV6]
75c69d15
JG
246 .sid; /* from primary */
247 break;
248 }
249 }
250 break;
251 case IPADDR_NONE:
252 break;
253 }
254
255 return sid;
256}
257
258uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo)
259{
260 uint32_t sid = MPLS_LABEL_NONE;
261 struct ls_subnet *subnet;
262
263 if (!path_ted_is_initialized())
264 return MPLS_LABEL_NONE;
265
266 if (!prefix)
267 return MPLS_LABEL_NONE;
268
269 switch (prefix->family) {
270 case AF_INET:
271 case AF_INET6:
b5894669 272 subnet = ls_find_subnet(ted_state_g.ted, prefix);
75c69d15
JG
273 if (subnet) {
274 if ((CHECK_FLAG(subnet->ls_pref->flags, LS_PREF_SR))
275 && (subnet->ls_pref->sr.algo == algo))
276 sid = subnet->ls_pref->sr.sid;
277 }
278 break;
279 default:
280 break;
281 }
282
283 return sid;
284}
285
286uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id)
287{
288 uint32_t sid = MPLS_LABEL_NONE;
289 struct ls_subnet *subnet;
290 struct listnode *lst_node;
291 struct ls_edge *edge;
292
293 if (!path_ted_is_initialized())
294 return MPLS_LABEL_NONE;
295
296 if (!prefix)
297 return MPLS_LABEL_NONE;
298
299 switch (prefix->family) {
300 case AF_INET:
301 case AF_INET6:
b5894669 302 subnet = ls_find_subnet(ted_state_g.ted, prefix);
75c69d15
JG
303 if (subnet && subnet->vertex
304 && subnet->vertex->outgoing_edges) {
305 /* from the vertex linked in subnet */
306 /* loop over outgoing edges */
307 for (ALL_LIST_ELEMENTS_RO(
308 subnet->vertex->outgoing_edges, lst_node,
309 edge)) {
310 /* and look for ifaceid */
311 /* so get sid of attribute */
312 if (CHECK_FLAG(edge->attributes->flags,
313 LS_ATTR_LOCAL_ID)
314 && edge->attributes->standard.local_id
315 == iface_id) {
316 sid = subnet->ls_pref->sr.sid;
317 break;
318 }
319 }
320 }
321 break;
322 default:
323 break;
324 }
325
326 return sid;
327}
328
329DEFPY (debug_path_ted,
330 debug_path_ted_cmd,
331 "[no] debug pathd mpls-te",
332 NO_STR
333 DEBUG_STR
334 "path debugging\n"
335 "ted debugging\n")
336{
337 uint32_t mode = DEBUG_NODE2MODE(vty->node);
338 bool no_debug = (no != NULL);
339
340 DEBUG_MODE_SET(&ted_state_g.dbg, mode, !no);
341 DEBUG_FLAGS_SET(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC, !no_debug);
342 return CMD_SUCCESS;
343}
344
345/*
78dfa0c7 346 * Following are vty command functions.
75c69d15
JG
347 */
348/* clang-format off */
349DEFUN (path_ted_on,
350 path_ted_on_cmd,
351 "mpls-te on",
352 NO_STR
353 "Enable the TE database (TED) functionality\n")
354/* clang-format on */
355{
356
357 if (ted_state_g.enabled) {
358 PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__);
359 return CMD_SUCCESS;
360 }
361
362 ted_state_g.ted = path_ted_create_ted();
363 ted_state_g.enabled = true;
364 PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__);
365
366 return CMD_SUCCESS;
367}
368
369/* clang-format off */
370DEFUN (no_path_ted,
371 no_path_ted_cmd,
372 "no mpls-te [on]",
373 NO_STR
374 NO_STR
375 "Disable the TE Database functionality\n")
376/* clang-format on */
377{
cab69e3f 378 if (!ted_state_g.enabled) {
75c69d15
JG
379 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__);
380 return CMD_SUCCESS;
381 }
382
383 /* Remove TED */
aa5ced0a 384 ls_ted_del_all(&ted_state_g.ted);
75c69d15
JG
385 ted_state_g.enabled = false;
386 PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__);
387 ted_state_g.import = IMPORT_UNKNOWN;
388 if (ls_unregister(zclient, false /*client*/) != 0) {
389 vty_out(vty, "Unable to unregister Link State\n");
390 return CMD_WARNING;
391 }
392
393 return CMD_SUCCESS;
394}
395
396/* clang-format off */
397DEFPY(path_ted_import,
398 path_ted_import_cmd,
399 "mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
400 "Enable the TE database (TED) fill with remote igp data\n"
401 "import\n"
402 "Origin ospfv2\n"
403 "Origin ospfv3\n"
404 "Origin isis\n")
405/* clang-format on */
406{
407
408 if (ted_state_g.enabled)
409 if (path_ted_start_importing_igp(import_daemon)) {
410 vty_out(vty, "Unable to start importing\n");
411 return CMD_WARNING;
412 }
413 return CMD_SUCCESS;
414}
415
416/* clang-format off */
417DEFUN (no_path_ted_import,
418 no_path_ted_import_cmd,
419 "no mpls-te import",
420 NO_STR
421 NO_STR
422 "Disable the TE Database fill with remote igp data\n")
423/* clang-format on */
424{
425
426 if (ted_state_g.import) {
427 if (path_ted_stop_importing_igp()) {
428 vty_out(vty, "Unable to stop importing\n");
429 return CMD_WARNING;
430 } else {
431 PATH_TED_DEBUG(
432 "%s: PATHD-TED: Importing igp data already OFF",
433 __func__);
434 }
435 }
436 return CMD_SUCCESS;
437}
438
439/* clang-format off */
1e519577 440DEFPY (show_pathd_ted_db,
75c69d15
JG
441 show_pathd_ted_db_cmd,
442 "show pathd ted database <verbose|json>$ver_json ",
443 "show command\n"
444 "pathd daemon\n"
445 "traffic eng\n"
446 "database\n"
447 "verbose output\n"
448 "Show complete received TED database\n")
449/* clang-format on */
450{
451 bool st_json = false;
452 json_object *json = NULL;
453
454 if (!ted_state_g.enabled) {
e77ac87a 455 vty_out(vty, "Traffic Engineering database is not enabled\n");
75c69d15
JG
456 return CMD_WARNING;
457 }
458 if (strcmp(ver_json, "json") == 0) {
459 st_json = true;
460 json = json_object_new_object();
461 }
462 /* Show the complete TED */
463 ls_show_ted(ted_state_g.ted, vty, json, !st_json);
c48349e3 464 if (st_json)
3cc8ef87 465 vty_json(vty, json);
75c69d15
JG
466 return CMD_SUCCESS;
467}
468
469/*
470 * Config Write functions
471 */
472
473int path_ted_cli_debug_config_write(struct vty *vty)
474{
475 if (DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_CONF)) {
476 if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
477 vty_out(vty, "debug pathd mpls-te\n");
478 return 1;
479 }
480 return 0;
481}
482
96cb277e
PG
483void path_ted_show_debugging(struct vty *vty)
484{
485 if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
486 vty_out(vty, " Path TED debugging is on\n");
487}
488
75c69d15
JG
489int path_ted_cli_debug_set_all(uint32_t flags, bool set)
490{
491 DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
492
493 /* If all modes have been turned off, don't preserve options. */
494 if (!DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_ALL))
495 DEBUG_CLEAR(&ted_state_g.dbg);
496
497 return 0;
498}
499
500/**
501 * Help fn to show ted related configuration
502 *
503 * @param vty
504 *
505 * @return Status
506 */
507uint32_t path_ted_config_write(struct vty *vty)
508{
509
510 if (ted_state_g.enabled) {
dfbabd45 511 vty_out(vty, " mpls-te on\n");
75c69d15
JG
512 switch (ted_state_g.import) {
513 case IMPORT_ISIS:
dfbabd45 514 vty_out(vty, " mpls-te import isis\n");
75c69d15
JG
515 break;
516 case IMPORT_OSPFv2:
dfbabd45 517 vty_out(vty, " mpls-te import ospfv2\n");
75c69d15
JG
518 break;
519 case IMPORT_OSPFv3:
dfbabd45 520 vty_out(vty, " mpls-te import ospfv3\n");
75c69d15 521 break;
d5dea350 522 case IMPORT_UNKNOWN:
75c69d15
JG
523 break;
524 }
525 }
526 return 0;
527}
528
529/**
530 * Register the fn's for CLI and hook for config show
531 *
532 * @param void
533 *
534 */
535static void path_ted_register_vty(void)
536{
537 install_element(VIEW_NODE, &show_pathd_ted_db_cmd);
538 install_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
539 install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
540 install_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
541 install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
542
543 install_element(CONFIG_NODE, &debug_path_ted_cmd);
544 install_element(ENABLE_NODE, &debug_path_ted_cmd);
545
546 hook_register(nb_client_debug_config_write,
547 path_ted_cli_debug_config_write);
548 hook_register(nb_client_debug_set_all, path_ted_cli_debug_set_all);
549}
550
551/**
552 * UnRegister the fn's for CLI and hook for config show
553 *
554 * @param void
555 *
556 */
557static void path_ted_unregister_vty(void)
558{
559 uninstall_element(VIEW_NODE, &show_pathd_ted_db_cmd);
560 uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
561 uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
562 uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
563 uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
564}
565
566/**
567 * Ask igp for a complete TED so far
568 *
569 * @param void
570 *
571 * @return zclient status
572 */
573enum zclient_send_status path_ted_link_state_sync(void)
574{
575 enum zclient_send_status status;
576
577 status = ls_request_sync(zclient);
578 if (status == -1) {
579 PATH_TED_ERROR(
580 "%s: PATHD-TED: Opaque error asking for TED sync ",
581 __func__);
582 return status;
583 } else {
584 PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
585 __func__);
586 }
907a2395
DS
587 event_add_timer(ted_state_g.main, path_ted_timer_handler_sync,
588 &ted_state_g, ted_state_g.link_state_delay_interval,
589 &ted_state_g.t_link_state_sync);
75c69d15
JG
590
591 return status;
592}
593
594/**
595 * Timer cb for check link state sync
596 *
597 * @param thread Current thread
598 *
599 * @return status
600 */
e6685141 601void path_ted_timer_handler_sync(struct event *thread)
75c69d15
JG
602{
603 /* data unpacking */
e16d030c 604 struct ted_state *data = EVENT_ARG(thread);
75c69d15
JG
605
606 assert(data != NULL);
607 /* Retry the sync */
cc9f21da 608 path_ted_link_state_sync();
75c69d15
JG
609}
610
611/**
612 * refresg segment list and create timer to keep up updated
613 *
614 * @param void
615 *
616 * @return status
617 */
618int path_ted_segment_list_refresh(void)
619{
620 int status = 0;
621
622 path_ted_timer_refresh_cancel();
907a2395
DS
623 event_add_timer(ted_state_g.main, path_ted_timer_handler_refresh,
624 &ted_state_g, ted_state_g.segment_list_refresh_interval,
625 &ted_state_g.t_segment_list_refresh);
75c69d15
JG
626
627 return status;
628}
629
630/**
631 * Timer cb for refreshing sid in segment lists
632 *
633 * @param void
634 *
635 * @return status
636 */
e6685141 637void path_ted_timer_handler_refresh(struct event *thread)
75c69d15
JG
638{
639 if (!path_ted_is_initialized())
cc9f21da 640 return;
75c69d15
JG
641
642 PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__);
643 /* data unpacking */
e16d030c 644 struct ted_state *data = EVENT_ARG(thread);
75c69d15
JG
645
646 assert(data != NULL);
647
648 srte_policy_update_ted_sid();
75c69d15
JG
649}
650
651/**
652 * Cancel sync timer
653 *
654 * @param void
655 *
656 * @return void status
657 */
658void path_ted_timer_sync_cancel(void)
659{
660 if (ted_state_g.t_link_state_sync != NULL) {
332beb64 661 event_cancel(&ted_state_g.t_link_state_sync);
75c69d15
JG
662 ted_state_g.t_link_state_sync = NULL;
663 }
664}
665
666/**
667 * Cancel refresh timer
668 *
669 * @param void
670 *
671 * @return void status
672 */
673void path_ted_timer_refresh_cancel(void)
674{
675 if (ted_state_g.t_segment_list_refresh != NULL) {
332beb64 676 event_cancel(&ted_state_g.t_segment_list_refresh);
75c69d15
JG
677 ted_state_g.t_segment_list_refresh = NULL;
678 }
679}
680
681/**
682 * Check which igp is configured
683 *
684 * @param igp who want to check against config-
685 *
686 * @return status
687 */
688uint32_t path_ted_get_current_igp(uint32_t igp)
689{
690 switch (igp) {
691 case ISIS_L1:
692 case ISIS_L2:
693 if (ted_state_g.import != IMPORT_ISIS) {
694 PATH_TED_ERROR(
695 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
696 __func__,
697 PATH_TED_IGP_PRINT(ted_state_g.import),
698 LS_IGP_PRINT(igp));
699 return 1;
700 }
701 break;
702 case OSPFv2:
703 if (ted_state_g.import != IMPORT_OSPFv2) {
704 PATH_TED_ERROR(
705 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
706 __func__,
707 PATH_TED_IGP_PRINT(ted_state_g.import),
708 LS_IGP_PRINT(igp));
709 return 1;
710 }
711 break;
712 case STATIC:
713 break;
714 }
715 return 0;
716}