Line data Source code
1 : /*
2 : * nsh_cli.c - nsh cli functions
3 : *
4 : * Copyright (c) 2019 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/vnet.h>
19 : #include <vnet/plugin/plugin.h>
20 : #include <nsh/nsh.h>
21 : #include <vnet/adj/adj.h>
22 :
23 : /* format from network order */
24 : u8 *
25 0 : format_nsh_pop_header (u8 * s, va_list * args)
26 : {
27 0 : return format_nsh_header (s, args);
28 : }
29 :
30 : u8 *
31 0 : format_nsh_pop_node_map_trace (u8 * s, va_list * args)
32 : {
33 0 : return format_nsh_node_map_trace (s, args);
34 : }
35 :
36 : static uword
37 0 : unformat_nsh_action (unformat_input_t * input, va_list * args)
38 : {
39 0 : u32 *result = va_arg (*args, u32 *);
40 : u32 tmp;
41 :
42 0 : if (unformat (input, "swap"))
43 0 : *result = NSH_ACTION_SWAP;
44 0 : else if (unformat (input, "push"))
45 0 : *result = NSH_ACTION_PUSH;
46 0 : else if (unformat (input, "pop"))
47 0 : *result = NSH_ACTION_POP;
48 0 : else if (unformat (input, "%d", &tmp))
49 0 : *result = tmp;
50 : else
51 0 : return 0;
52 :
53 0 : return 1;
54 : }
55 :
56 : static u8 *
57 0 : format_nsh_action (u8 * s, va_list * args)
58 : {
59 0 : u32 nsh_action = va_arg (*args, u32);
60 :
61 0 : switch (nsh_action)
62 : {
63 0 : case NSH_ACTION_SWAP:
64 0 : return format (s, "swap");
65 0 : case NSH_ACTION_PUSH:
66 0 : return format (s, "push");
67 0 : case NSH_ACTION_POP:
68 0 : return format (s, "pop");
69 0 : default:
70 0 : return format (s, "unknown %d", nsh_action);
71 : }
72 : return s;
73 : }
74 :
75 : u8 *
76 0 : format_nsh_map (u8 * s, va_list * args)
77 : {
78 0 : nsh_map_t *map = va_arg (*args, nsh_map_t *);
79 :
80 0 : s = format (s, "nsh entry nsp: %d nsi: %d ",
81 0 : (map->nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
82 0 : map->nsp_nsi & NSH_NSI_MASK);
83 0 : s = format (s, "maps to nsp: %d nsi: %d ",
84 0 : (map->mapped_nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
85 0 : map->mapped_nsp_nsi & NSH_NSI_MASK);
86 :
87 0 : s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
88 :
89 0 : switch (map->next_node)
90 : {
91 0 : case NSH_NODE_NEXT_ENCAP_GRE4:
92 : {
93 0 : s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index);
94 0 : break;
95 : }
96 0 : case NSH_NODE_NEXT_ENCAP_GRE6:
97 : {
98 0 : s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index);
99 0 : break;
100 : }
101 0 : case NSH_NODE_NEXT_ENCAP_VXLANGPE:
102 : {
103 0 : s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
104 0 : break;
105 : }
106 0 : case NSH_NODE_NEXT_ENCAP_VXLAN4:
107 : {
108 0 : s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
109 0 : break;
110 : }
111 0 : case NSH_NODE_NEXT_ENCAP_VXLAN6:
112 : {
113 0 : s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
114 0 : break;
115 : }
116 0 : case NSH_NODE_NEXT_DECAP_ETH_INPUT:
117 : {
118 0 : s = format (s, "encap-none");
119 0 : break;
120 : }
121 0 : case NSH_NODE_NEXT_ENCAP_LISP_GPE:
122 : {
123 0 : s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
124 0 : break;
125 : }
126 0 : case NSH_NODE_NEXT_ENCAP_ETHERNET:
127 : {
128 0 : s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index);
129 0 : break;
130 : }
131 0 : default:
132 0 : s = format (s, "only GRE and VXLANGPE support in this rev");
133 : }
134 :
135 0 : return s;
136 : }
137 :
138 : static adj_index_t
139 0 : nsh_get_adj_by_sw_if_index (u32 sw_if_index)
140 : {
141 0 : adj_index_t ai = ~0;
142 :
143 : /* *INDENT-OFF* */
144 0 : pool_foreach_index (ai, adj_pool)
145 : {
146 0 : if (sw_if_index == adj_get_sw_if_index(ai))
147 : {
148 0 : return ai;
149 : }
150 : }
151 : /* *INDENT-ON* */
152 :
153 0 : return ~0;
154 : }
155 :
156 :
157 : /**
158 : * CLI command for NSH map
159 : */
160 : static clib_error_t *
161 0 : nsh_add_del_map_command_fn (vlib_main_t * vm,
162 : unformat_input_t * input,
163 : vlib_cli_command_t * cmd)
164 : {
165 0 : unformat_input_t _line_input, *line_input = &_line_input;
166 0 : u8 is_add = 1;
167 : u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
168 0 : int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
169 0 : int nsh_action_set = 0;
170 0 : u32 next_node = ~0;
171 0 : u32 adj_index = ~0;
172 0 : u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
173 0 : u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
174 0 : nsh_add_del_map_args_t _a, *a = &_a;
175 : u32 map_index;
176 : int rv;
177 :
178 : /* Get a line of input. */
179 0 : if (!unformat_user (input, unformat_line_input, line_input))
180 0 : return 0;
181 :
182 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
183 : {
184 0 : if (unformat (line_input, "del"))
185 0 : is_add = 0;
186 0 : else if (unformat (line_input, "nsp %d", &nsp))
187 0 : nsp_set = 1;
188 0 : else if (unformat (line_input, "nsi %d", &nsi))
189 0 : nsi_set = 1;
190 0 : else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
191 0 : mapped_nsp_set = 1;
192 0 : else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
193 0 : mapped_nsi_set = 1;
194 0 : else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
195 : &nsh_action))
196 0 : nsh_action_set = 1;
197 0 : else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index))
198 0 : next_node = NSH_NODE_NEXT_ENCAP_GRE4;
199 0 : else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index))
200 0 : next_node = NSH_NODE_NEXT_ENCAP_GRE6;
201 0 : else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
202 0 : next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
203 0 : else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index))
204 0 : next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE;
205 0 : else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
206 0 : next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
207 0 : else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
208 0 : next_node = NSH_NODE_NEXT_ENCAP_VXLAN6;
209 0 : else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index))
210 : {
211 0 : next_node = NSH_NODE_NEXT_ENCAP_ETHERNET;
212 0 : adj_index = nsh_get_adj_by_sw_if_index (sw_if_index);
213 : }
214 : else
215 0 : if (unformat
216 : (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index))
217 0 : next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT;
218 : else
219 0 : return clib_error_return (0, "parse error: '%U'",
220 : format_unformat_error, line_input);
221 : }
222 :
223 0 : unformat_free (line_input);
224 :
225 0 : if (nsp_set == 0 || nsi_set == 0)
226 0 : return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
227 :
228 0 : if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
229 0 : return clib_error_return (0,
230 : "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
231 :
232 0 : if (nsh_action_set == 0)
233 0 : return clib_error_return (0, "nsh_action required: swap|push|pop.");
234 :
235 0 : if (next_node == ~0)
236 0 : return clib_error_return (0,
237 : "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none <tx_sw_if_index> <rx_sw_if_index>]");
238 :
239 0 : clib_memset (a, 0, sizeof (*a));
240 :
241 : /* set args structure */
242 0 : a->is_add = is_add;
243 0 : a->map.nsp_nsi = (nsp << NSH_NSP_SHIFT) | nsi;
244 0 : a->map.mapped_nsp_nsi = (mapped_nsp << NSH_NSP_SHIFT) | mapped_nsi;
245 0 : a->map.nsh_action = nsh_action;
246 0 : a->map.sw_if_index = sw_if_index;
247 0 : a->map.rx_sw_if_index = rx_sw_if_index;
248 0 : a->map.next_node = next_node;
249 0 : a->map.adj_index = adj_index;
250 :
251 0 : rv = nsh_add_del_map (a, &map_index);
252 :
253 0 : switch (rv)
254 : {
255 0 : case 0:
256 0 : break;
257 0 : case -1: //TODO API_ERROR_INVALID_VALUE:
258 0 : return clib_error_return (0,
259 : "mapping already exists. Remove it first.");
260 :
261 0 : case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
262 0 : return clib_error_return (0, "mapping does not exist.");
263 :
264 0 : default:
265 0 : return clib_error_return (0, "nsh_add_del_map returned %d", rv);
266 : }
267 :
268 0 : if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
269 0 : | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
270 : {
271 0 : rv = nsh_add_del_proxy_session (a);
272 :
273 0 : switch (rv)
274 : {
275 0 : case 0:
276 0 : break;
277 0 : case -1: //TODO API_ERROR_INVALID_VALUE:
278 0 : return clib_error_return (0,
279 : "nsh-proxy-session already exists. Remove it first.");
280 :
281 0 : case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
282 0 : return clib_error_return (0, "nsh-proxy-session does not exist.");
283 :
284 0 : default:
285 0 : return clib_error_return
286 : (0, "nsh_add_del_proxy_session() returned %d", rv);
287 : }
288 0 : }
289 :
290 0 : return 0;
291 : }
292 :
293 : /* *INDENT-OFF* */
294 58901 : VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
295 : .path = "create nsh map",
296 : .short_help =
297 : "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
298 : "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> "
299 : " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n",
300 : .function = nsh_add_del_map_command_fn,
301 : };
302 : /* *INDENT-ON* */
303 :
304 : /**
305 : * CLI command for showing the mapping between NSH entries
306 : */
307 : static clib_error_t *
308 0 : show_nsh_map_command_fn (vlib_main_t * vm,
309 : unformat_input_t * input, vlib_cli_command_t * cmd)
310 : {
311 0 : nsh_main_t *nm = &nsh_main;
312 : nsh_map_t *map;
313 :
314 0 : if (pool_elts (nm->nsh_mappings) == 0)
315 0 : vlib_cli_output (vm, "No nsh maps configured.");
316 :
317 0 : pool_foreach (map, nm->nsh_mappings)
318 : {
319 0 : vlib_cli_output (vm, "%U", format_nsh_map, map);
320 : }
321 :
322 0 : return 0;
323 : }
324 :
325 : /* *INDENT-OFF* */
326 58901 : VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
327 : .path = "show nsh map",
328 : .function = show_nsh_map_command_fn,
329 : };
330 : /* *INDENT-ON* */
331 :
332 : /**
333 : * CLI command for adding NSH entry
334 : */
335 : static clib_error_t *
336 0 : nsh_add_del_entry_command_fn (vlib_main_t * vm,
337 : unformat_input_t * input,
338 : vlib_cli_command_t * cmd)
339 : {
340 0 : unformat_input_t _line_input, *line_input = &_line_input;
341 0 : u8 is_add = 1;
342 0 : u8 ver_o_c = 0;
343 0 : u8 ttl = 63;
344 0 : u8 length = 0;
345 0 : u8 md_type = 0;
346 0 : u8 next_protocol = 1; /* default: ip4 */
347 : u32 nsp;
348 0 : u8 nsp_set = 0;
349 : u32 nsi;
350 0 : u8 nsi_set = 0;
351 : u32 nsp_nsi;
352 0 : u32 c1 = 0;
353 0 : u32 c2 = 0;
354 0 : u32 c3 = 0;
355 0 : u32 c4 = 0;
356 0 : u8 *data = 0;
357 : nsh_tlv_header_t tlv_header;
358 0 : u8 cur_len = 0, tlvs_len = 0;
359 : u8 *current;
360 0 : nsh_main_t *nm = &nsh_main;
361 0 : nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
362 0 : u8 option_size = 0;
363 : u32 tmp;
364 : int rv;
365 : u32 entry_index;
366 0 : nsh_add_del_entry_args_t _a, *a = &_a;
367 0 : u8 has_ioam_trace_option = 0;
368 :
369 : /* Get a line of input. */
370 0 : if (!unformat_user (input, unformat_line_input, line_input))
371 0 : return 0;
372 :
373 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
374 : {
375 0 : if (unformat (line_input, "del"))
376 0 : is_add = 0;
377 0 : else if (unformat (line_input, "version %d", &tmp))
378 0 : ver_o_c |= (tmp & 3) << 6;
379 0 : else if (unformat (line_input, "o-bit %d", &tmp))
380 0 : ver_o_c |= (tmp & 1) << 5;
381 0 : else if (unformat (line_input, "c-bit %d", &tmp))
382 0 : ver_o_c |= (tmp & 1) << 4;
383 0 : else if (unformat (line_input, "ttl %d", &ttl))
384 0 : ver_o_c |= (ttl & NSH_LEN_MASK) >> 2;
385 0 : else if (unformat (line_input, "md-type %d", &tmp))
386 0 : md_type = tmp;
387 0 : else if (unformat (line_input, "next-ip4"))
388 0 : next_protocol = 1;
389 0 : else if (unformat (line_input, "next-ip6"))
390 0 : next_protocol = 2;
391 0 : else if (unformat (line_input, "next-ethernet"))
392 0 : next_protocol = 3;
393 0 : else if (unformat (line_input, "c1 %d", &c1))
394 : ;
395 0 : else if (unformat (line_input, "c2 %d", &c2))
396 : ;
397 0 : else if (unformat (line_input, "c3 %d", &c3))
398 : ;
399 0 : else if (unformat (line_input, "c4 %d", &c4))
400 : ;
401 0 : else if (unformat (line_input, "nsp %d", &nsp))
402 0 : nsp_set = 1;
403 0 : else if (unformat (line_input, "nsi %d", &nsi))
404 0 : nsi_set = 1;
405 0 : else if (unformat (line_input, "tlv-ioam-trace"))
406 0 : has_ioam_trace_option = 1;
407 : else
408 0 : return clib_error_return (0, "parse error: '%U'",
409 : format_unformat_error, line_input);
410 : }
411 :
412 0 : unformat_free (line_input);
413 :
414 0 : if (nsp_set == 0)
415 0 : return clib_error_return (0, "nsp not specified");
416 :
417 0 : if (nsi_set == 0)
418 0 : return clib_error_return (0, "nsi not specified");
419 :
420 0 : if (md_type == 1 && has_ioam_trace_option == 1)
421 0 : return clib_error_return (0, "Invalid MD Type");
422 :
423 0 : nsp_nsi = (nsp << 8) | nsi;
424 :
425 0 : clib_memset (a, 0, sizeof (*a));
426 0 : a->is_add = is_add;
427 :
428 0 : if (md_type == 1)
429 : {
430 0 : a->nsh_entry.md.md1_data.c1 = c1;
431 0 : a->nsh_entry.md.md1_data.c2 = c2;
432 0 : a->nsh_entry.md.md1_data.c3 = c3;
433 0 : a->nsh_entry.md.md1_data.c4 = c4;
434 0 : length = (sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t)) >> 2;
435 : }
436 0 : else if (md_type == 2)
437 : {
438 0 : length = sizeof (nsh_base_header_t) >> 2;
439 :
440 0 : vec_free (a->nsh_entry.tlvs_data);
441 0 : tlvs_len = (MAX_METADATA_LEN << 2);
442 0 : vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
443 0 : a->nsh_entry.tlvs_data = data;
444 0 : current = data;
445 :
446 0 : if (has_ioam_trace_option)
447 : {
448 0 : tlv_header.class = clib_host_to_net_u16 (NSH_MD2_IOAM_CLASS);
449 0 : tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
450 : /* Uses network order's class and type to lookup */
451 : nsh_option =
452 0 : nsh_md2_lookup_option (tlv_header.class, tlv_header.type);
453 0 : if (nsh_option == NULL)
454 0 : return clib_error_return (0, "iOAM Trace not registered");
455 :
456 0 : if (nm->add_options[nsh_option->option_id] != NULL)
457 : {
458 0 : if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current,
459 : &option_size))
460 : {
461 0 : return clib_error_return (0, "Invalid MD Type");
462 : }
463 : }
464 :
465 0 : nm->options_size[nsh_option->option_id] = option_size;
466 : /* round to 4-byte */
467 0 : option_size = (((option_size + 3) >> 2) << 2);
468 :
469 0 : cur_len += option_size;
470 0 : current = data + option_size;
471 : }
472 :
473 : /* Add more options' parsing */
474 :
475 0 : a->nsh_entry.tlvs_len = cur_len;
476 0 : length += (cur_len >> 2);
477 : }
478 0 : length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6);
479 :
480 : #define _(x) a->nsh_entry.nsh_base.x = x;
481 0 : foreach_copy_nsh_base_hdr_field;
482 : #undef _
483 :
484 0 : rv = nsh_add_del_entry (a, &entry_index);
485 :
486 0 : switch (rv)
487 : {
488 0 : case 0:
489 0 : break;
490 0 : default:
491 0 : return clib_error_return (0, "nsh_add_del_entry returned %d", rv);
492 : }
493 :
494 0 : return 0;
495 : }
496 :
497 : /* *INDENT-OFF* */
498 58901 : VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
499 : .path = "create nsh entry",
500 : .short_help =
501 : "create nsh entry {nsp <nn> nsi <nn>} [ttl <nn>] [md-type <nn>]"
502 : " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",
503 : .function = nsh_add_del_entry_command_fn,
504 : };
505 : /* *INDENT-ON* */
506 :
507 : /* format from network order */
508 : u8 *
509 0 : format_nsh_header (u8 * s, va_list * args)
510 : {
511 0 : nsh_main_t *nm = &nsh_main;
512 : nsh_md2_data_t *opt0;
513 : nsh_md2_data_t *limit0;
514 : nsh_option_map_t *nsh_option;
515 0 : u8 option_len = 0;
516 :
517 0 : u8 *header = va_arg (*args, u8 *);
518 0 : nsh_base_header_t *nsh_base = (nsh_base_header_t *) header;
519 0 : nsh_md1_data_t *nsh_md1 = (nsh_md1_data_t *) (nsh_base + 1);
520 0 : nsh_md2_data_t *nsh_md2 = (nsh_md2_data_t *) (nsh_base + 1);
521 0 : opt0 = (nsh_md2_data_t *) nsh_md2;
522 0 : limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 +
523 0 : ((nsh_base->length & NSH_LEN_MASK) * 4
524 : - sizeof (nsh_base_header_t)));
525 :
526 0 : s = format (s, "nsh ver %d ", (nsh_base->ver_o_c >> 6));
527 0 : if (nsh_base->ver_o_c & NSH_O_BIT)
528 0 : s = format (s, "O-set ");
529 :
530 0 : if (nsh_base->ver_o_c & NSH_C_BIT)
531 0 : s = format (s, "C-set ");
532 :
533 0 : s = format (s, "ttl %d ", (nsh_base->ver_o_c & NSH_TTL_H4_MASK) << 2 |
534 0 : (nsh_base->length & NSH_TTL_L2_MASK) >> 6);
535 :
536 0 : s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
537 0 : (nsh_base->length & NSH_LEN_MASK),
538 0 : (nsh_base->length & NSH_LEN_MASK) * 4,
539 0 : nsh_base->md_type, nsh_base->next_protocol);
540 :
541 0 : s = format (s, " service path %d service index %d\n",
542 0 : (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) &
543 : NSH_NSP_MASK,
544 0 : clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK);
545 :
546 0 : if (nsh_base->md_type == 1)
547 : {
548 0 : s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
549 : clib_net_to_host_u32 (nsh_md1->c1),
550 : clib_net_to_host_u32 (nsh_md1->c2),
551 : clib_net_to_host_u32 (nsh_md1->c3),
552 : clib_net_to_host_u32 (nsh_md1->c4));
553 : }
554 0 : else if (nsh_base->md_type == 2)
555 : {
556 0 : s = format (s, " Supported TLVs: \n");
557 :
558 : /* Scan the set of variable metadata, network order */
559 0 : while (opt0 < limit0)
560 : {
561 0 : nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
562 0 : if (nsh_option != NULL)
563 : {
564 0 : if (nm->trace[nsh_option->option_id] != NULL)
565 : {
566 0 : s = (*nm->trace[nsh_option->option_id]) (s, opt0);
567 : }
568 : else
569 : {
570 : s =
571 0 : format (s, "\n untraced option %d length %d",
572 0 : opt0->type, opt0->length);
573 : }
574 : }
575 : else
576 : {
577 : s =
578 0 : format (s, "\n unrecognized option %d length %d",
579 0 : opt0->type, opt0->length);
580 : }
581 :
582 : /* round to 4-byte */
583 0 : option_len = ((opt0->length + 3) >> 2) << 2;
584 0 : opt0 =
585 0 : (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
586 : option_len);
587 : }
588 : }
589 :
590 0 : return s;
591 : }
592 :
593 : u8 *
594 0 : format_nsh_node_map_trace (u8 * s, va_list * args)
595 : {
596 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
597 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
598 0 : nsh_input_trace_t *t = va_arg (*args, nsh_input_trace_t *);
599 :
600 0 : s = format (s, "\n %U", format_nsh_header, &(t->trace_data));
601 :
602 0 : return s;
603 : }
604 :
605 : static clib_error_t *
606 0 : show_nsh_entry_command_fn (vlib_main_t * vm,
607 : unformat_input_t * input, vlib_cli_command_t * cmd)
608 : {
609 0 : nsh_main_t *nm = &nsh_main;
610 : nsh_entry_t *nsh_entry;
611 :
612 0 : if (pool_elts (nm->nsh_entries) == 0)
613 0 : vlib_cli_output (vm, "No nsh entries configured.");
614 :
615 0 : pool_foreach (nsh_entry, nm->nsh_entries)
616 : {
617 0 : vlib_cli_output (vm, "%U", format_nsh_header, nsh_entry->rewrite);
618 0 : vlib_cli_output (vm, " rewrite_size: %d bytes", nsh_entry->rewrite_size);
619 : }
620 :
621 0 : return 0;
622 : }
623 :
624 : /* *INDENT-OFF* */
625 58901 : VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
626 : .path = "show nsh entry",
627 : .function = show_nsh_entry_command_fn,
628 : };
629 : /* *INDENT-ON* */
630 :
631 : /*
632 : * fd.io coding-style-patch-verification: ON
633 : *
634 : * Local Variables:
635 : * eval: (c-set-style "gnu")
636 : * End:
637 : */
|