aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/srv6/sr_pt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/srv6/sr_pt.c')
-rw-r--r--src/vnet/srv6/sr_pt.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/vnet/srv6/sr_pt.c b/src/vnet/srv6/sr_pt.c
new file mode 100644
index 00000000000..6299faa84ab
--- /dev/null
+++ b/src/vnet/srv6/sr_pt.c
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+/**
+ * @file
+ * @brief SR Path Tracing (PT)
+ *
+ * SR PT CLI
+ *
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/srv6/sr.h>
+#include <vnet/ip/ip.h>
+#include <vnet/srv6/sr_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/dpo/dpo.h>
+#include <vnet/adj/adj.h>
+#include <vnet/srv6/sr_pt.h>
+
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+sr_pt_main_t sr_pt_main;
+
+void *
+sr_pt_find_iface (u32 iface)
+{
+ sr_pt_main_t *sr_pt = &sr_pt_main;
+ uword *p;
+
+ /* Search for the item */
+ p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
+ if (p)
+ {
+ /* Retrieve sr_pt_iface */
+ return pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
+ }
+ return NULL;
+}
+
+int
+sr_pt_add_iface (u32 iface, u16 id, u8 ingress_load, u8 egress_load,
+ u8 tts_template)
+{
+ sr_pt_main_t *sr_pt = &sr_pt_main;
+ uword *p;
+
+ sr_pt_iface_t *ls = 0;
+
+ if (iface == (u32) ~0)
+ return SR_PT_ERR_IFACE_INVALID;
+
+ /* Search for the item */
+ p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
+
+ if (p)
+ return SR_PT_ERR_EXIST;
+
+ if (id > SR_PT_ID_MAX)
+ return SR_PT_ERR_ID_INVALID;
+
+ if (ingress_load > SR_PT_LOAD_MAX || egress_load > SR_PT_LOAD_MAX)
+ return SR_PT_ERR_LOAD_INVALID;
+
+ if (tts_template > SR_PT_TTS_TEMPLATE_MAX)
+ return SR_PT_ERR_TTS_TEMPLATE_INVALID;
+
+ vnet_feature_enable_disable ("ip6-output", "pt", iface, 1, 0, 0);
+
+ /* Create a new sr_pt_iface */
+ pool_get_zero (sr_pt->sr_pt_iface, ls);
+ ls->iface = iface;
+ ls->id = id;
+ ls->ingress_load = ingress_load;
+ ls->egress_load = egress_load;
+ ls->tts_template = tts_template;
+
+ /* Set hash key for searching sr_pt_iface by iface */
+ mhash_set (&sr_pt->sr_pt_iface_index_hash, &iface, ls - sr_pt->sr_pt_iface,
+ NULL);
+ return 0;
+}
+
+int
+sr_pt_del_iface (u32 iface)
+{
+ sr_pt_main_t *sr_pt = &sr_pt_main;
+ uword *p;
+
+ sr_pt_iface_t *ls = 0;
+
+ if (iface == (u32) ~0)
+ return SR_PT_ERR_IFACE_INVALID;
+
+ /* Search for the item */
+ p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
+
+ if (p)
+ {
+ /* Retrieve sr_pt_iface */
+ ls = pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
+ vnet_feature_enable_disable ("ip6-output", "pt", iface, 0, 0, 0);
+ /* Delete sr_pt_iface */
+ pool_put (sr_pt->sr_pt_iface, ls);
+ mhash_unset (&sr_pt->sr_pt_iface_index_hash, &iface, NULL);
+ }
+ else
+ {
+ return SR_PT_ERR_NOENT;
+ }
+ return 0;
+}
+
+/**
+ * @brief "sr pt add iface" CLI function.
+ *
+ * @see sr_pt_add_iface
+ */
+static clib_error_t *
+sr_pt_add_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 iface = (u32) ~0;
+ u32 id = (u32) ~0;
+ u32 ingress_load = 0;
+ u32 egress_load = 0;
+ u32 tts_template = SR_PT_TTS_TEMPLATE_DEFAULT;
+
+ int rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
+ ;
+ else if (unformat (input, "id %u", &id))
+ ;
+ else if (unformat (input, "ingress-load %u", &ingress_load))
+ ;
+ else if (unformat (input, "egress-load %u", &egress_load))
+ ;
+ else if (unformat (input, "tts-template %u", &tts_template))
+ ;
+ else
+ break;
+ }
+
+ rv = sr_pt_add_iface (iface, id, ingress_load, egress_load, tts_template);
+
+ switch (rv)
+ {
+ case 0:
+ break;
+ case SR_PT_ERR_EXIST:
+ return clib_error_return (0, "Error: Identical iface already exists.");
+ case SR_PT_ERR_IFACE_INVALID:
+ return clib_error_return (0, "Error: The iface name invalid.");
+ case SR_PT_ERR_ID_INVALID:
+ return clib_error_return (0, "Error: The iface id value invalid.");
+ case SR_PT_ERR_LOAD_INVALID:
+ return clib_error_return (
+ 0, "Error: The iface ingress or egress load value invalid.");
+ case SR_PT_ERR_TTS_TEMPLATE_INVALID:
+ return clib_error_return (
+ 0, "Error: The iface TTS Template value invalid.");
+ default:
+ return clib_error_return (0, "Error: unknown error.");
+ }
+ return 0;
+}
+
+/**
+ * @brief "sr pt del iface" CLI function.
+ *
+ * @see sr_pt_del_iface
+ */
+static clib_error_t *
+sr_pt_del_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 iface = (u32) ~0;
+
+ int rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
+ ;
+ else
+ break;
+ }
+
+ rv = sr_pt_del_iface (iface);
+
+ switch (rv)
+ {
+ case 0:
+ break;
+ case SR_PT_ERR_NOENT:
+ return clib_error_return (0, "Error: No such iface.");
+ case SR_PT_ERR_IFACE_INVALID:
+ return clib_error_return (0, "Error: The iface name is not valid.");
+ default:
+ return clib_error_return (0, "Error: unknown error.");
+ }
+ return 0;
+}
+
+/**
+ * @brief CLI function to show all SR PT interfcaes
+ */
+static clib_error_t *
+sr_pt_show_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ sr_pt_main_t *sr_pt = &sr_pt_main;
+ sr_pt_iface_t **sr_pt_iface_list = 0;
+ sr_pt_iface_t *ls;
+ int i;
+
+ vlib_cli_output (vm, "SR PT Interfaces");
+ vlib_cli_output (vm, "==================================");
+
+ pool_foreach (ls, sr_pt->sr_pt_iface)
+ {
+ vec_add1 (sr_pt_iface_list, ls);
+ };
+
+ for (i = 0; i < vec_len (sr_pt_iface_list); i++)
+ {
+ ls = sr_pt_iface_list[i];
+ vlib_cli_output (
+ vm,
+ "\tiface : \t%U\n\tid : \t%d\n\tingress-load: "
+ "\t%d\n\tegress-load : \t%d\n\ttts-template: \t%d ",
+ format_vnet_sw_if_index_name, vnm, ls->iface, ls->id, ls->ingress_load,
+ ls->egress_load, ls->tts_template);
+ vlib_cli_output (vm, "--------------------------------");
+ }
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (sr_pt_add_iface_command, static) = {
+ .path = "sr pt add iface",
+ .short_help = "sr pt add iface <iface-name> id <pt-iface-id> ingress-load "
+ "<ingress-load-value> egress-load <egress-load-value> "
+ "tts-template <tts-template-value>",
+ .function = sr_pt_add_iface_command_fn,
+};
+
+VLIB_CLI_COMMAND (sr_pt_del_iface_command, static) = {
+ .path = "sr pt del iface",
+ .short_help = "sr pt del iface <iface-name>",
+ .function = sr_pt_del_iface_command_fn,
+};
+
+VLIB_CLI_COMMAND (sr_pt_show_iface_command, static) = {
+ .path = "sr pt show iface",
+ .short_help = "sr pt show iface",
+ .function = sr_pt_show_iface_command_fn,
+};
+
+/**
+ * * @brief SR PT initialization
+ * */
+clib_error_t *
+sr_pt_init (vlib_main_t *vm)
+{
+ sr_pt_main_t *pt = &sr_pt_main;
+ mhash_init (&pt->sr_pt_iface_index_hash, sizeof (uword), sizeof (u32));
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (sr_pt_init); \ No newline at end of file