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