Line data Source code
1 : /* 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 : *
9 : * SR PT CLI
10 : *
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 :
27 : sr_pt_main_t sr_pt_main;
28 :
29 : void *
30 0 : sr_pt_find_iface (u32 iface)
31 : {
32 0 : sr_pt_main_t *sr_pt = &sr_pt_main;
33 : uword *p;
34 :
35 : /* Search for the item */
36 0 : p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
37 0 : if (p)
38 : {
39 : /* Retrieve sr_pt_iface */
40 0 : return pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
41 : }
42 0 : return NULL;
43 : }
44 :
45 : int
46 0 : sr_pt_add_iface (u32 iface, u16 id, u8 ingress_load, u8 egress_load,
47 : u8 tts_template)
48 : {
49 0 : sr_pt_main_t *sr_pt = &sr_pt_main;
50 : uword *p;
51 :
52 0 : sr_pt_iface_t *ls = 0;
53 :
54 0 : if (iface == (u32) ~0)
55 0 : return SR_PT_ERR_IFACE_INVALID;
56 :
57 : /* Search for the item */
58 0 : p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
59 :
60 0 : if (p)
61 0 : return SR_PT_ERR_EXIST;
62 :
63 0 : if (id > SR_PT_ID_MAX)
64 0 : return SR_PT_ERR_ID_INVALID;
65 :
66 0 : if (ingress_load > SR_PT_LOAD_MAX || egress_load > SR_PT_LOAD_MAX)
67 0 : return SR_PT_ERR_LOAD_INVALID;
68 :
69 0 : if (tts_template > SR_PT_TTS_TEMPLATE_MAX)
70 0 : return SR_PT_ERR_TTS_TEMPLATE_INVALID;
71 :
72 0 : vnet_feature_enable_disable ("ip6-output", "pt", iface, 1, 0, 0);
73 :
74 : /* Create a new sr_pt_iface */
75 0 : pool_get_zero (sr_pt->sr_pt_iface, ls);
76 0 : ls->iface = iface;
77 0 : ls->id = id;
78 0 : ls->ingress_load = ingress_load;
79 0 : ls->egress_load = egress_load;
80 0 : ls->tts_template = tts_template;
81 :
82 : /* Set hash key for searching sr_pt_iface by iface */
83 0 : mhash_set (&sr_pt->sr_pt_iface_index_hash, &iface, ls - sr_pt->sr_pt_iface,
84 : NULL);
85 0 : return 0;
86 : }
87 :
88 : int
89 0 : sr_pt_del_iface (u32 iface)
90 : {
91 0 : sr_pt_main_t *sr_pt = &sr_pt_main;
92 : uword *p;
93 :
94 0 : sr_pt_iface_t *ls = 0;
95 :
96 0 : if (iface == (u32) ~0)
97 0 : return SR_PT_ERR_IFACE_INVALID;
98 :
99 : /* Search for the item */
100 0 : p = mhash_get (&sr_pt->sr_pt_iface_index_hash, &iface);
101 :
102 0 : if (p)
103 : {
104 : /* Retrieve sr_pt_iface */
105 0 : ls = pool_elt_at_index (sr_pt->sr_pt_iface, p[0]);
106 0 : vnet_feature_enable_disable ("ip6-output", "pt", iface, 0, 0, 0);
107 : /* Delete sr_pt_iface */
108 0 : pool_put (sr_pt->sr_pt_iface, ls);
109 0 : mhash_unset (&sr_pt->sr_pt_iface_index_hash, &iface, NULL);
110 : }
111 : else
112 : {
113 0 : return SR_PT_ERR_NOENT;
114 : }
115 0 : return 0;
116 : }
117 :
118 : /**
119 : * @brief "sr pt add iface" CLI function.
120 : *
121 : * @see sr_pt_add_iface
122 : */
123 : static clib_error_t *
124 0 : sr_pt_add_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
125 : vlib_cli_command_t *cmd)
126 : {
127 0 : vnet_main_t *vnm = vnet_get_main ();
128 0 : u32 iface = (u32) ~0;
129 0 : u32 id = (u32) ~0;
130 0 : u32 ingress_load = 0;
131 0 : u32 egress_load = 0;
132 0 : u32 tts_template = SR_PT_TTS_TEMPLATE_DEFAULT;
133 :
134 : int rv;
135 :
136 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
137 : {
138 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
139 : ;
140 0 : else if (unformat (input, "id %u", &id))
141 : ;
142 0 : else if (unformat (input, "ingress-load %u", &ingress_load))
143 : ;
144 0 : else if (unformat (input, "egress-load %u", &egress_load))
145 : ;
146 0 : else if (unformat (input, "tts-template %u", &tts_template))
147 : ;
148 : else
149 0 : break;
150 : }
151 :
152 0 : rv = sr_pt_add_iface (iface, id, ingress_load, egress_load, tts_template);
153 :
154 0 : switch (rv)
155 : {
156 0 : case 0:
157 0 : break;
158 0 : case SR_PT_ERR_EXIST:
159 0 : return clib_error_return (0, "Error: Identical iface already exists.");
160 0 : case SR_PT_ERR_IFACE_INVALID:
161 0 : return clib_error_return (0, "Error: The iface name invalid.");
162 0 : case SR_PT_ERR_ID_INVALID:
163 0 : return clib_error_return (0, "Error: The iface id value invalid.");
164 0 : case SR_PT_ERR_LOAD_INVALID:
165 0 : return clib_error_return (
166 : 0, "Error: The iface ingress or egress load value invalid.");
167 0 : case SR_PT_ERR_TTS_TEMPLATE_INVALID:
168 0 : return clib_error_return (
169 : 0, "Error: The iface TTS Template value invalid.");
170 0 : default:
171 0 : return clib_error_return (0, "Error: unknown error.");
172 : }
173 0 : return 0;
174 : }
175 :
176 : /**
177 : * @brief "sr pt del iface" CLI function.
178 : *
179 : * @see sr_pt_del_iface
180 : */
181 : static clib_error_t *
182 0 : sr_pt_del_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
183 : vlib_cli_command_t *cmd)
184 : {
185 0 : vnet_main_t *vnm = vnet_get_main ();
186 0 : u32 iface = (u32) ~0;
187 :
188 : int rv;
189 :
190 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
191 : {
192 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &iface))
193 : ;
194 : else
195 0 : break;
196 : }
197 :
198 0 : rv = sr_pt_del_iface (iface);
199 :
200 0 : switch (rv)
201 : {
202 0 : case 0:
203 0 : break;
204 0 : case SR_PT_ERR_NOENT:
205 0 : return clib_error_return (0, "Error: No such iface.");
206 0 : case SR_PT_ERR_IFACE_INVALID:
207 0 : return clib_error_return (0, "Error: The iface name is not valid.");
208 0 : default:
209 0 : return clib_error_return (0, "Error: unknown error.");
210 : }
211 0 : return 0;
212 : }
213 :
214 : /**
215 : * @brief CLI function to show all SR PT interfcaes
216 : */
217 : static clib_error_t *
218 0 : sr_pt_show_iface_command_fn (vlib_main_t *vm, unformat_input_t *input,
219 : vlib_cli_command_t *cmd)
220 : {
221 0 : vnet_main_t *vnm = vnet_get_main ();
222 0 : sr_pt_main_t *sr_pt = &sr_pt_main;
223 0 : sr_pt_iface_t **sr_pt_iface_list = 0;
224 : sr_pt_iface_t *ls;
225 : int i;
226 :
227 0 : vlib_cli_output (vm, "SR PT Interfaces");
228 0 : vlib_cli_output (vm, "==================================");
229 :
230 0 : pool_foreach (ls, sr_pt->sr_pt_iface)
231 : {
232 0 : vec_add1 (sr_pt_iface_list, ls);
233 : };
234 :
235 0 : for (i = 0; i < vec_len (sr_pt_iface_list); i++)
236 : {
237 0 : ls = sr_pt_iface_list[i];
238 0 : 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 0 : format_vnet_sw_if_index_name, vnm, ls->iface, ls->id, ls->ingress_load,
243 0 : ls->egress_load, ls->tts_template);
244 0 : vlib_cli_output (vm, "--------------------------------");
245 : }
246 :
247 0 : return 0;
248 : }
249 :
250 272887 : 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,
256 : };
257 :
258 272887 : 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,
262 : };
263 :
264 272887 : 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,
268 : };
269 :
270 : /**
271 : * * @brief SR PT initialization
272 : * */
273 : clib_error_t *
274 559 : sr_pt_init (vlib_main_t *vm)
275 : {
276 559 : sr_pt_main_t *pt = &sr_pt_main;
277 559 : mhash_init (&pt->sr_pt_iface_index_hash, sizeof (uword), sizeof (u32));
278 559 : return 0;
279 : }
280 :
281 67759 : VLIB_INIT_FUNCTION (sr_pt_init);
|