1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2022 Cisco Systems, Inc.
7 * @brief SR Path Tracing (PT)
13 #include <vlib/vlib.h>
14 #include <vnet/vnet.h>
15 #include <vnet/srv6/sr.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/srv6/sr_packet.h>
18 #include <vnet/ip/ip6_packet.h>
19 #include <vnet/fib/ip6_fib.h>
20 #include <vnet/dpo/dpo.h>
21 #include <vnet/adj/adj.h>
22 #include <vnet/srv6/sr_pt.h>
24 #include <vppinfra/error.h>
25 #include <vppinfra/elog.h>
27 sr_pt_main_t sr_pt_main;
30 sr_pt_find_iface (u32 iface)
32 sr_pt_main_t *sr_pt = &sr_pt_main;
35 /* Search for the item */
36 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
39 /* Retrieve sr_pt_iface */
40 return pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
46 sr_pt_add_iface (u32 iface, u16 id, u8 ingress_load, u8 egress_load,
49 sr_pt_main_t *sr_pt = &sr_pt_main;
52 sr_pt_iface_t *ls = 0;
54 if (iface == (u32) ~0)
55 return SR_PT_ERR_IFACE_INVALID;
57 /* Search for the item */
58 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
61 return SR_PT_ERR_EXIST;
63 if (id > SR_PT_ID_MAX)
64 return SR_PT_ERR_ID_INVALID;
66 if (ingress_load > SR_PT_LOAD_MAX || egress_load > SR_PT_LOAD_MAX)
67 return SR_PT_ERR_LOAD_INVALID;
69 if (tts_template > SR_PT_TTS_TEMPLATE_MAX)
70 return SR_PT_ERR_TTS_TEMPLATE_INVALID;
72 vnet_feature_enable_disable ("ip6-output", "pt", iface, 1, 0, 0);
74 /* Create a new sr_pt_iface */
75 pool_get_zero (sr_pt->sr_pt_iface, ls);
78 ls->ingress_load = ingress_load;
79 ls->egress_load = egress_load;
80 ls->tts_template = tts_template;
82 /* Set hash key for searching sr_pt_iface by iface */
83 mhash_set (&sr_pt->sr_pt_iface_index_hash, &iface, ls - sr_pt->sr_pt_iface,
89 sr_pt_del_iface (u32 iface)
91 sr_pt_main_t *sr_pt = &sr_pt_main;
94 sr_pt_iface_t *ls = 0;
96 if (iface == (u32) ~0)
97 return SR_PT_ERR_IFACE_INVALID;
99 /* Search for the item */
100 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
104 /* Retrieve sr_pt_iface */
105 ls = pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
106 vnet_feature_enable_disable ("ip6-output", "pt", iface, 0, 0, 0);
107 /* Delete sr_pt_iface */
108 pool_put (sr_pt->sr_pt_iface, ls);
109 mhash_unset (&sr_pt->sr_pt_iface_index_hash, &iface, NULL);
113 return SR_PT_ERR_NOENT;
119 * @brief "sr pt add iface" CLI function.
121 * @see sr_pt_add_iface
123 static clib_error_t *
124 sr_pt_add_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
125 vlib_cli_command_t *cmd)
127 vnet_main_t *vnm = vnet_get_main ();
128 u32 iface = (u32) ~0;
130 u32 ingress_load = 0;
132 u32 tts_template = SR_PT_TTS_TEMPLATE_DEFAULT;
136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
138 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
140 else if (unformat (input, "id %u", &id))
142 else if (unformat (input, "ingress-load %u", &ingress_load))
144 else if (unformat (input, "egress-load %u", &egress_load))
146 else if (unformat (input, "tts-template %u", &tts_template))
152 rv = sr_pt_add_iface (iface, id, ingress_load, egress_load, tts_template);
158 case SR_PT_ERR_EXIST:
159 return clib_error_return (0, "Error: Identical iface already exists.");
160 case SR_PT_ERR_IFACE_INVALID:
161 return clib_error_return (0, "Error: The iface name invalid.");
162 case SR_PT_ERR_ID_INVALID:
163 return clib_error_return (0, "Error: The iface id value invalid.");
164 case SR_PT_ERR_LOAD_INVALID:
165 return clib_error_return (
166 0, "Error: The iface ingress or egress load value invalid.");
167 case SR_PT_ERR_TTS_TEMPLATE_INVALID:
168 return clib_error_return (
169 0, "Error: The iface TTS Template value invalid.");
171 return clib_error_return (0, "Error: unknown error.");
177 * @brief "sr pt del iface" CLI function.
179 * @see sr_pt_del_iface
181 static clib_error_t *
182 sr_pt_del_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
183 vlib_cli_command_t *cmd)
185 vnet_main_t *vnm = vnet_get_main ();
186 u32 iface = (u32) ~0;
190 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
192 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
198 rv = sr_pt_del_iface (iface);
204 case SR_PT_ERR_NOENT:
205 return clib_error_return (0, "Error: No such iface.");
206 case SR_PT_ERR_IFACE_INVALID:
207 return clib_error_return (0, "Error: The iface name is not valid.");
209 return clib_error_return (0, "Error: unknown error.");
215 * @brief CLI function to show all SR PT interfcaes
217 static clib_error_t *
218 sr_pt_show_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
219 vlib_cli_command_t *cmd)
221 vnet_main_t *vnm = vnet_get_main ();
222 sr_pt_main_t *sr_pt = &sr_pt_main;
223 sr_pt_iface_t **sr_pt_iface_list = 0;
227 vlib_cli_output (vm, "SR PT Interfaces");
228 vlib_cli_output (vm, "==================================");
230 pool_foreach (ls, sr_pt->sr_pt_iface)
232 vec_add1 (sr_pt_iface_list, ls);
235 for (i = 0; i < vec_len (sr_pt_iface_list); i++)
237 ls = sr_pt_iface_list[i];
240 "\tiface : \t%U\n\tid : \t%d\n\tingress-load: "
241 "\t%d\n\tegress-load : \t%d\n\ttts-template: \t%d ",
242 format_vnet_sw_if_index_name, vnm, ls->iface, ls->id, ls->ingress_load,
243 ls->egress_load, ls->tts_template);
244 vlib_cli_output (vm, "--------------------------------");
250 VLIB_CLI_COMMAND (sr_pt_add_iface_command, static) = {
251 .path = "sr pt add iface",
252 .short_help = "sr pt add iface <iface-name> id <pt-iface-id> ingress-load "
253 "<ingress-load-value> egress-load <egress-load-value> "
254 "tts-template <tts-template-value>",
255 .function = sr_pt_add_iface_command_fn,
258 VLIB_CLI_COMMAND (sr_pt_del_iface_command, static) = {
259 .path = "sr pt del iface",
260 .short_help = "sr pt del iface <iface-name>",
261 .function = sr_pt_del_iface_command_fn,
264 VLIB_CLI_COMMAND (sr_pt_show_iface_command, static) = {
265 .path = "sr pt show iface",
266 .short_help = "sr pt show iface",
267 .function = sr_pt_show_iface_command_fn,
271 * * @brief SR PT initialization
274 sr_pt_init (vlib_main_t *vm)
276 sr_pt_main_t *pt = &sr_pt_main;
277 mhash_init (&pt->sr_pt_iface_index_hash, sizeof (uword), sizeof (u32));
281 VLIB_INIT_FUNCTION (sr_pt_init);