]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_ted.c
Merge pull request #12728 from opensourcerouting/feature/bgp_neighbor_path-attribute_...
[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 void path_ted_show_debugging(struct vty *vty)
492 {
493 if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
494 vty_out(vty, " Path TED debugging is on\n");
495 }
496
497 int path_ted_cli_debug_set_all(uint32_t flags, bool set)
498 {
499 DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
500
501 /* If all modes have been turned off, don't preserve options. */
502 if (!DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_ALL))
503 DEBUG_CLEAR(&ted_state_g.dbg);
504
505 return 0;
506 }
507
508 /**
509 * Help fn to show ted related configuration
510 *
511 * @param vty
512 *
513 * @return Status
514 */
515 uint32_t path_ted_config_write(struct vty *vty)
516 {
517
518 if (ted_state_g.enabled) {
519 vty_out(vty, " mpls-te on\n");
520 switch (ted_state_g.import) {
521 case IMPORT_ISIS:
522 vty_out(vty, " mpls-te import isis\n");
523 break;
524 case IMPORT_OSPFv2:
525 vty_out(vty, " mpls-te import ospfv2\n");
526 break;
527 case IMPORT_OSPFv3:
528 vty_out(vty, " mpls-te import ospfv3\n");
529 break;
530 case IMPORT_UNKNOWN:
531 break;
532 }
533 }
534 return 0;
535 }
536
537 /**
538 * Register the fn's for CLI and hook for config show
539 *
540 * @param void
541 *
542 */
543 static void path_ted_register_vty(void)
544 {
545 install_element(VIEW_NODE, &show_pathd_ted_db_cmd);
546 install_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
547 install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
548 install_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
549 install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
550
551 install_element(CONFIG_NODE, &debug_path_ted_cmd);
552 install_element(ENABLE_NODE, &debug_path_ted_cmd);
553
554 hook_register(nb_client_debug_config_write,
555 path_ted_cli_debug_config_write);
556 hook_register(nb_client_debug_set_all, path_ted_cli_debug_set_all);
557 }
558
559 /**
560 * UnRegister the fn's for CLI and hook for config show
561 *
562 * @param void
563 *
564 */
565 static void path_ted_unregister_vty(void)
566 {
567 uninstall_element(VIEW_NODE, &show_pathd_ted_db_cmd);
568 uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
569 uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
570 uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
571 uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
572 }
573
574 /**
575 * Ask igp for a complete TED so far
576 *
577 * @param void
578 *
579 * @return zclient status
580 */
581 enum zclient_send_status path_ted_link_state_sync(void)
582 {
583 enum zclient_send_status status;
584
585 status = ls_request_sync(zclient);
586 if (status == -1) {
587 PATH_TED_ERROR(
588 "%s: PATHD-TED: Opaque error asking for TED sync ",
589 __func__);
590 return status;
591 } else {
592 PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
593 __func__);
594 }
595 thread_add_timer(ted_state_g.main, path_ted_timer_handler_sync,
596 &ted_state_g, ted_state_g.link_state_delay_interval,
597 &ted_state_g.t_link_state_sync);
598
599 return status;
600 }
601
602 /**
603 * Timer cb for check link state sync
604 *
605 * @param thread Current thread
606 *
607 * @return status
608 */
609 void path_ted_timer_handler_sync(struct thread *thread)
610 {
611 /* data unpacking */
612 struct ted_state *data = THREAD_ARG(thread);
613
614 assert(data != NULL);
615 /* Retry the sync */
616 path_ted_link_state_sync();
617 }
618
619 /**
620 * refresg segment list and create timer to keep up updated
621 *
622 * @param void
623 *
624 * @return status
625 */
626 int path_ted_segment_list_refresh(void)
627 {
628 int status = 0;
629
630 path_ted_timer_refresh_cancel();
631 thread_add_timer(ted_state_g.main, path_ted_timer_handler_refresh,
632 &ted_state_g,
633 ted_state_g.segment_list_refresh_interval,
634 &ted_state_g.t_segment_list_refresh);
635
636 return status;
637 }
638
639 /**
640 * Timer cb for refreshing sid in segment lists
641 *
642 * @param void
643 *
644 * @return status
645 */
646 void path_ted_timer_handler_refresh(struct thread *thread)
647 {
648 if (!path_ted_is_initialized())
649 return;
650
651 PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__);
652 /* data unpacking */
653 struct ted_state *data = THREAD_ARG(thread);
654
655 assert(data != NULL);
656
657 srte_policy_update_ted_sid();
658 }
659
660 /**
661 * Cancel sync timer
662 *
663 * @param void
664 *
665 * @return void status
666 */
667 void path_ted_timer_sync_cancel(void)
668 {
669 if (ted_state_g.t_link_state_sync != NULL) {
670 thread_cancel(&ted_state_g.t_link_state_sync);
671 ted_state_g.t_link_state_sync = NULL;
672 }
673 }
674
675 /**
676 * Cancel refresh timer
677 *
678 * @param void
679 *
680 * @return void status
681 */
682 void path_ted_timer_refresh_cancel(void)
683 {
684 if (ted_state_g.t_segment_list_refresh != NULL) {
685 thread_cancel(&ted_state_g.t_segment_list_refresh);
686 ted_state_g.t_segment_list_refresh = NULL;
687 }
688 }
689
690 /**
691 * Check which igp is configured
692 *
693 * @param igp who want to check against config-
694 *
695 * @return status
696 */
697 uint32_t path_ted_get_current_igp(uint32_t igp)
698 {
699 switch (igp) {
700 case ISIS_L1:
701 case ISIS_L2:
702 if (ted_state_g.import != IMPORT_ISIS) {
703 PATH_TED_ERROR(
704 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
705 __func__,
706 PATH_TED_IGP_PRINT(ted_state_g.import),
707 LS_IGP_PRINT(igp));
708 return 1;
709 }
710 break;
711 case OSPFv2:
712 if (ted_state_g.import != IMPORT_OSPFv2) {
713 PATH_TED_ERROR(
714 "%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
715 __func__,
716 PATH_TED_IGP_PRINT(ted_state_g.import),
717 LS_IGP_PRINT(igp));
718 return 1;
719 }
720 break;
721 case STATIC:
722 break;
723 }
724 return 0;
725 }