]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_ted.c
Merge pull request #11302 from punith-shivakumar/master
[mirror_frr.git] / pathd / path_ted.c
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 <zebra.h>
19
20 #include <stdlib.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 #include "pathd/path_ted_clippy.c"
33
34 static struct ls_ted *path_ted_create_ted(void);
35 static void path_ted_register_vty(void);
36 static void path_ted_unregister_vty(void);
37 static uint32_t path_ted_start_importing_igp(const char *daemon_str);
38 static uint32_t path_ted_stop_importing_igp(void);
39 static enum zclient_send_status path_ted_link_state_sync(void);
40 static void path_ted_timer_handler_sync(struct thread *thread);
41 static void path_ted_timer_handler_refresh(struct thread *thread);
42 static int path_ted_cli_debug_config_write(struct vty *vty);
43 static int path_ted_cli_debug_set_all(uint32_t flags, bool set);
44
45 extern struct zclient *zclient;
46
47 struct ted_state ted_state_g = {};
48
49 /*
50 * path_path_ted public API function implementations
51 */
52
53 void 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
62 uint32_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();
67 ls_ted_del_all(&ted_state_g.ted);
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 */
79 uint32_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 */
121 uint32_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 */
146 bool 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 */
163 struct ls_ted *path_ted_create_ted(void)
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
178 uint32_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
214 uint32_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:
244 key = (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[2]) << 32 |
245 (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[3]);
246 edge = ls_find_edge_by_key(ted_state_g.ted, key);
247 if (edge) {
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]
254 .sid; /* from primary */
255 break;
256 }
257 }
258 break;
259 case IPADDR_NONE:
260 break;
261 }
262
263 return sid;
264 }
265
266 uint32_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
294 uint32_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
337 DEFPY (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 /*
354 * Following are vty command functions.
355 */
356 /* clang-format off */
357 DEFUN (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 */
378 DEFUN (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 {
386 if (!ted_state_g.enabled) {
387 PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__);
388 return CMD_SUCCESS;
389 }
390
391 /* Remove TED */
392 ls_ted_del_all(&ted_state_g.ted);
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 */
405 DEFPY(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 */
425 DEFUN (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 */
448 DEFPY (show_pathd_ted_db,
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) {
463 vty_out(vty, "Traffic Engineering database is not enabled\n");
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);
472 if (st_json)
473 vty_json(vty, json);
474 return CMD_SUCCESS;
475 }
476
477 /*
478 * Config Write functions
479 */
480
481 int 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
491 int 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 */
509 uint32_t path_ted_config_write(struct vty *vty)
510 {
511
512 if (ted_state_g.enabled) {
513 vty_out(vty, " mpls-te on\n");
514 switch (ted_state_g.import) {
515 case IMPORT_ISIS:
516 vty_out(vty, " mpls-te import isis\n");
517 break;
518 case IMPORT_OSPFv2:
519 vty_out(vty, " mpls-te import ospfv2\n");
520 break;
521 case IMPORT_OSPFv3:
522 vty_out(vty, " mpls-te import ospfv3\n");
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 */
537 static 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 */
559 static 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 */
575 enum 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 */
603 void path_ted_timer_handler_sync(struct thread *thread)
604 {
605 /* data unpacking */
606 struct ted_state *data = THREAD_ARG(thread);
607
608 assert(data != NULL);
609 /* Retry the sync */
610 path_ted_link_state_sync();
611 }
612
613 /**
614 * refresg segment list and create timer to keep up updated
615 *
616 * @param void
617 *
618 * @return status
619 */
620 int 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 */
640 void path_ted_timer_handler_refresh(struct thread *thread)
641 {
642 if (!path_ted_is_initialized())
643 return;
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();
652 }
653
654 /**
655 * Cancel sync timer
656 *
657 * @param void
658 *
659 * @return void status
660 */
661 void 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 */
676 void 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 */
691 uint32_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 }