From c933bb7e37a209c8f29c8a376d274c01ce460079 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Wed, 29 Jun 2022 11:08:42 +0000 Subject: sr: Add support for SRv6 Path Tracing Infrastructure This patch adds support for the infrastructure required to support SRv6 Path Tracing defined in https://datatracker.ietf.org/doc/draft-filsfils-spring-path-tracing/ Type: feature Change-Id: If3b09d6216490a60dd5a816577477b6399abc124 Signed-off-by: Ahmed Abdelsalam --- MAINTAINERS | 1 + src/vnet/CMakeLists.txt | 2 + src/vnet/srv6/sr_pt.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++ src/vnet/srv6/sr_pt.h | 68 ++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 src/vnet/srv6/sr_pt.c create mode 100644 src/vnet/srv6/sr_pt.h diff --git a/MAINTAINERS b/MAINTAINERS index e24d077b540..444871ce7ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: src/vnet/pg/ VNET Segment Routing (IPv6 and MPLS) I: sr M: Pablo Camarillo +M: Ahmed Abdelsalam F: src/vnet/srv6/ F: src/vnet/srmpls/ F: src/examples/srv6-sample-localsid/ diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 1cd5b58f85a..3c9ae80162c 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -817,11 +817,13 @@ list(APPEND VNET_SOURCES srv6/sr_policy_rewrite.c srv6/sr_steering.c srv6/sr_api.c + srv6/sr_pt.c ) list(APPEND VNET_HEADERS srv6/sr_packet.h srv6/sr.h + srv6/sr_pt.h ) list(APPEND VNET_API_FILES diff --git a/src/vnet/srv6/sr_pt.c b/src/vnet/srv6/sr_pt.c new file mode 100644 index 00000000000..28da12e22f4 --- /dev/null +++ b/src/vnet/srv6/sr_pt.c @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2022 Cisco Systems, Inc. + */ + +/** + * @file + * @brief SR Path Tracing (PT) + * + * PT CLI + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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; + + /* Create a new pt_iface */ + pool_get (sr_pt->sr_pt_iface, ls); + clib_memset (ls, 0, sizeof (*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 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]); + /* 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 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 id ingress-load " + " egress-load " + "tts-template ", + .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 ", + .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 diff --git a/src/vnet/srv6/sr_pt.h b/src/vnet/srv6/sr_pt.h new file mode 100644 index 00000000000..7242f90b6b3 --- /dev/null +++ b/src/vnet/srv6/sr_pt.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2022 Cisco Systems, Inc. + */ + +/** + * @file + * @brief SR Path Tracing data structures definitions + * + */ + +#ifndef included_vnet_sr_pt_h +#define included_vnet_sr_pt_h + +/*PT error codes*/ +#define SR_PT_ERR_NOENT -1 /* No such entry*/ +#define SR_PT_ERR_EXIST -2 /* Entry exists */ +#define SR_PT_ERR_IFACE_INVALID -3 /* IFACE invalid */ +#define SR_PT_ERR_ID_INVALID -4 /* ID invalid */ +#define SR_PT_ERR_LOAD_INVALID -5 /* LOAD invalid*/ +#define SR_PT_ERR_TTS_TEMPLATE_INVALID -6 /* TTS Template invalid */ + +/*PT paramters max values*/ +#define SR_PT_ID_MAX 4095 +#define SR_PT_LOAD_MAX 15 +#define SR_PT_TTS_TEMPLATE_MAX 3 + +/*PT TTS Templates*/ +#define SR_PT_TTS_TEMPLATE_0 0 +#define SR_PT_TTS_TEMPLATE_1 1 +#define SR_PT_TTS_TEMPLATE_2 2 +#define SR_PT_TTS_TEMPLATE_3 3 +#define SR_PT_TTS_TEMPLATE_DEFAULT 2 + +/*PT TTS Template shift value*/ +#define SR_PT_TTS_SHIFT_TEMPLATE_0 8 +#define SR_PT_TTS_SHIFT_TEMPLATE_1 12 +#define SR_PT_TTS_SHIFT_TEMPLATE_2 16 +#define SR_PT_TTS_SHIFT_TEMPLATE_3 20 + +typedef struct +{ + u32 iface; /**< Interface */ + u16 id; /**< Interface ID */ + u8 ingress_load; /**< Interface Ingress Load */ + u8 egress_load; /**< Interface Egress Load */ + u8 tts_template; /**< Interface TTS Template */ +} sr_pt_iface_t; + +/** + * @brief Path Tracing main datastructure + */ +typedef struct +{ + /* Pool of pt_iface instances */ + sr_pt_iface_t *sr_pt_iface; + + /* Hash table for pt iface parameters */ + mhash_t sr_pt_iface_index_hash; + +} sr_pt_main_t; + +extern sr_pt_main_t sr_pt_main; +extern int sr_pt_add_iface (u32 iface, u16 id, u8 ingress_load, u8 egress_load, + u8 tts_template); +extern int sr_pt_del_iface (u32 iface); +extern void *sr_pt_find_iface (u32 iface); + +#endif /* included_vnet_sr_pt_h */ -- cgit 1.2.3-korg