summaryrefslogtreecommitdiffstats
path: root/lib/flex_algo.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/flex_algo.c')
-rw-r--r--lib/flex_algo.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/lib/flex_algo.c b/lib/flex_algo.c
new file mode 100644
index 0000000..f48117f
--- /dev/null
+++ b/lib/flex_algo.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*********************************************************************
+ * Copyright 2022 Hiroki Shirokura, LINE Corporation
+ * Copyright 2022 Masakazu Asama
+ * Copyright 2022 6WIND S.A.
+ *
+ * flex_algo.c: Flexible Algorithm library
+ *
+ * Authors
+ * -------
+ * Hiroki Shirokura
+ * Masakazu Asama
+ * Louis Scalbert
+ */
+
+#include "zebra.h"
+
+#include "flex_algo.h"
+
+DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO_DATABASE, "Flex-Algo database");
+DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO, "Flex-Algo algorithm information");
+
+static void _flex_algo_delete(struct flex_algos *flex_algos,
+ struct flex_algo *fa);
+
+struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator,
+ flex_algo_releaser_t releaser)
+{
+ struct flex_algos *flex_algos;
+
+ flex_algos =
+ XCALLOC(MTYPE_FLEX_ALGO_DATABASE, sizeof(struct flex_algos));
+ flex_algos->flex_algos = list_new();
+ flex_algos->allocator = allocator;
+ flex_algos->releaser = releaser;
+ return flex_algos;
+}
+
+void flex_algos_free(struct flex_algos *flex_algos)
+{
+ struct listnode *node, *nnode;
+ struct flex_algo *fa;
+
+ for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa))
+ _flex_algo_delete(flex_algos, fa);
+ list_delete(&flex_algos->flex_algos);
+ XFREE(MTYPE_FLEX_ALGO_DATABASE, flex_algos);
+}
+
+struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos,
+ uint8_t algorithm, void *arg)
+{
+ struct flex_algo *fa;
+
+ fa = XCALLOC(MTYPE_FLEX_ALGO, sizeof(struct flex_algo));
+ fa->algorithm = algorithm;
+ if (flex_algos->allocator)
+ fa->data = flex_algos->allocator(arg);
+ admin_group_init(&fa->admin_group_exclude_any);
+ admin_group_init(&fa->admin_group_include_any);
+ admin_group_init(&fa->admin_group_include_all);
+ listnode_add(flex_algos->flex_algos, fa);
+ return fa;
+}
+
+static void _flex_algo_delete(struct flex_algos *flex_algos,
+ struct flex_algo *fa)
+{
+ if (flex_algos->releaser)
+ flex_algos->releaser(fa->data);
+ admin_group_term(&fa->admin_group_exclude_any);
+ admin_group_term(&fa->admin_group_include_any);
+ admin_group_term(&fa->admin_group_include_all);
+ listnode_delete(flex_algos->flex_algos, fa);
+ XFREE(MTYPE_FLEX_ALGO, fa);
+}
+
+
+void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm)
+{
+ struct listnode *node, *nnode;
+ struct flex_algo *fa;
+
+ for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) {
+ if (fa->algorithm != algorithm)
+ continue;
+ _flex_algo_delete(flex_algos, fa);
+ }
+}
+
+/**
+ * @brief Look up the local flex-algo object by its algorithm number.
+ * @param algorithm flex-algo algorithm number
+ * @param area area pointer of flex-algo
+ * @return local flex-algo object if exist, else NULL
+ */
+struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos,
+ uint8_t algorithm)
+{
+ struct listnode *node;
+ struct flex_algo *fa;
+
+ for (ALL_LIST_ELEMENTS_RO(flex_algos->flex_algos, node, fa))
+ if (fa->algorithm == algorithm)
+ return fa;
+ return NULL;
+}
+
+/**
+ * @brief Compare two Flex-Algo Definitions (FAD)
+ * @param Flex algo 1
+ * @param Flex algo 2
+ * @return true if the definition is equal, else false
+ */
+bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2)
+{
+ if (fa1->algorithm != fa2->algorithm)
+ return false;
+ if (fa1->calc_type != fa2->calc_type)
+ return false;
+ if (fa1->metric_type != fa2->metric_type)
+ return false;
+ if (fa1->exclude_srlg != fa2->exclude_srlg)
+ return false;
+ if (fa1->flags != fa2->flags)
+ return false;
+ if (fa1->unsupported_subtlv != fa2->unsupported_subtlv)
+ return false;
+
+ if (!admin_group_cmp(&fa1->admin_group_exclude_any,
+ &fa2->admin_group_exclude_any))
+ return false;
+ if (!admin_group_cmp(&fa1->admin_group_include_all,
+ &fa2->admin_group_include_all))
+ return false;
+ if (!admin_group_cmp(&fa1->admin_group_include_any,
+ &fa2->admin_group_include_any))
+ return false;
+
+ return true;
+}
+
+/**
+ * Check SR Algorithm is Flex-Algo
+ * according to RFC9350 section 4
+ *
+ * @param algorithm SR Algorithm
+ */
+bool flex_algo_id_valid(uint16_t algorithm)
+{
+ return algorithm >= SR_ALGORITHM_FLEX_MIN &&
+ algorithm <= SR_ALGORITHM_FLEX_MAX;
+}
+
+char *flex_algo_metric_type_print(char *type_str, size_t sz,
+ enum flex_algo_metric_type metric_type)
+{
+ switch (metric_type) {
+ case MT_IGP:
+ snprintf(type_str, sz, "igp");
+ break;
+ case MT_MIN_UNI_LINK_DELAY:
+ snprintf(type_str, sz, "delay");
+ break;
+ case MT_TE_DEFAULT:
+ snprintf(type_str, sz, "te");
+ break;
+ }
+ return type_str;
+}
+
+bool flex_algo_get_state(struct flex_algos *flex_algos, uint8_t algorithm)
+{
+ struct flex_algo *fa = flex_algo_lookup(flex_algos, algorithm);
+
+ if (!fa)
+ return false;
+
+ return fa->state;
+}
+
+void flex_algo_set_state(struct flex_algos *flex_algos, uint8_t algorithm,
+ bool state)
+{
+ struct flex_algo *fa = flex_algo_lookup(flex_algos, algorithm);
+
+ if (!fa)
+ return;
+
+ fa->state = state;
+}