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 <ahabdels@cisco.com>
This commit is contained in:
Ahmed Abdelsalam
2022-06-29 11:08:42 +00:00
committed by Damjan Marion
parent 0c3ca59e3f
commit c933bb7e37
4 changed files with 350 additions and 0 deletions

View File

@ -180,6 +180,7 @@ F: src/vnet/pg/
VNET Segment Routing (IPv6 and MPLS)
I: sr
M: Pablo Camarillo <pcamaril@cisco.com>
M: Ahmed Abdelsalam <ahabdels@cisco.com>
F: src/vnet/srv6/
F: src/vnet/srmpls/
F: src/examples/srv6-sample-localsid/

View File

@ -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

279
src/vnet/srv6/sr_pt.c Normal file
View File

@ -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 <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 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 <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);

68
src/vnet/srv6/sr_pt.h Normal file
View File

@ -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 */