]> git.proxmox.com Git - mirror_frr.git/blame - pathd/path_ted.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[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);
cc9f21da
DS
31static void path_ted_timer_handler_sync(struct thread *thread);
32static void path_ted_timer_handler_refresh(struct thread *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
44void path_ted_init(struct thread_master *master)
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;
209 uint64_t key;
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 */
221 key = ((uint64_t)ntohl(local->ip._v4_addr.s_addr)) & 0xffffffff;
222 edge = ls_find_edge_by_key(ted_state_g.ted, key);
223 if (edge) {
224 if (edge->attributes->standard.remote.s_addr
225 == remote->ip._v4_addr.s_addr
226 && CHECK_FLAG(edge->attributes->flags,
227 LS_ATTR_ADJ_SID)) {
228 sid = edge->attributes->adj_sid[0]
229 .sid; /* from primary */
230 break;
231 }
232 }
233 break;
234 case IPADDR_V6:
98654f42
FD
235 key = (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[2]) << 32 |
236 (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[3]);
75c69d15
JG
237 edge = ls_find_edge_by_key(ted_state_g.ted, key);
238 if (edge) {
98654f42
FD
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]
75c69d15
JG
245 .sid; /* from primary */
246 break;
247 }
248 }
249 break;
250 case IPADDR_NONE:
251 break;
252 }
253
254 return sid;
255}
256
257uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo)
258{
259 uint32_t sid = MPLS_LABEL_NONE;
260 struct ls_subnet *subnet;
261
262 if (!path_ted_is_initialized())
263 return MPLS_LABEL_NONE;
264
265 if (!prefix)
266 return MPLS_LABEL_NONE;
267
268 switch (prefix->family) {
269 case AF_INET:
270 case AF_INET6:
271 subnet = ls_find_subnet(ted_state_g.ted, *prefix);
272 if (subnet) {
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;
276 }
277 break;
278 default:
279 break;
280 }
281
282 return sid;
283}
284
285uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id)
286{
287 uint32_t sid = MPLS_LABEL_NONE;
288 struct ls_subnet *subnet;
289 struct listnode *lst_node;
290 struct ls_edge *edge;
291
292 if (!path_ted_is_initialized())
293 return MPLS_LABEL_NONE;
294
295 if (!prefix)
296 return MPLS_LABEL_NONE;
297
298 switch (prefix->family) {
299 case AF_INET:
300 case AF_INET6:
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,
308 edge)) {
309 /* and look for ifaceid */
310 /* so get sid of attribute */
311 if (CHECK_FLAG(edge->attributes->flags,
312 LS_ATTR_LOCAL_ID)
313 && edge->attributes->standard.local_id
314 == iface_id) {
315 sid = subnet->ls_pref->sr.sid;
316 break;
317 }
318 }
319 }
320 break;
321 default:
322 break;
323 }
324
325 return sid;
326}
327
328DEFPY (debug_path_ted,
329 debug_path_ted_cmd,
330 "[no] debug pathd mpls-te",
331 NO_STR
332 DEBUG_STR
333 "path debugging\n"
334 "ted debugging\n")
335{
336 uint32_t mode = DEBUG_NODE2MODE(vty->node);
337 bool no_debug = (no != NULL);
338
339 DEBUG_MODE_SET(&ted_state_g.dbg, mode, !no);
340 DEBUG_FLAGS_SET(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC, !no_debug);
341 return CMD_SUCCESS;
342}
343
344/*
78dfa0c7 345 * Following are vty command functions.
75c69d15
JG
346 */
347/* clang-format off */
348DEFUN (path_ted_on,
349 path_ted_on_cmd,
350 "mpls-te on",
351 NO_STR
352 "Enable the TE database (TED) functionality\n")
353/* clang-format on */
354{
355
356 if (ted_state_g.enabled) {
357 PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__);
358 return CMD_SUCCESS;
359 }
360
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__);
364
365 return CMD_SUCCESS;
366}
367
368/* clang-format off */
369DEFUN (no_path_ted,
370 no_path_ted_cmd,
371 "no mpls-te [on]",
372 NO_STR
373 NO_STR
374 "Disable the TE Database functionality\n")
375/* clang-format on */
376{
cab69e3f 377 if (!ted_state_g.enabled) {
75c69d15
JG
378 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__);
379 return CMD_SUCCESS;
380 }
381
382 /* Remove TED */
aa5ced0a 383 ls_ted_del_all(&ted_state_g.ted);
75c69d15
JG
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");
389 return CMD_WARNING;
390 }
391
392 return CMD_SUCCESS;
393}
394
395/* clang-format off */
396DEFPY(path_ted_import,
397 path_ted_import_cmd,
398 "mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
399 "Enable the TE database (TED) fill with remote igp data\n"
400 "import\n"
401 "Origin ospfv2\n"
402 "Origin ospfv3\n"
403 "Origin isis\n")
404/* clang-format on */
405{
406
407 if (ted_state_g.enabled)
408 if (path_ted_start_importing_igp(import_daemon)) {
409 vty_out(vty, "Unable to start importing\n");
410 return CMD_WARNING;
411 }
412 return CMD_SUCCESS;
413}
414
415/* clang-format off */
416DEFUN (no_path_ted_import,
417 no_path_ted_import_cmd,
418 "no mpls-te import",
419 NO_STR
420 NO_STR
421 "Disable the TE Database fill with remote igp data\n")
422/* clang-format on */
423{
424
425 if (ted_state_g.import) {
426 if (path_ted_stop_importing_igp()) {
427 vty_out(vty, "Unable to stop importing\n");
428 return CMD_WARNING;
429 } else {
430 PATH_TED_DEBUG(
431 "%s: PATHD-TED: Importing igp data already OFF",
432 __func__);
433 }
434 }
435 return CMD_SUCCESS;
436}
437
438/* clang-format off */
1e519577 439DEFPY (show_pathd_ted_db,
75c69d15
JG
440 show_pathd_ted_db_cmd,
441 "show pathd ted database <verbose|json>$ver_json ",
442 "show command\n"
443 "pathd daemon\n"
444 "traffic eng\n"
445 "database\n"
446 "verbose output\n"
447 "Show complete received TED database\n")
448/* clang-format on */
449{
450 bool st_json = false;
451 json_object *json = NULL;
452
453 if (!ted_state_g.enabled) {
e77ac87a 454 vty_out(vty, "Traffic Engineering database is not enabled\n");
75c69d15
JG
455 return CMD_WARNING;
456 }
457 if (strcmp(ver_json, "json") == 0) {
458 st_json = true;
459 json = json_object_new_object();
460 }
461 /* Show the complete TED */
462 ls_show_ted(ted_state_g.ted, vty, json, !st_json);
c48349e3 463 if (st_json)
3cc8ef87 464 vty_json(vty, json);
75c69d15
JG
465 return CMD_SUCCESS;
466}
467
468/*
469 * Config Write functions
470 */
471
472int path_ted_cli_debug_config_write(struct vty *vty)
473{
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");
477 return 1;
478 }
479 return 0;
480}
481
96cb277e
PG
482void path_ted_show_debugging(struct vty *vty)
483{
484 if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
485 vty_out(vty, " Path TED debugging is on\n");
486}
487
75c69d15
JG
488int path_ted_cli_debug_set_all(uint32_t flags, bool set)
489{
490 DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
491
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);
495
496 return 0;
497}
498
499/**
500 * Help fn to show ted related configuration
501 *
502 * @param vty
503 *
504 * @return Status
505 */
506uint32_t path_ted_config_write(struct vty *vty)
507{
508
509 if (ted_state_g.enabled) {
dfbabd45 510 vty_out(vty, " mpls-te on\n");
75c69d15
JG
511 switch (ted_state_g.import) {
512 case IMPORT_ISIS:
dfbabd45 513 vty_out(vty, " mpls-te import isis\n");
75c69d15
JG
514 break;
515 case IMPORT_OSPFv2:
dfbabd45 516 vty_out(vty, " mpls-te import ospfv2\n");
75c69d15
JG
517 break;
518 case IMPORT_OSPFv3:
dfbabd45 519 vty_out(vty, " mpls-te import ospfv3\n");
75c69d15 520 break;
d5dea350 521 case IMPORT_UNKNOWN:
75c69d15
JG
522 break;
523 }
524 }
525 return 0;
526}
527
528/**
529 * Register the fn's for CLI and hook for config show
530 *
531 * @param void
532 *
533 */
534static void path_ted_register_vty(void)
535{
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);
541
542 install_element(CONFIG_NODE, &debug_path_ted_cmd);
543 install_element(ENABLE_NODE, &debug_path_ted_cmd);
544
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);
548}
549
550/**
551 * UnRegister the fn's for CLI and hook for config show
552 *
553 * @param void
554 *
555 */
556static void path_ted_unregister_vty(void)
557{
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);
563}
564
565/**
566 * Ask igp for a complete TED so far
567 *
568 * @param void
569 *
570 * @return zclient status
571 */
572enum zclient_send_status path_ted_link_state_sync(void)
573{
574 enum zclient_send_status status;
575
576 status = ls_request_sync(zclient);
577 if (status == -1) {
578 PATH_TED_ERROR(
579 "%s: PATHD-TED: Opaque error asking for TED sync ",
580 __func__);
581 return status;
582 } else {
583 PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
584 __func__);
585 }
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);
589
590 return status;
591}
592
593/**
594 * Timer cb for check link state sync
595 *
596 * @param thread Current thread
597 *
598 * @return status
599 */
cc9f21da 600void path_ted_timer_handler_sync(struct thread *thread)
75c69d15
JG
601{
602 /* data unpacking */
603 struct ted_state *data = THREAD_ARG(thread);
604
605 assert(data != NULL);
606 /* Retry the sync */
cc9f21da 607 path_ted_link_state_sync();
75c69d15
JG
608}
609
610/**
611 * refresg segment list and create timer to keep up updated
612 *
613 * @param void
614 *
615 * @return status
616 */
617int path_ted_segment_list_refresh(void)
618{
619 int status = 0;
620
621 path_ted_timer_refresh_cancel();
622 thread_add_timer(ted_state_g.main, path_ted_timer_handler_refresh,
623 &ted_state_g,
624 ted_state_g.segment_list_refresh_interval,
625 &ted_state_g.t_segment_list_refresh);
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 */
cc9f21da 637void path_ted_timer_handler_refresh(struct thread *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 */
644 struct ted_state *data = THREAD_ARG(thread);
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) {
661 thread_cancel(&ted_state_g.t_link_state_sync);
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) {
676 thread_cancel(&ted_state_g.t_segment_list_refresh);
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}