blob: 4680292317fa3237c3d9e4d5ffbefa97e12fa2d2 [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 */
21#include <vnet/lisp-cp/lisp_types.h>
Steve Shin99a0e602017-07-01 04:16:20 +000022#include <vnet/lldp/lldp.h>
Klement Sekerade4582b2016-09-13 12:27:08 +020023#include <vnet/lldp/lldp_node.h>
24
25#ifndef ETHER_ADDR_LEN
26#include <net/ethernet.h>
27#endif
28
Klement Sekerade4582b2016-09-13 12:27:08 +020029static clib_error_t *
30lldp_cfg_err_to_clib_err (lldp_cfg_err_t e)
31{
32
33 switch (e)
34 {
35 case lldp_ok:
36 return 0;
37 case lldp_not_supported:
38 return clib_error_return (0, "not supported");
39 case lldp_invalid_arg:
40 return clib_error_return (0, "invalid argument");
41 }
42 return 0;
43}
44
Steve Shin99a0e602017-07-01 04:16:20 +000045lldp_cfg_err_t
Steve Shin9a6fcef2017-10-11 13:55:16 -070046lldp_cfg_intf_set (u32 hw_if_index, u8 ** port_desc, u8 ** mgmt_ip4,
47 u8 ** mgmt_ip6, u8 ** mgmt_oid, int enable)
Klement Sekerade4582b2016-09-13 12:27:08 +020048{
49 lldp_main_t *lm = &lldp_main;
50 vnet_main_t *vnm = lm->vnet_main;
51 ethernet_main_t *em = &ethernet_main;
Steve Shincda4c882017-10-25 11:16:45 -070052 const vnet_hw_interface_t *hi;
53 const ethernet_interface_t *eif;
Klement Sekerade4582b2016-09-13 12:27:08 +020054
Steve Shincda4c882017-10-25 11:16:45 -070055 if (pool_is_free_index (vnm->interface_main.hw_interfaces, hw_if_index))
56 {
57 return lldp_invalid_arg;
58 }
59
60 hi = vnet_get_hw_interface (vnm, hw_if_index);
61 eif = ethernet_get_interface (em, hw_if_index);
Klement Sekerade4582b2016-09-13 12:27:08 +020062 if (!eif)
63 {
64 return lldp_not_supported;
65 }
66
67 if (enable)
68 {
69 lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
70 if (n)
71 {
72 /* already enabled */
Steve Shin99a0e602017-07-01 04:16:20 +000073 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +020074 }
75 n = lldp_create_intf (lm, hw_if_index);
Steve Shin99a0e602017-07-01 04:16:20 +000076
77 if (port_desc && *port_desc)
78 {
79 n->port_desc = *port_desc;
80 *port_desc = NULL;
81 }
82
Steve Shin9a6fcef2017-10-11 13:55:16 -070083 if (mgmt_ip4 && *mgmt_ip4)
84 {
85 n->mgmt_ip4 = *mgmt_ip4;
86 *mgmt_ip4 = NULL;
87 }
88
89 if (mgmt_ip6 && *mgmt_ip6)
90 {
91 n->mgmt_ip6 = *mgmt_ip6;
92 *mgmt_ip6 = NULL;
93 }
94
95 if (mgmt_oid && *mgmt_oid)
96 {
97 n->mgmt_oid = *mgmt_oid;
Dave Wallacef13f6a42017-12-18 17:19:21 -050098 *mgmt_oid = NULL;
Steve Shin9a6fcef2017-10-11 13:55:16 -070099 }
100
Klement Sekerade4582b2016-09-13 12:27:08 +0200101 const vnet_sw_interface_t *sw =
102 vnet_get_sw_interface (lm->vnet_main, hi->sw_if_index);
Steven Luong5ad541e2019-08-27 07:43:27 -0700103 if (sw->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP))
Klement Sekerade4582b2016-09-13 12:27:08 +0200104 {
105 lldp_schedule_intf (lm, n);
106 }
107 }
108 else
109 {
110 lldp_intf_t *n = lldp_get_intf (lm, hi->sw_if_index);
111 lldp_delete_intf (lm, n);
112 }
113
Steve Shin99a0e602017-07-01 04:16:20 +0000114 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +0200115}
116
117static clib_error_t *
118lldp_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
119 vlib_cli_command_t * cmd)
120{
121 lldp_main_t *lm = &lldp_main;
122 vnet_main_t *vnm = lm->vnet_main;
Steve Shin99a0e602017-07-01 04:16:20 +0000123 u32 sw_if_index = (u32) ~ 0;
124 int enable = 1;
125 u8 *port_desc = NULL;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700126 u8 *mgmt_ip4 = NULL, *mgmt_ip6 = NULL, *mgmt_oid = NULL;
127 ip4_address_t ip4_addr;
128 ip6_address_t ip6_addr;
Klement Sekerade4582b2016-09-13 12:27:08 +0200129
Steve Shin99a0e602017-07-01 04:16:20 +0000130 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Klement Sekerade4582b2016-09-13 12:27:08 +0200131 {
Steve Shin99a0e602017-07-01 04:16:20 +0000132 if (unformat (input, "sw_if_index %d", &sw_if_index))
133 ;
134 if (unformat
135 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
136 ;
137 else if (unformat (input, "disable"))
138 enable = 0;
139 else if (unformat (input, "port-desc %s", &port_desc))
140 ;
141 else
Steve Shin9a6fcef2017-10-11 13:55:16 -0700142 if (unformat (input, "mgmt-ip4 %U", unformat_ip4_address, &ip4_addr))
143 {
144 vec_validate (mgmt_ip4, sizeof (ip4_address_t) - 1);
145 clib_memcpy (mgmt_ip4, &ip4_addr, vec_len (mgmt_ip4));
146 }
147 else
148 if (unformat (input, "mgmt-ip6 %U", unformat_ip6_address, &ip6_addr))
149 {
150 vec_validate (mgmt_ip6, sizeof (ip6_address_t) - 1);
151 clib_memcpy (mgmt_ip6, &ip6_addr, vec_len (mgmt_ip6));
152 }
153 else if (unformat (input, "mgmt-oid %s", &mgmt_oid))
154 ;
155 else
Steve Shin99a0e602017-07-01 04:16:20 +0000156 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200157 }
Steve Shin99a0e602017-07-01 04:16:20 +0000158
159 if (sw_if_index == (u32) ~ 0)
160 return clib_error_return (0, "Interface name is invalid!");
161
162 return lldp_cfg_err_to_clib_err (lldp_cfg_intf_set (sw_if_index,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700163 &port_desc, &mgmt_ip4,
164 &mgmt_ip6, &mgmt_oid,
165 enable));
Klement Sekerade4582b2016-09-13 12:27:08 +0200166}
167
Steve Shin99a0e602017-07-01 04:16:20 +0000168lldp_cfg_err_t
Klement Sekerade4582b2016-09-13 12:27:08 +0200169lldp_cfg_set (u8 ** host, int hold_time, int tx_interval)
170{
171 lldp_main_t *lm = &lldp_main;
172 int reschedule = 0;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700173
Klement Sekerade4582b2016-09-13 12:27:08 +0200174 if (host && *host)
175 {
176 vec_free (lm->sys_name);
177 lm->sys_name = *host;
178 *host = NULL;
179 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700180
Klement Sekerade4582b2016-09-13 12:27:08 +0200181 if (hold_time)
182 {
183 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
184 {
185 return lldp_invalid_arg;
186 }
187 if (lm->msg_tx_hold != hold_time)
188 {
189 lm->msg_tx_hold = hold_time;
190 reschedule = 1;
191 }
192 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700193
Klement Sekerade4582b2016-09-13 12:27:08 +0200194 if (tx_interval)
195 {
196 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
197 tx_interval > LLDP_MAX_TX_INTERVAL)
198 {
199 return lldp_invalid_arg;
200 }
201 if (lm->msg_tx_interval != tx_interval)
202 {
203 reschedule = 1;
204 lm->msg_tx_interval = tx_interval;
205 }
206 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700207
Klement Sekerade4582b2016-09-13 12:27:08 +0200208 if (reschedule)
209 {
210 vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
211 LLDP_EVENT_RESCHEDULE, 0);
212 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700213
Klement Sekerade4582b2016-09-13 12:27:08 +0200214 return lldp_ok;
215}
216
217static clib_error_t *
218lldp_cfg_cmd (vlib_main_t * vm, unformat_input_t * input,
219 vlib_cli_command_t * cmd)
220{
221 int hold_time = 0;
222 int tx_interval = 0;
223 u8 *host = NULL;
224 clib_error_t *ret = NULL;
225
226 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
227 {
228 if (unformat (input, "system-name %s", &host))
229 {
230 }
231 else if (unformat (input, "tx-hold %d", &hold_time))
232 {
233 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
234 {
235 ret =
236 clib_error_return (0,
237 "invalid tx-hold `%d' (out of range <%d,%d>)",
238 hold_time, LLDP_MIN_TX_HOLD,
239 LLDP_MAX_TX_HOLD);
240 goto out;
241 }
242 }
243 else if (unformat (input, "tx-interval %d", &tx_interval))
244 {
245 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
246 tx_interval > LLDP_MAX_TX_INTERVAL)
247 {
248 ret =
249 clib_error_return (0,
250 "invalid tx-interval `%d' (out of range <%d,%d>)",
251 tx_interval, LLDP_MIN_TX_INTERVAL,
252 LLDP_MAX_TX_INTERVAL);
253 goto out;
254 }
255 }
256 else
257 {
Klement Sekera3d62a7f2017-06-28 13:35:30 +0200258 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200259 }
260 }
261 ret =
262 lldp_cfg_err_to_clib_err (lldp_cfg_set (&host, hold_time, tx_interval));
263out:
264 vec_free (host);
265 return ret;
266}
267
268/* *INDENT-OFF* */
269VLIB_CLI_COMMAND(set_interface_lldp_cmd, static) = {
270 .path = "set interface lldp",
Steve Shin99a0e602017-07-01 04:16:20 +0000271 .short_help = "set interface lldp <interface> | sw_if_index <idx>"
Steve Shin9a6fcef2017-10-11 13:55:16 -0700272 " [port-desc <string>] [mgmt-ip4 <string>]"
273 " [mgmt-ip6 <string>] [mgmt-oid <string>] [disable]",
Klement Sekerade4582b2016-09-13 12:27:08 +0200274 .function = lldp_intf_cmd,
275};
276
277VLIB_CLI_COMMAND(set_lldp_cmd, static) = {
278 .path = "set lldp",
279 .short_help = "set lldp [system-name <string>] [tx-hold <value>] "
280 "[tx-interval <value>]",
281 .function = lldp_cfg_cmd,
282};
283/* *INDENT-ON* */
284
285static const char *
286lldp_chassis_id_subtype_str (lldp_chassis_id_subtype_t t)
287{
288 switch (t)
289 {
290#define F(num, val, str) \
291 case num: \
292 return str;
293 foreach_chassis_id_subtype (F)
294#undef F
295 }
296 return "unknown chassis subtype";
297}
298
299static const char *
300lldp_port_id_subtype_str (lldp_port_id_subtype_t t)
301{
302 switch (t)
303 {
304#define F(num, val, str) \
305 case num: \
306 return str;
307 foreach_port_id_subtype (F)
308#undef F
309 }
310 return "unknown port subtype";
311}
312
313/*
314 * format port id subtype&value
315 *
316 * @param va - 1st argument - unsigned - port id subtype
317 * @param va - 2nd argument - u8* - port id
318 * @param va - 3rd argument - unsigned - port id length
319 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
320 */
321u8 *
322format_lldp_port_id (u8 * s, va_list * va)
323{
324 const lldp_port_id_subtype_t subtype = va_arg (*va, unsigned);
325 const u8 *id = va_arg (*va, u8 *);
326 const unsigned len = va_arg (*va, unsigned);
327 const int detail = va_arg (*va, int);
328 if (!id)
329 {
330 return s;
331 }
332 switch (subtype)
333 {
334 case LLDP_PORT_ID_SUBTYPE_NAME (intf_alias):
335 /* fallthrough */
336 case LLDP_PORT_ID_SUBTYPE_NAME (port_comp):
337 /* fallthrough */
338 case LLDP_PORT_ID_SUBTYPE_NAME (local):
339 /* fallthrough */
340 case LLDP_PORT_ID_SUBTYPE_NAME (intf_name):
341 if (detail)
342 {
343 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
344 lldp_port_id_subtype_str (subtype));
345 }
346 else
347 {
348 s = format (s, "%U", format_ascii_bytes, id, len);
349 }
350 break;
351 case LLDP_PORT_ID_SUBTYPE_NAME (mac_addr):
352 if (ETHER_ADDR_LEN == len)
353 {
354 if (detail)
355 {
356 s = format (s, "%U(%s)", format_mac_address, id,
357 lldp_port_id_subtype_str (subtype));
358 }
359 else
360 {
361 s = format (s, "%U", format_mac_address, id);
362 }
363 break;
364 }
365 /* fallthrough */
366 case LLDP_PORT_ID_SUBTYPE_NAME (net_addr):
367 /* TODO */
368 /* fallthrough */
369 default:
370 if (detail)
371 {
372 s = format (s, "%U(%s)", format_hex_bytes, id, len,
373 lldp_port_id_subtype_str (subtype));
374 }
375 else
376 {
377 s = format (s, "%U", format_hex_bytes, id, len);
378 }
379 break;
380 }
381 return s;
382}
383
384/*
385 * format chassis id subtype&value
386 *
387 * @param s format string
388 * @param va - 1st argument - unsigned - chassis id subtype
389 * @param va - 2nd argument - u8* - chassis id
390 * @param va - 3rd argument - unsigned - chassis id length
391 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
392 */
393u8 *
394format_lldp_chassis_id (u8 * s, va_list * va)
395{
396 const lldp_chassis_id_subtype_t subtype =
397 va_arg (*va, lldp_chassis_id_subtype_t);
398 const u8 *id = va_arg (*va, u8 *);
399 const unsigned len = va_arg (*va, unsigned);
400 const int detail = va_arg (*va, int);
401 if (!id)
402 {
403 return s;
404 }
405 switch (subtype)
406 {
407 case LLDP_CHASS_ID_SUBTYPE_NAME (chassis_comp):
408 /* fallthrough */
409 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_alias):
410 /* fallthrough */
411 case LLDP_CHASS_ID_SUBTYPE_NAME (port_comp):
412 /* fallthrough */
413 case LLDP_PORT_ID_SUBTYPE_NAME (local):
414 /* fallthrough */
415 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_name):
416 if (detail)
417 {
418 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
419 lldp_chassis_id_subtype_str (subtype));
420 }
421 else
422 {
423 s = format (s, "%U", format_ascii_bytes, id, len);
424 }
425 break;
426 case LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr):
427 if (ETHER_ADDR_LEN == len)
428 {
429 if (detail)
430 {
431 s = format (s, "%U(%s)", format_mac_address, id,
432 lldp_chassis_id_subtype_str (subtype));
433 }
434 else
435 {
436 s = format (s, "%U", format_mac_address, id);
437 }
438 break;
439 }
440 /* fallthrough */
441 case LLDP_CHASS_ID_SUBTYPE_NAME (net_addr):
442 /* TODO */
443 default:
444 if (detail)
445 {
446 s = format (s, "%U(%s)", format_hex_bytes, id, len,
447 lldp_chassis_id_subtype_str (subtype));
448 }
449 else
450 {
451 s = format (s, "%U", format_hex_bytes, id, len);
452 }
453 break;
454 }
455 return s;
456}
457
458/*
459 * convert a tlv code to human-readable string
460 */
461static const char *
462lldp_tlv_code_str (lldp_tlv_code_t t)
463{
464 switch (t)
465 {
466#define F(n, t, s) \
467 case n: \
468 return s;
469 foreach_lldp_tlv_type (F)
470#undef F
471 }
472 return "unknown lldp tlv";
473}
474
475/*
476 * format a single LLDP TLV
477 *
478 * @param s format string
479 * @param va variable list - pointer to lldp_tlv_t is expected
480 */
481u8 *
482format_lldp_tlv (u8 * s, va_list * va)
483{
484 const lldp_tlv_t *tlv = va_arg (*va, lldp_tlv_t *);
485 if (!tlv)
486 {
487 return s;
488 }
489 u16 l = lldp_tlv_get_length (tlv);
490 switch (lldp_tlv_get_code (tlv))
491 {
492 case LLDP_TLV_NAME (chassis_id):
493 s = format (s, "%U", format_lldp_chassis_id,
494 ((lldp_chassis_id_tlv_t *) tlv)->subtype,
495 ((lldp_chassis_id_tlv_t *) tlv)->id,
496 l - STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype), 1);
497 break;
498 case LLDP_TLV_NAME (port_id):
499 s = format (s, "%U", format_lldp_port_id,
500 ((lldp_port_id_tlv_t *) tlv)->subtype,
501 ((lldp_port_id_tlv_t *) tlv)->id,
502 l - STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype), 1);
503 break;
504 case LLDP_TLV_NAME (ttl):
505 s = format (s, "%d", ntohs (((lldp_ttl_tlv_t *) tlv)->ttl));
506 break;
507 case LLDP_TLV_NAME (sys_name):
508 /* fallthrough */
509 case LLDP_TLV_NAME (sys_desc):
510 s = format (s, "%U", format_ascii_bytes, tlv->v, l);
511 break;
512 default:
513 s = format (s, "%U", format_hex_bytes, tlv->v, l);
514 }
515
516 return s;
517}
518
519static u8 *
520format_time_ago (u8 * s, va_list * va)
521{
522 f64 ago = va_arg (*va, double);
523 f64 now = va_arg (*va, double);
524 if (ago < 0.01)
525 {
526 return format (s, "never");
527 }
528 return format (s, "%.1fs ago", now - ago);
529}
530
531static u8 *
532format_lldp_intfs_detail (u8 * s, vlib_main_t * vm, const lldp_main_t * lm)
533{
534 vnet_main_t *vnm = &vnet_main;
535 const lldp_intf_t *n;
536 const vnet_hw_interface_t *hw;
537 const vnet_sw_interface_t *sw;
538 s = format (s, "LLDP configuration:\n");
539 if (lm->sys_name)
540 {
541 s = format (s, "Configured system name: %U\n", format_ascii_bytes,
542 lm->sys_name, vec_len (lm->sys_name));
543 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700544
Klement Sekerade4582b2016-09-13 12:27:08 +0200545 s = format (s, "Configured tx-hold: %d\n", (int) lm->msg_tx_hold);
546 s = format (s, "Configured tx-interval: %d\n", (int) lm->msg_tx_interval);
547 s = format (s, "\nLLDP-enabled interface table:\n");
548 f64 now = vlib_time_now (vm);
549
550 /* *INDENT-OFF* */
551 pool_foreach(
552 n, lm->intfs, ({
553 hw = vnet_get_hw_interface(vnm, n->hw_if_index);
554 sw = vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
Steve Shin9a6fcef2017-10-11 13:55:16 -0700555
556 s = format(s, "\nLocal Interface name: %s\n"
557 "Local Port Description: %s\n",
558 hw->name, n->port_desc);
559 if (n->mgmt_ip4)
560 {
561 s = format (s, "Local Management address: %U\n",
562 format_ip4_address, n->mgmt_ip4, vec_len (n->mgmt_ip4));
563 }
564
565 if (n->mgmt_ip6)
566 {
567 s = format (s, "Local Management address IPV6: %U\n",
568 format_ip6_address, n->mgmt_ip6, vec_len (n->mgmt_ip6));
569 }
570
571 if (n->mgmt_oid)
572 {
573 s = format (s, "Local Management address OID: %U\n",
574 format_ascii_bytes, n->mgmt_oid, vec_len (n->mgmt_oid));
575 }
576
Klement Sekerade4582b2016-09-13 12:27:08 +0200577 /* Interface shutdown */
Steven Luong5ad541e2019-08-27 07:43:27 -0700578 if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
Klement Sekerade4582b2016-09-13 12:27:08 +0200579 {
Steve Shin9a6fcef2017-10-11 13:55:16 -0700580 s = format(s, "Interface/peer state: interface down\n"
581 "Last packet sent: %U\n",
582 format_time_ago, n->last_sent, now);
Klement Sekerade4582b2016-09-13 12:27:08 +0200583 }
584 else if (now < n->last_heard + n->ttl)
585 {
586 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700587 "Interface/peer state: active\n"
588 "Peer chassis ID: %U\nRemote port ID: %U\n"
589 "Last packet sent: %U\nLast packet received: %U\n",
590 format_lldp_chassis_id, n->chassis_id_subtype,
591 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200592 format_lldp_port_id, n->port_id_subtype, n->port_id,
593 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
594 now, format_time_ago, n->last_heard, now);
595 }
596 else
597 {
Steve Shin99a0e602017-07-01 04:16:20 +0000598 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700599 "Interface/peer state: inactive(timeout)\n"
600 "Last known peer chassis ID: %U\n"
601 "Last known peer port ID: %U\nLast packet sent: %U\n"
602 "Last packet received: %U\n",
603 format_lldp_chassis_id, n->chassis_id_subtype,
604 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200605 format_lldp_port_id, n->port_id_subtype, n->port_id,
606 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
607 now, format_time_ago, n->last_heard, now);
608 }
609 }));
610 /* *INDENT-ON* */
611 return s;
612}
613
614static u8 *
615format_lldp_intfs (u8 * s, va_list * va)
616{
617 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
618 const lldp_main_t *lm = va_arg (*va, lldp_main_t *);
619 const int detail = va_arg (*va, int);
620 vnet_main_t *vnm = &vnet_main;
621 const lldp_intf_t *n;
622
623 if (detail)
624 {
625 return format_lldp_intfs_detail (s, vm, lm);
626 }
627
628 f64 now = vlib_time_now (vm);
629 s = format (s, "%-25s %-25s %-25s %=15s %=15s %=10s\n", "Local interface",
630 "Peer chassis ID", "Remote port ID", "Last heard", "Last sent",
631 "Status");
632
633 /* *INDENT-OFF* */
634 pool_foreach(
635 n, lm->intfs, ({
636 const vnet_hw_interface_t *hw =
637 vnet_get_hw_interface(vnm, n->hw_if_index);
638 const vnet_sw_interface_t *sw =
639 vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
640 /* Interface shutdown */
641 if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
642 continue;
643 if (now < n->last_heard + n->ttl)
644 {
645 s = format(s, "%-25s %-25U %-25U %=15U %=15U %=10s\n", hw->name,
646 format_lldp_chassis_id, n->chassis_id_subtype,
647 n->chassis_id, vec_len(n->chassis_id), 0,
648 format_lldp_port_id, n->port_id_subtype, n->port_id,
649 vec_len(n->port_id), 0, format_time_ago, n->last_heard,
650 now, format_time_ago, n->last_sent, now, "active");
651 }
652 else
653 {
654 s = format(s, "%-25s %-25s %-25s %=15U %=15U %=10s\n", hw->name,
655 "", "", format_time_ago, n->last_heard, now,
656 format_time_ago, n->last_sent, now, "inactive");
657 }
658 }));
659 /* *INDENT-ON* */
660 return s;
661}
662
663static clib_error_t *
664show_lldp (vlib_main_t * vm, unformat_input_t * input,
665 CLIB_UNUSED (vlib_cli_command_t * lmd))
666{
667 lldp_main_t *lm = &lldp_main;
668
669 if (unformat (input, "detail"))
670 {
671 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 1);
672 }
673 else
674 {
675 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 0);
676 }
677 return 0;
678}
679
680/* *INDENT-OFF* */
681VLIB_CLI_COMMAND(show_lldp_command, static) = {
682 .path = "show lldp",
683 .short_help = "show lldp [detail]",
684 .function = show_lldp,
685};
686/* *INDENT-ON* */
687
688/*
689 * packet trace format function, very similar to
690 * lldp_packet_scan except that we call the per TLV format
691 * functions instead of the per TLV processing functions
692 */
693u8 *
694lldp_input_format_trace (u8 * s, va_list * args)
695{
696 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
697 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
698 const lldp_input_trace_t *t = va_arg (*args, lldp_input_trace_t *);
699 const u8 *cur;
700 const lldp_tlv_t *tlv;
701 cur = t->data;
702 while (((cur + lldp_tlv_get_length ((lldp_tlv_t *) cur)) <
703 t->data + t->len))
704 {
705 tlv = (lldp_tlv_t *) cur;
706 if (cur == t->data)
707 {
708 s = format (s, "TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
709 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
710 format_lldp_tlv, tlv);
711 }
712 else
713 {
714 s = format (s, " TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
715 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
716 format_lldp_tlv, tlv);
717 }
718 cur += STRUCT_SIZE_OF (lldp_tlv_t, head) + lldp_tlv_get_length (tlv);
719 }
720
721 return s;
722}
723
724/*
725 * fd.io coding-style-patch-verification: ON
726 *
727 * Local Variables:
728 * eval: (c-set-style "gnu")
729 * End:
730 */