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