blob: ef3fccc8b4b23e2cd4ceba8acf19a1006c0d6b25 [file] [log] [blame]
Klement Sekerade4582b2016-09-13 12:27:08 +02001/*
2 * Copyright (c) 2011-2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * @file
18 * @brief LLDP CLI handling
19 *
20 */
Damjan Marion864d8572019-09-19 18:43:42 +020021#include <vnet/ethernet/ethernet.h>
Neale Ranns3f9fdd92020-09-18 12:58:40 +000022#include <vnet/ip/ip.h>
23#include <lldp/lldp.h>
24#include <lldp/lldp_node.h>
Klement Sekerade4582b2016-09-13 12:27:08 +020025
26#ifndef ETHER_ADDR_LEN
27#include <net/ethernet.h>
28#endif
29
Klement Sekerade4582b2016-09-13 12:27:08 +020030static clib_error_t *
31lldp_cfg_err_to_clib_err (lldp_cfg_err_t e)
32{
33
34 switch (e)
35 {
36 case lldp_ok:
37 return 0;
38 case lldp_not_supported:
39 return clib_error_return (0, "not supported");
40 case lldp_invalid_arg:
41 return clib_error_return (0, "invalid argument");
Klement Sekera149fd3f2020-10-02 14:12:37 +000042 case lldp_internal_error:
43 return clib_error_return (0, "internal error");
Klement Sekerade4582b2016-09-13 12:27:08 +020044 }
45 return 0;
46}
47
Steve Shin99a0e602017-07-01 04:16:20 +000048lldp_cfg_err_t
Steve Shin9a6fcef2017-10-11 13:55:16 -070049lldp_cfg_intf_set (u32 hw_if_index, u8 ** port_desc, u8 ** mgmt_ip4,
50 u8 ** mgmt_ip6, u8 ** mgmt_oid, int enable)
Klement Sekerade4582b2016-09-13 12:27:08 +020051{
Dmitry Vakhrushevdecf51a2020-10-12 13:43:39 +030052 clib_error_t *error = 0;
Klement Sekerade4582b2016-09-13 12:27:08 +020053 lldp_main_t *lm = &lldp_main;
54 vnet_main_t *vnm = lm->vnet_main;
55 ethernet_main_t *em = &ethernet_main;
Steve Shincda4c882017-10-25 11:16:45 -070056 const vnet_hw_interface_t *hi;
57 const ethernet_interface_t *eif;
Klement Sekerade4582b2016-09-13 12:27:08 +020058
Steve Shincda4c882017-10-25 11:16:45 -070059 if (pool_is_free_index (vnm->interface_main.hw_interfaces, hw_if_index))
60 {
61 return lldp_invalid_arg;
62 }
63
64 hi = vnet_get_hw_interface (vnm, hw_if_index);
65 eif = ethernet_get_interface (em, hw_if_index);
Klement Sekerade4582b2016-09-13 12:27:08 +020066 if (!eif)
67 {
68 return lldp_not_supported;
69 }
70
71 if (enable)
72 {
73 lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
74 if (n)
75 {
76 /* already enabled */
Steve Shin99a0e602017-07-01 04:16:20 +000077 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +020078 }
79 n = lldp_create_intf (lm, hw_if_index);
Steve Shin99a0e602017-07-01 04:16:20 +000080
81 if (port_desc && *port_desc)
82 {
83 n->port_desc = *port_desc;
84 *port_desc = NULL;
85 }
86
Steve Shin9a6fcef2017-10-11 13:55:16 -070087 if (mgmt_ip4 && *mgmt_ip4)
88 {
89 n->mgmt_ip4 = *mgmt_ip4;
90 *mgmt_ip4 = NULL;
91 }
92
93 if (mgmt_ip6 && *mgmt_ip6)
94 {
95 n->mgmt_ip6 = *mgmt_ip6;
96 *mgmt_ip6 = NULL;
97 }
98
99 if (mgmt_oid && *mgmt_oid)
100 {
101 n->mgmt_oid = *mgmt_oid;
Dave Wallacef13f6a42017-12-18 17:19:21 -0500102 *mgmt_oid = NULL;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700103 }
104
Dmitry Vakhrushev4a98cf92020-10-16 23:39:28 +0300105 /* Add MAC address to an interface's filter */
106 if (hi->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER)
Klement Sekera149fd3f2020-10-02 14:12:37 +0000107 {
Dmitry Vakhrushev4a98cf92020-10-16 23:39:28 +0300108 error =
109 vnet_hw_interface_add_del_mac_address (lm->vnet_main,
110 hw_if_index,
111 lldp_mac_addr,
112 1 /* is_add */ );
113 if (error)
114 {
115 clib_error_free (error);
116 lldp_delete_intf (lm, n);
117 return lldp_internal_error;
118 }
Klement Sekera149fd3f2020-10-02 14:12:37 +0000119 }
120
Klement Sekerade4582b2016-09-13 12:27:08 +0200121 const vnet_sw_interface_t *sw =
122 vnet_get_sw_interface (lm->vnet_main, hi->sw_if_index);
Steven Luong5ad541e2019-08-27 07:43:27 -0700123 if (sw->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP))
Klement Sekerade4582b2016-09-13 12:27:08 +0200124 {
125 lldp_schedule_intf (lm, n);
126 }
127 }
128 else
129 {
130 lldp_intf_t *n = lldp_get_intf (lm, hi->sw_if_index);
131 lldp_delete_intf (lm, n);
Dmitry Vakhrushev4a98cf92020-10-16 23:39:28 +0300132 /* Remove MAC address from the interface's filter */
133 if ((n) && (hi->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER))
Klement Sekera149fd3f2020-10-02 14:12:37 +0000134 {
Dmitry Vakhrushevdecf51a2020-10-12 13:43:39 +0300135 error =
Dmitry Vakhrushev4a98cf92020-10-16 23:39:28 +0300136 vnet_hw_interface_add_del_mac_address (lm->vnet_main,
137 hw_if_index,
Dmitry Vakhrushevdecf51a2020-10-12 13:43:39 +0300138 lldp_mac_addr,
139 0 /* is_add */ );
140 if (error)
141 {
142 clib_error_free (error);
143 }
Klement Sekera149fd3f2020-10-02 14:12:37 +0000144 }
Klement Sekerade4582b2016-09-13 12:27:08 +0200145 }
146
Steve Shin99a0e602017-07-01 04:16:20 +0000147 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +0200148}
149
150static clib_error_t *
151lldp_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
152 vlib_cli_command_t * cmd)
153{
154 lldp_main_t *lm = &lldp_main;
155 vnet_main_t *vnm = lm->vnet_main;
Steve Shin99a0e602017-07-01 04:16:20 +0000156 u32 sw_if_index = (u32) ~ 0;
157 int enable = 1;
158 u8 *port_desc = NULL;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700159 u8 *mgmt_ip4 = NULL, *mgmt_ip6 = NULL, *mgmt_oid = NULL;
160 ip4_address_t ip4_addr;
161 ip6_address_t ip6_addr;
Klement Sekerade4582b2016-09-13 12:27:08 +0200162
Steve Shin99a0e602017-07-01 04:16:20 +0000163 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Klement Sekerade4582b2016-09-13 12:27:08 +0200164 {
Steve Shin99a0e602017-07-01 04:16:20 +0000165 if (unformat (input, "sw_if_index %d", &sw_if_index))
166 ;
167 if (unformat
168 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
169 ;
170 else if (unformat (input, "disable"))
171 enable = 0;
172 else if (unformat (input, "port-desc %s", &port_desc))
173 ;
174 else
Steve Shin9a6fcef2017-10-11 13:55:16 -0700175 if (unformat (input, "mgmt-ip4 %U", unformat_ip4_address, &ip4_addr))
176 {
177 vec_validate (mgmt_ip4, sizeof (ip4_address_t) - 1);
178 clib_memcpy (mgmt_ip4, &ip4_addr, vec_len (mgmt_ip4));
179 }
180 else
181 if (unformat (input, "mgmt-ip6 %U", unformat_ip6_address, &ip6_addr))
182 {
183 vec_validate (mgmt_ip6, sizeof (ip6_address_t) - 1);
184 clib_memcpy (mgmt_ip6, &ip6_addr, vec_len (mgmt_ip6));
185 }
186 else if (unformat (input, "mgmt-oid %s", &mgmt_oid))
187 ;
188 else
Steve Shin99a0e602017-07-01 04:16:20 +0000189 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200190 }
Steve Shin99a0e602017-07-01 04:16:20 +0000191
192 if (sw_if_index == (u32) ~ 0)
193 return clib_error_return (0, "Interface name is invalid!");
194
195 return lldp_cfg_err_to_clib_err (lldp_cfg_intf_set (sw_if_index,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700196 &port_desc, &mgmt_ip4,
197 &mgmt_ip6, &mgmt_oid,
198 enable));
Klement Sekerade4582b2016-09-13 12:27:08 +0200199}
200
Steve Shin99a0e602017-07-01 04:16:20 +0000201lldp_cfg_err_t
Klement Sekerade4582b2016-09-13 12:27:08 +0200202lldp_cfg_set (u8 ** host, int hold_time, int tx_interval)
203{
204 lldp_main_t *lm = &lldp_main;
205 int reschedule = 0;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700206
Klement Sekerade4582b2016-09-13 12:27:08 +0200207 if (host && *host)
208 {
209 vec_free (lm->sys_name);
210 lm->sys_name = *host;
211 *host = NULL;
212 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700213
Klement Sekerade4582b2016-09-13 12:27:08 +0200214 if (hold_time)
215 {
216 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
217 {
218 return lldp_invalid_arg;
219 }
220 if (lm->msg_tx_hold != hold_time)
221 {
222 lm->msg_tx_hold = hold_time;
223 reschedule = 1;
224 }
225 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700226
Klement Sekerade4582b2016-09-13 12:27:08 +0200227 if (tx_interval)
228 {
229 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
230 tx_interval > LLDP_MAX_TX_INTERVAL)
231 {
232 return lldp_invalid_arg;
233 }
234 if (lm->msg_tx_interval != tx_interval)
235 {
236 reschedule = 1;
237 lm->msg_tx_interval = tx_interval;
238 }
239 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700240
Klement Sekerade4582b2016-09-13 12:27:08 +0200241 if (reschedule)
242 {
243 vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
244 LLDP_EVENT_RESCHEDULE, 0);
245 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700246
Klement Sekerade4582b2016-09-13 12:27:08 +0200247 return lldp_ok;
248}
249
250static clib_error_t *
251lldp_cfg_cmd (vlib_main_t * vm, unformat_input_t * input,
252 vlib_cli_command_t * cmd)
253{
254 int hold_time = 0;
255 int tx_interval = 0;
256 u8 *host = NULL;
257 clib_error_t *ret = NULL;
258
259 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
260 {
261 if (unformat (input, "system-name %s", &host))
262 {
263 }
264 else if (unformat (input, "tx-hold %d", &hold_time))
265 {
266 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
267 {
268 ret =
269 clib_error_return (0,
270 "invalid tx-hold `%d' (out of range <%d,%d>)",
271 hold_time, LLDP_MIN_TX_HOLD,
272 LLDP_MAX_TX_HOLD);
273 goto out;
274 }
275 }
276 else if (unformat (input, "tx-interval %d", &tx_interval))
277 {
278 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
279 tx_interval > LLDP_MAX_TX_INTERVAL)
280 {
281 ret =
282 clib_error_return (0,
283 "invalid tx-interval `%d' (out of range <%d,%d>)",
284 tx_interval, LLDP_MIN_TX_INTERVAL,
285 LLDP_MAX_TX_INTERVAL);
286 goto out;
287 }
288 }
289 else
290 {
Klement Sekera3d62a7f2017-06-28 13:35:30 +0200291 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200292 }
293 }
294 ret =
295 lldp_cfg_err_to_clib_err (lldp_cfg_set (&host, hold_time, tx_interval));
296out:
297 vec_free (host);
298 return ret;
299}
300
301/* *INDENT-OFF* */
302VLIB_CLI_COMMAND(set_interface_lldp_cmd, static) = {
303 .path = "set interface lldp",
Steve Shin99a0e602017-07-01 04:16:20 +0000304 .short_help = "set interface lldp <interface> | sw_if_index <idx>"
Steve Shin9a6fcef2017-10-11 13:55:16 -0700305 " [port-desc <string>] [mgmt-ip4 <string>]"
306 " [mgmt-ip6 <string>] [mgmt-oid <string>] [disable]",
Klement Sekerade4582b2016-09-13 12:27:08 +0200307 .function = lldp_intf_cmd,
308};
309
310VLIB_CLI_COMMAND(set_lldp_cmd, static) = {
311 .path = "set lldp",
312 .short_help = "set lldp [system-name <string>] [tx-hold <value>] "
313 "[tx-interval <value>]",
314 .function = lldp_cfg_cmd,
315};
316/* *INDENT-ON* */
317
318static const char *
319lldp_chassis_id_subtype_str (lldp_chassis_id_subtype_t t)
320{
321 switch (t)
322 {
323#define F(num, val, str) \
324 case num: \
325 return str;
326 foreach_chassis_id_subtype (F)
327#undef F
328 }
329 return "unknown chassis subtype";
330}
331
332static const char *
333lldp_port_id_subtype_str (lldp_port_id_subtype_t t)
334{
335 switch (t)
336 {
337#define F(num, val, str) \
338 case num: \
339 return str;
340 foreach_port_id_subtype (F)
341#undef F
342 }
343 return "unknown port subtype";
344}
345
346/*
347 * format port id subtype&value
348 *
349 * @param va - 1st argument - unsigned - port id subtype
350 * @param va - 2nd argument - u8* - port id
351 * @param va - 3rd argument - unsigned - port id length
352 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
353 */
354u8 *
355format_lldp_port_id (u8 * s, va_list * va)
356{
357 const lldp_port_id_subtype_t subtype = va_arg (*va, unsigned);
358 const u8 *id = va_arg (*va, u8 *);
359 const unsigned len = va_arg (*va, unsigned);
360 const int detail = va_arg (*va, int);
361 if (!id)
362 {
363 return s;
364 }
365 switch (subtype)
366 {
367 case LLDP_PORT_ID_SUBTYPE_NAME (intf_alias):
368 /* fallthrough */
369 case LLDP_PORT_ID_SUBTYPE_NAME (port_comp):
370 /* fallthrough */
371 case LLDP_PORT_ID_SUBTYPE_NAME (local):
372 /* fallthrough */
373 case LLDP_PORT_ID_SUBTYPE_NAME (intf_name):
374 if (detail)
375 {
376 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
377 lldp_port_id_subtype_str (subtype));
378 }
379 else
380 {
381 s = format (s, "%U", format_ascii_bytes, id, len);
382 }
383 break;
384 case LLDP_PORT_ID_SUBTYPE_NAME (mac_addr):
385 if (ETHER_ADDR_LEN == len)
386 {
387 if (detail)
388 {
389 s = format (s, "%U(%s)", format_mac_address, id,
390 lldp_port_id_subtype_str (subtype));
391 }
392 else
393 {
394 s = format (s, "%U", format_mac_address, id);
395 }
396 break;
397 }
398 /* fallthrough */
399 case LLDP_PORT_ID_SUBTYPE_NAME (net_addr):
400 /* TODO */
401 /* fallthrough */
402 default:
403 if (detail)
404 {
405 s = format (s, "%U(%s)", format_hex_bytes, id, len,
406 lldp_port_id_subtype_str (subtype));
407 }
408 else
409 {
410 s = format (s, "%U", format_hex_bytes, id, len);
411 }
412 break;
413 }
414 return s;
415}
416
417/*
418 * format chassis id subtype&value
419 *
420 * @param s format string
421 * @param va - 1st argument - unsigned - chassis id subtype
422 * @param va - 2nd argument - u8* - chassis id
423 * @param va - 3rd argument - unsigned - chassis id length
424 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
425 */
426u8 *
427format_lldp_chassis_id (u8 * s, va_list * va)
428{
429 const lldp_chassis_id_subtype_t subtype =
430 va_arg (*va, lldp_chassis_id_subtype_t);
431 const u8 *id = va_arg (*va, u8 *);
432 const unsigned len = va_arg (*va, unsigned);
433 const int detail = va_arg (*va, int);
434 if (!id)
435 {
436 return s;
437 }
438 switch (subtype)
439 {
440 case LLDP_CHASS_ID_SUBTYPE_NAME (chassis_comp):
441 /* fallthrough */
442 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_alias):
443 /* fallthrough */
444 case LLDP_CHASS_ID_SUBTYPE_NAME (port_comp):
445 /* fallthrough */
446 case LLDP_PORT_ID_SUBTYPE_NAME (local):
447 /* fallthrough */
448 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_name):
449 if (detail)
450 {
451 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
452 lldp_chassis_id_subtype_str (subtype));
453 }
454 else
455 {
456 s = format (s, "%U", format_ascii_bytes, id, len);
457 }
458 break;
459 case LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr):
460 if (ETHER_ADDR_LEN == len)
461 {
462 if (detail)
463 {
464 s = format (s, "%U(%s)", format_mac_address, id,
465 lldp_chassis_id_subtype_str (subtype));
466 }
467 else
468 {
469 s = format (s, "%U", format_mac_address, id);
470 }
471 break;
472 }
473 /* fallthrough */
474 case LLDP_CHASS_ID_SUBTYPE_NAME (net_addr):
475 /* TODO */
476 default:
477 if (detail)
478 {
479 s = format (s, "%U(%s)", format_hex_bytes, id, len,
480 lldp_chassis_id_subtype_str (subtype));
481 }
482 else
483 {
484 s = format (s, "%U", format_hex_bytes, id, len);
485 }
486 break;
487 }
488 return s;
489}
490
491/*
492 * convert a tlv code to human-readable string
493 */
494static const char *
495lldp_tlv_code_str (lldp_tlv_code_t t)
496{
497 switch (t)
498 {
499#define F(n, t, s) \
500 case n: \
501 return s;
502 foreach_lldp_tlv_type (F)
503#undef F
504 }
505 return "unknown lldp tlv";
506}
507
508/*
509 * format a single LLDP TLV
510 *
511 * @param s format string
512 * @param va variable list - pointer to lldp_tlv_t is expected
513 */
514u8 *
515format_lldp_tlv (u8 * s, va_list * va)
516{
517 const lldp_tlv_t *tlv = va_arg (*va, lldp_tlv_t *);
518 if (!tlv)
519 {
520 return s;
521 }
522 u16 l = lldp_tlv_get_length (tlv);
523 switch (lldp_tlv_get_code (tlv))
524 {
525 case LLDP_TLV_NAME (chassis_id):
526 s = format (s, "%U", format_lldp_chassis_id,
527 ((lldp_chassis_id_tlv_t *) tlv)->subtype,
528 ((lldp_chassis_id_tlv_t *) tlv)->id,
529 l - STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype), 1);
530 break;
531 case LLDP_TLV_NAME (port_id):
532 s = format (s, "%U", format_lldp_port_id,
533 ((lldp_port_id_tlv_t *) tlv)->subtype,
534 ((lldp_port_id_tlv_t *) tlv)->id,
535 l - STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype), 1);
536 break;
537 case LLDP_TLV_NAME (ttl):
538 s = format (s, "%d", ntohs (((lldp_ttl_tlv_t *) tlv)->ttl));
539 break;
540 case LLDP_TLV_NAME (sys_name):
541 /* fallthrough */
542 case LLDP_TLV_NAME (sys_desc):
543 s = format (s, "%U", format_ascii_bytes, tlv->v, l);
544 break;
545 default:
546 s = format (s, "%U", format_hex_bytes, tlv->v, l);
547 }
548
549 return s;
550}
551
552static u8 *
553format_time_ago (u8 * s, va_list * va)
554{
555 f64 ago = va_arg (*va, double);
556 f64 now = va_arg (*va, double);
557 if (ago < 0.01)
558 {
559 return format (s, "never");
560 }
561 return format (s, "%.1fs ago", now - ago);
562}
563
564static u8 *
565format_lldp_intfs_detail (u8 * s, vlib_main_t * vm, const lldp_main_t * lm)
566{
567 vnet_main_t *vnm = &vnet_main;
568 const lldp_intf_t *n;
569 const vnet_hw_interface_t *hw;
570 const vnet_sw_interface_t *sw;
571 s = format (s, "LLDP configuration:\n");
572 if (lm->sys_name)
573 {
574 s = format (s, "Configured system name: %U\n", format_ascii_bytes,
575 lm->sys_name, vec_len (lm->sys_name));
576 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700577
Klement Sekerade4582b2016-09-13 12:27:08 +0200578 s = format (s, "Configured tx-hold: %d\n", (int) lm->msg_tx_hold);
579 s = format (s, "Configured tx-interval: %d\n", (int) lm->msg_tx_interval);
580 s = format (s, "\nLLDP-enabled interface table:\n");
581 f64 now = vlib_time_now (vm);
582
583 /* *INDENT-OFF* */
584 pool_foreach(
585 n, lm->intfs, ({
586 hw = vnet_get_hw_interface(vnm, n->hw_if_index);
587 sw = vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
Steve Shin9a6fcef2017-10-11 13:55:16 -0700588
Vladimir Isaeve85aa4c2020-09-23 14:39:17 +0300589 s = format(s, "\nLocal Interface name: %v\n"
Steve Shin9a6fcef2017-10-11 13:55:16 -0700590 "Local Port Description: %s\n",
591 hw->name, n->port_desc);
592 if (n->mgmt_ip4)
593 {
594 s = format (s, "Local Management address: %U\n",
595 format_ip4_address, n->mgmt_ip4, vec_len (n->mgmt_ip4));
596 }
597
598 if (n->mgmt_ip6)
599 {
600 s = format (s, "Local Management address IPV6: %U\n",
601 format_ip6_address, n->mgmt_ip6, vec_len (n->mgmt_ip6));
602 }
603
604 if (n->mgmt_oid)
605 {
606 s = format (s, "Local Management address OID: %U\n",
607 format_ascii_bytes, n->mgmt_oid, vec_len (n->mgmt_oid));
608 }
609
Klement Sekerade4582b2016-09-13 12:27:08 +0200610 /* Interface shutdown */
Steven Luong5ad541e2019-08-27 07:43:27 -0700611 if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
Klement Sekerade4582b2016-09-13 12:27:08 +0200612 {
Steve Shin9a6fcef2017-10-11 13:55:16 -0700613 s = format(s, "Interface/peer state: interface down\n"
614 "Last packet sent: %U\n",
615 format_time_ago, n->last_sent, now);
Klement Sekerade4582b2016-09-13 12:27:08 +0200616 }
617 else if (now < n->last_heard + n->ttl)
618 {
619 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700620 "Interface/peer state: active\n"
621 "Peer chassis ID: %U\nRemote port ID: %U\n"
622 "Last packet sent: %U\nLast packet received: %U\n",
623 format_lldp_chassis_id, n->chassis_id_subtype,
624 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200625 format_lldp_port_id, n->port_id_subtype, n->port_id,
626 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
627 now, format_time_ago, n->last_heard, now);
628 }
629 else
630 {
Steve Shin99a0e602017-07-01 04:16:20 +0000631 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700632 "Interface/peer state: inactive(timeout)\n"
633 "Last known peer chassis ID: %U\n"
634 "Last known peer port ID: %U\nLast packet sent: %U\n"
635 "Last packet received: %U\n",
636 format_lldp_chassis_id, n->chassis_id_subtype,
637 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200638 format_lldp_port_id, n->port_id_subtype, n->port_id,
639 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
640 now, format_time_ago, n->last_heard, now);
641 }
642 }));
643 /* *INDENT-ON* */
644 return s;
645}
646
647static u8 *
648format_lldp_intfs (u8 * s, va_list * va)
649{
650 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
651 const lldp_main_t *lm = va_arg (*va, lldp_main_t *);
652 const int detail = va_arg (*va, int);
653 vnet_main_t *vnm = &vnet_main;
654 const lldp_intf_t *n;
655
656 if (detail)
657 {
658 return format_lldp_intfs_detail (s, vm, lm);
659 }
660
661 f64 now = vlib_time_now (vm);
662 s = format (s, "%-25s %-25s %-25s %=15s %=15s %=10s\n", "Local interface",
663 "Peer chassis ID", "Remote port ID", "Last heard", "Last sent",
664 "Status");
665
666 /* *INDENT-OFF* */
667 pool_foreach(
668 n, lm->intfs, ({
669 const vnet_hw_interface_t *hw =
670 vnet_get_hw_interface(vnm, n->hw_if_index);
671 const vnet_sw_interface_t *sw =
672 vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
673 /* Interface shutdown */
674 if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
675 continue;
676 if (now < n->last_heard + n->ttl)
677 {
Vladimir Isaeve85aa4c2020-09-23 14:39:17 +0300678 s = format(s, "%-25v %-25U %-25U %=15U %=15U %=10s\n", hw->name,
Klement Sekerade4582b2016-09-13 12:27:08 +0200679 format_lldp_chassis_id, n->chassis_id_subtype,
680 n->chassis_id, vec_len(n->chassis_id), 0,
681 format_lldp_port_id, n->port_id_subtype, n->port_id,
682 vec_len(n->port_id), 0, format_time_ago, n->last_heard,
683 now, format_time_ago, n->last_sent, now, "active");
684 }
685 else
686 {
Vladimir Isaeve85aa4c2020-09-23 14:39:17 +0300687 s = format(s, "%-25v %-25s %-25s %=15U %=15U %=10s\n", hw->name,
Klement Sekerade4582b2016-09-13 12:27:08 +0200688 "", "", format_time_ago, n->last_heard, now,
689 format_time_ago, n->last_sent, now, "inactive");
690 }
691 }));
692 /* *INDENT-ON* */
693 return s;
694}
695
696static clib_error_t *
697show_lldp (vlib_main_t * vm, unformat_input_t * input,
698 CLIB_UNUSED (vlib_cli_command_t * lmd))
699{
700 lldp_main_t *lm = &lldp_main;
701
702 if (unformat (input, "detail"))
703 {
704 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 1);
705 }
706 else
707 {
708 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 0);
709 }
710 return 0;
711}
712
713/* *INDENT-OFF* */
714VLIB_CLI_COMMAND(show_lldp_command, static) = {
715 .path = "show lldp",
716 .short_help = "show lldp [detail]",
717 .function = show_lldp,
718};
719/* *INDENT-ON* */
720
721/*
722 * packet trace format function, very similar to
723 * lldp_packet_scan except that we call the per TLV format
724 * functions instead of the per TLV processing functions
725 */
726u8 *
727lldp_input_format_trace (u8 * s, va_list * args)
728{
729 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
730 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
731 const lldp_input_trace_t *t = va_arg (*args, lldp_input_trace_t *);
732 const u8 *cur;
733 const lldp_tlv_t *tlv;
734 cur = t->data;
735 while (((cur + lldp_tlv_get_length ((lldp_tlv_t *) cur)) <
736 t->data + t->len))
737 {
738 tlv = (lldp_tlv_t *) cur;
739 if (cur == t->data)
740 {
741 s = format (s, "TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
742 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
743 format_lldp_tlv, tlv);
744 }
745 else
746 {
747 s = format (s, " TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
748 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
749 format_lldp_tlv, tlv);
750 }
751 cur += STRUCT_SIZE_OF (lldp_tlv_t, head) + lldp_tlv_get_length (tlv);
752 }
753
754 return s;
755}
756
757/*
758 * fd.io coding-style-patch-verification: ON
759 *
760 * Local Variables:
761 * eval: (c-set-style "gnu")
762 * End:
763 */