blob: 6299faa84ab343f2eaa8fbb56d7dfa4058daea73 [file] [log] [blame]
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +00001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2022 Cisco Systems, Inc.
3 */
4
5/**
6 * @file
7 * @brief SR Path Tracing (PT)
8 *
Ahmed Abdelsalamb0057282022-06-29 16:30:21 +00009 * SR PT CLI
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +000010 *
11 */
12
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>
23
24#include <vppinfra/error.h>
25#include <vppinfra/elog.h>
26
27sr_pt_main_t sr_pt_main;
28
29void *
30sr_pt_find_iface (u32 iface)
31{
32 sr_pt_main_t *sr_pt = &sr_pt_main;
33 uword *p;
34
35 /* Search for the item */
36 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
37 if (p)
38 {
Ahmed Abdelsalamb0057282022-06-29 16:30:21 +000039 /* Retrieve sr_pt_iface */
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +000040 return pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
41 }
42 return NULL;
43}
44
45int
46sr_pt_add_iface (u32 iface, u16 id, u8 ingress_load, u8 egress_load,
47 u8 tts_template)
48{
49 sr_pt_main_t *sr_pt = &sr_pt_main;
50 uword *p;
51
52 sr_pt_iface_t *ls = 0;
53
54 if (iface == (u32) ~0)
55 return SR_PT_ERR_IFACE_INVALID;
56
57 /* Search for the item */
58 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
59
60 if (p)
61 return SR_PT_ERR_EXIST;
62
63 if (id > SR_PT_ID_MAX)
64 return SR_PT_ERR_ID_INVALID;
65
66 if (ingress_load > SR_PT_LOAD_MAX || egress_load > SR_PT_LOAD_MAX)
67 return SR_PT_ERR_LOAD_INVALID;
68
69 if (tts_template > SR_PT_TTS_TEMPLATE_MAX)
70 return SR_PT_ERR_TTS_TEMPLATE_INVALID;
71
Julian Klaiber39d6dec2022-10-18 10:37:14 +020072 vnet_feature_enable_disable ("ip6-output", "pt", iface, 1, 0, 0);
73
Ahmed Abdelsalamb0057282022-06-29 16:30:21 +000074 /* Create a new sr_pt_iface */
75 pool_get_zero (sr_pt->sr_pt_iface, ls);
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +000076 ls->iface = iface;
77 ls->id = id;
78 ls->ingress_load = ingress_load;
79 ls->egress_load = egress_load;
80 ls->tts_template = tts_template;
81
Ahmed Abdelsalamb0057282022-06-29 16:30:21 +000082 /* Set hash key for searching sr_pt_iface by iface */
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +000083 mhash_set (&sr_pt->sr_pt_iface_index_hash, &iface, ls - sr_pt->sr_pt_iface,
84 NULL);
85 return 0;
86}
87
88int
89sr_pt_del_iface (u32 iface)
90{
91 sr_pt_main_t *sr_pt = &sr_pt_main;
92 uword *p;
93
94 sr_pt_iface_t *ls = 0;
95
96 if (iface == (u32) ~0)
97 return SR_PT_ERR_IFACE_INVALID;
98
99 /* Search for the item */
100 p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
101
102 if (p)
103 {
104 /* Retrieve sr_pt_iface */
105 ls = pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
Julian Klaiber39d6dec2022-10-18 10:37:14 +0200106 vnet_feature_enable_disable ("ip6-output", "pt", iface, 0, 0, 0);
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +0000107 /* 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);
110 }
111 else
112 {
113 return SR_PT_ERR_NOENT;
114 }
115 return 0;
116}
117
118/**
119 * @brief "sr pt add iface" CLI function.
120 *
121 * @see sr_pt_add_iface
122 */
123static clib_error_t *
124sr_pt_add_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
125 vlib_cli_command_t *cmd)
126{
127 vnet_main_t *vnm = vnet_get_main ();
128 u32 iface = (u32) ~0;
129 u32 id = (u32) ~0;
130 u32 ingress_load = 0;
131 u32 egress_load = 0;
132 u32 tts_template = SR_PT_TTS_TEMPLATE_DEFAULT;
133
134 int rv;
135
136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
137 {
138 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
139 ;
140 else if (unformat (input, "id %u", &id))
141 ;
142 else if (unformat (input, "ingress-load %u", &ingress_load))
143 ;
144 else if (unformat (input, "egress-load %u", &egress_load))
145 ;
146 else if (unformat (input, "tts-template %u", &tts_template))
147 ;
148 else
149 break;
150 }
151
152 rv = sr_pt_add_iface (iface, id, ingress_load, egress_load, tts_template);
153
154 switch (rv)
155 {
156 case 0:
157 break;
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.");
170 default:
171 return clib_error_return (0, "Error: unknown error.");
172 }
173 return 0;
174}
175
176/**
177 * @brief "sr pt del iface" CLI function.
178 *
179 * @see sr_pt_del_iface
180 */
181static clib_error_t *
182sr_pt_del_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
183 vlib_cli_command_t *cmd)
184{
185 vnet_main_t *vnm = vnet_get_main ();
186 u32 iface = (u32) ~0;
187
188 int rv;
189
190 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
191 {
192 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
193 ;
194 else
195 break;
196 }
197
198 rv = sr_pt_del_iface (iface);
199
200 switch (rv)
201 {
202 case 0:
203 break;
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.");
208 default:
209 return clib_error_return (0, "Error: unknown error.");
210 }
211 return 0;
212}
213
214/**
Ahmed Abdelsalamb0057282022-06-29 16:30:21 +0000215 * @brief CLI function to show all SR PT interfcaes
Ahmed Abdelsalamc933bb72022-06-29 11:08:42 +0000216 */
217static clib_error_t *
218sr_pt_show_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
219 vlib_cli_command_t *cmd)
220{
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;
224 sr_pt_iface_t *ls;
225 int i;
226
227 vlib_cli_output (vm, "SR PT Interfaces");
228 vlib_cli_output (vm, "==================================");
229
230 pool_foreach (ls, sr_pt->sr_pt_iface)
231 {
232 vec_add1 (sr_pt_iface_list, ls);
233 };
234
235 for (i = 0; i < vec_len (sr_pt_iface_list); i++)
236 {
237 ls = sr_pt_iface_list[i];
238 vlib_cli_output (
239 vm,
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, "--------------------------------");
245 }
246
247 return 0;
248}
249
250VLIB_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,
256};
257
258VLIB_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,
262};
263
264VLIB_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,
268};
269
270/**
271 * * @brief SR PT initialization
272 * */
273clib_error_t *
274sr_pt_init (vlib_main_t *vm)
275{
276 sr_pt_main_t *pt = &sr_pt_main;
277 mhash_init (&pt->sr_pt_iface_index_hash, sizeof (uword), sizeof (u32));
278 return 0;
279}
280
281VLIB_INIT_FUNCTION (sr_pt_init);