]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_ted.c
Merge pull request #9998 from pguibert6WIND/bgp_tcp_keepalive
[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 #ifndef VTYSH_EXTRACT_PL
33 #include "pathd/path_ted_clippy.c"
34 #endif
35
36 static struct ls_ted *path_ted_create_ted(void);
37 static void path_ted_register_vty(void);
38 static void path_ted_unregister_vty(void);
39 static uint32_t path_ted_start_importing_igp(const char *daemon_str);
40 static uint32_t path_ted_stop_importing_igp(void);
41 static enum zclient_send_status path_ted_link_state_sync(void);
42 static void path_ted_timer_handler_sync(struct thread *thread);
43 static void path_ted_timer_handler_refresh(struct thread *thread);
44 static int path_ted_cli_debug_config_write(struct vty *vty);
45 static int path_ted_cli_debug_set_all(uint32_t flags, bool set);
46
47 extern struct zclient *zclient;
48
49 struct ted_state ted_state_g = {};
50
51 /*
52 * path_path_ted public API function implementations
53 */
54
55 void 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
64 uint32_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();
69 ls_ted_del_all(&ted_state_g.ted);
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 */
81 uint32_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 */
123 uint32_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 */
148 bool 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 */
165 struct 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
180 uint32_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
216 uint32_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)ntohl(local->ip._v6_addr.s6_addr32[2]) << 32 |
247 (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[3]);
248 edge = ls_find_edge_by_key(ted_state_g.ted, key);
249 if (edge) {
250 if ((0 == 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_SID6))) {
255 sid = edge->attributes->adj_sid[ADJ_PRI_IPV6]
256 .sid; /* from primary */
257 break;
258 }
259 }
260 break;
261 case IPADDR_NONE:
262 break;
263 }
264
265 return sid;
266 }
267
268 uint32_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
296 uint32_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
339 DEFPY (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 /*
356 * Following are vty command functions.
357 */
358 /* clang-format off */
359 DEFUN (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 */
380 DEFUN (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 */
394 ls_ted_del_all(&ted_state_g.ted);
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 */
407 DEFPY(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 */
427 DEFUN (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 */
450 DEFPY (show_pathd_ted_db,
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, "Traffic Engineering 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);
474 if (st_json)
475 vty_json(vty, json);
476 return CMD_SUCCESS;
477 }
478
479 /*
480 * Config Write functions
481 */
482
483 int 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
493 int 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 */
511 uint32_t path_ted_config_write(struct vty *vty)
512 {
513
514 if (ted_state_g.enabled) {
515 vty_out(vty, " mpls-te on\n");
516 switch (ted_state_g.import) {
517 case IMPORT_ISIS:
518 vty_out(vty, " mpls-te import isis\n");
519 break;
520 case IMPORT_OSPFv2:
521 vty_out(vty, " mpls-te import ospfv2\n");
522 break;
523 case IMPORT_OSPFv3:
524 vty_out(vty, " mpls-te import ospfv3\n");
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 */
539 static 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 */
561 static 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 */
577 enum 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 */
605 void path_ted_timer_handler_sync(struct thread *thread)
606 {
607 /* data unpacking */
608 struct ted_state *data = THREAD_ARG(thread);
609
610 assert(data != NULL);
611 /* Retry the sync */
612 path_ted_link_state_sync();
613 }
614
615 /**
616 * refresg segment list and create timer to keep up updated
617 *
618 * @param void
619 *
620 * @return status
621 */
622 int 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 */
642 void path_ted_timer_handler_refresh(struct thread *thread)
643 {
644 if (!path_ted_is_initialized())
645 return;
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();
654 }
655
656 /**
657 * Cancel sync timer
658 *
659 * @param void
660 *
661 * @return void status
662 */
663 void 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 */
678 void 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 */
693 uint32_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 }