blob: ddedd137bedcf55fc6f99bb0ab197a976e2587a2 [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;
52 const vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
53 const ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index);
54
55 if (!eif)
56 {
57 return lldp_not_supported;
58 }
59
60 if (enable)
61 {
62 lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
63 if (n)
64 {
65 /* already enabled */
Steve Shin99a0e602017-07-01 04:16:20 +000066 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +020067 }
68 n = lldp_create_intf (lm, hw_if_index);
Steve Shin99a0e602017-07-01 04:16:20 +000069
70 if (port_desc && *port_desc)
71 {
72 n->port_desc = *port_desc;
73 *port_desc = NULL;
74 }
75
Steve Shin9a6fcef2017-10-11 13:55:16 -070076 if (mgmt_ip4 && *mgmt_ip4)
77 {
78 n->mgmt_ip4 = *mgmt_ip4;
79 *mgmt_ip4 = NULL;
80 }
81
82 if (mgmt_ip6 && *mgmt_ip6)
83 {
84 n->mgmt_ip6 = *mgmt_ip6;
85 *mgmt_ip6 = NULL;
86 }
87
88 if (mgmt_oid && *mgmt_oid)
89 {
90 n->mgmt_oid = *mgmt_oid;
91 *mgmt_ip6 = NULL;
92 }
93
Klement Sekerade4582b2016-09-13 12:27:08 +020094 const vnet_sw_interface_t *sw =
95 vnet_get_sw_interface (lm->vnet_main, hi->sw_if_index);
Steve Shin042a6212017-07-07 14:57:46 -070096 if (sw->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP |
97 VNET_SW_INTERFACE_FLAG_BOND_SLAVE))
Klement Sekerade4582b2016-09-13 12:27:08 +020098 {
99 lldp_schedule_intf (lm, n);
100 }
101 }
102 else
103 {
104 lldp_intf_t *n = lldp_get_intf (lm, hi->sw_if_index);
105 lldp_delete_intf (lm, n);
106 }
107
Steve Shin99a0e602017-07-01 04:16:20 +0000108 return lldp_ok;
Klement Sekerade4582b2016-09-13 12:27:08 +0200109}
110
111static clib_error_t *
112lldp_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
113 vlib_cli_command_t * cmd)
114{
115 lldp_main_t *lm = &lldp_main;
116 vnet_main_t *vnm = lm->vnet_main;
Steve Shin99a0e602017-07-01 04:16:20 +0000117 u32 sw_if_index = (u32) ~ 0;
118 int enable = 1;
119 u8 *port_desc = NULL;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700120 u8 *mgmt_ip4 = NULL, *mgmt_ip6 = NULL, *mgmt_oid = NULL;
121 ip4_address_t ip4_addr;
122 ip6_address_t ip6_addr;
Klement Sekerade4582b2016-09-13 12:27:08 +0200123
Steve Shin99a0e602017-07-01 04:16:20 +0000124 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Klement Sekerade4582b2016-09-13 12:27:08 +0200125 {
Steve Shin99a0e602017-07-01 04:16:20 +0000126 if (unformat (input, "sw_if_index %d", &sw_if_index))
127 ;
128 if (unformat
129 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
130 ;
131 else if (unformat (input, "disable"))
132 enable = 0;
133 else if (unformat (input, "port-desc %s", &port_desc))
134 ;
135 else
Steve Shin9a6fcef2017-10-11 13:55:16 -0700136 if (unformat (input, "mgmt-ip4 %U", unformat_ip4_address, &ip4_addr))
137 {
138 vec_validate (mgmt_ip4, sizeof (ip4_address_t) - 1);
139 clib_memcpy (mgmt_ip4, &ip4_addr, vec_len (mgmt_ip4));
140 }
141 else
142 if (unformat (input, "mgmt-ip6 %U", unformat_ip6_address, &ip6_addr))
143 {
144 vec_validate (mgmt_ip6, sizeof (ip6_address_t) - 1);
145 clib_memcpy (mgmt_ip6, &ip6_addr, vec_len (mgmt_ip6));
146 }
147 else if (unformat (input, "mgmt-oid %s", &mgmt_oid))
148 ;
149 else
Steve Shin99a0e602017-07-01 04:16:20 +0000150 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200151 }
Steve Shin99a0e602017-07-01 04:16:20 +0000152
153 if (sw_if_index == (u32) ~ 0)
154 return clib_error_return (0, "Interface name is invalid!");
155
156 return lldp_cfg_err_to_clib_err (lldp_cfg_intf_set (sw_if_index,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700157 &port_desc, &mgmt_ip4,
158 &mgmt_ip6, &mgmt_oid,
159 enable));
Klement Sekerade4582b2016-09-13 12:27:08 +0200160}
161
Steve Shin99a0e602017-07-01 04:16:20 +0000162lldp_cfg_err_t
Klement Sekerade4582b2016-09-13 12:27:08 +0200163lldp_cfg_set (u8 ** host, int hold_time, int tx_interval)
164{
165 lldp_main_t *lm = &lldp_main;
166 int reschedule = 0;
Steve Shin9a6fcef2017-10-11 13:55:16 -0700167
Klement Sekerade4582b2016-09-13 12:27:08 +0200168 if (host && *host)
169 {
170 vec_free (lm->sys_name);
171 lm->sys_name = *host;
172 *host = NULL;
173 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700174
Klement Sekerade4582b2016-09-13 12:27:08 +0200175 if (hold_time)
176 {
177 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
178 {
179 return lldp_invalid_arg;
180 }
181 if (lm->msg_tx_hold != hold_time)
182 {
183 lm->msg_tx_hold = hold_time;
184 reschedule = 1;
185 }
186 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700187
Klement Sekerade4582b2016-09-13 12:27:08 +0200188 if (tx_interval)
189 {
190 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
191 tx_interval > LLDP_MAX_TX_INTERVAL)
192 {
193 return lldp_invalid_arg;
194 }
195 if (lm->msg_tx_interval != tx_interval)
196 {
197 reschedule = 1;
198 lm->msg_tx_interval = tx_interval;
199 }
200 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700201
Klement Sekerade4582b2016-09-13 12:27:08 +0200202 if (reschedule)
203 {
204 vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
205 LLDP_EVENT_RESCHEDULE, 0);
206 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700207
Klement Sekerade4582b2016-09-13 12:27:08 +0200208 return lldp_ok;
209}
210
211static clib_error_t *
212lldp_cfg_cmd (vlib_main_t * vm, unformat_input_t * input,
213 vlib_cli_command_t * cmd)
214{
215 int hold_time = 0;
216 int tx_interval = 0;
217 u8 *host = NULL;
218 clib_error_t *ret = NULL;
219
220 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
221 {
222 if (unformat (input, "system-name %s", &host))
223 {
224 }
225 else if (unformat (input, "tx-hold %d", &hold_time))
226 {
227 if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
228 {
229 ret =
230 clib_error_return (0,
231 "invalid tx-hold `%d' (out of range <%d,%d>)",
232 hold_time, LLDP_MIN_TX_HOLD,
233 LLDP_MAX_TX_HOLD);
234 goto out;
235 }
236 }
237 else if (unformat (input, "tx-interval %d", &tx_interval))
238 {
239 if (tx_interval < LLDP_MIN_TX_INTERVAL ||
240 tx_interval > LLDP_MAX_TX_INTERVAL)
241 {
242 ret =
243 clib_error_return (0,
244 "invalid tx-interval `%d' (out of range <%d,%d>)",
245 tx_interval, LLDP_MIN_TX_INTERVAL,
246 LLDP_MAX_TX_INTERVAL);
247 goto out;
248 }
249 }
250 else
251 {
Klement Sekera3d62a7f2017-06-28 13:35:30 +0200252 break;
Klement Sekerade4582b2016-09-13 12:27:08 +0200253 }
254 }
255 ret =
256 lldp_cfg_err_to_clib_err (lldp_cfg_set (&host, hold_time, tx_interval));
257out:
258 vec_free (host);
259 return ret;
260}
261
262/* *INDENT-OFF* */
263VLIB_CLI_COMMAND(set_interface_lldp_cmd, static) = {
264 .path = "set interface lldp",
Steve Shin99a0e602017-07-01 04:16:20 +0000265 .short_help = "set interface lldp <interface> | sw_if_index <idx>"
Steve Shin9a6fcef2017-10-11 13:55:16 -0700266 " [port-desc <string>] [mgmt-ip4 <string>]"
267 " [mgmt-ip6 <string>] [mgmt-oid <string>] [disable]",
Klement Sekerade4582b2016-09-13 12:27:08 +0200268 .function = lldp_intf_cmd,
269};
270
271VLIB_CLI_COMMAND(set_lldp_cmd, static) = {
272 .path = "set lldp",
273 .short_help = "set lldp [system-name <string>] [tx-hold <value>] "
274 "[tx-interval <value>]",
275 .function = lldp_cfg_cmd,
276};
277/* *INDENT-ON* */
278
279static const char *
280lldp_chassis_id_subtype_str (lldp_chassis_id_subtype_t t)
281{
282 switch (t)
283 {
284#define F(num, val, str) \
285 case num: \
286 return str;
287 foreach_chassis_id_subtype (F)
288#undef F
289 }
290 return "unknown chassis subtype";
291}
292
293static const char *
294lldp_port_id_subtype_str (lldp_port_id_subtype_t t)
295{
296 switch (t)
297 {
298#define F(num, val, str) \
299 case num: \
300 return str;
301 foreach_port_id_subtype (F)
302#undef F
303 }
304 return "unknown port subtype";
305}
306
307/*
308 * format port id subtype&value
309 *
310 * @param va - 1st argument - unsigned - port id subtype
311 * @param va - 2nd argument - u8* - port id
312 * @param va - 3rd argument - unsigned - port id length
313 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
314 */
315u8 *
316format_lldp_port_id (u8 * s, va_list * va)
317{
318 const lldp_port_id_subtype_t subtype = va_arg (*va, unsigned);
319 const u8 *id = va_arg (*va, u8 *);
320 const unsigned len = va_arg (*va, unsigned);
321 const int detail = va_arg (*va, int);
322 if (!id)
323 {
324 return s;
325 }
326 switch (subtype)
327 {
328 case LLDP_PORT_ID_SUBTYPE_NAME (intf_alias):
329 /* fallthrough */
330 case LLDP_PORT_ID_SUBTYPE_NAME (port_comp):
331 /* fallthrough */
332 case LLDP_PORT_ID_SUBTYPE_NAME (local):
333 /* fallthrough */
334 case LLDP_PORT_ID_SUBTYPE_NAME (intf_name):
335 if (detail)
336 {
337 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
338 lldp_port_id_subtype_str (subtype));
339 }
340 else
341 {
342 s = format (s, "%U", format_ascii_bytes, id, len);
343 }
344 break;
345 case LLDP_PORT_ID_SUBTYPE_NAME (mac_addr):
346 if (ETHER_ADDR_LEN == len)
347 {
348 if (detail)
349 {
350 s = format (s, "%U(%s)", format_mac_address, id,
351 lldp_port_id_subtype_str (subtype));
352 }
353 else
354 {
355 s = format (s, "%U", format_mac_address, id);
356 }
357 break;
358 }
359 /* fallthrough */
360 case LLDP_PORT_ID_SUBTYPE_NAME (net_addr):
361 /* TODO */
362 /* fallthrough */
363 default:
364 if (detail)
365 {
366 s = format (s, "%U(%s)", format_hex_bytes, id, len,
367 lldp_port_id_subtype_str (subtype));
368 }
369 else
370 {
371 s = format (s, "%U", format_hex_bytes, id, len);
372 }
373 break;
374 }
375 return s;
376}
377
378/*
379 * format chassis id subtype&value
380 *
381 * @param s format string
382 * @param va - 1st argument - unsigned - chassis id subtype
383 * @param va - 2nd argument - u8* - chassis id
384 * @param va - 3rd argument - unsigned - chassis id length
385 * @param va - 4th argument - int - 1 for detailed output, 0 for simple
386 */
387u8 *
388format_lldp_chassis_id (u8 * s, va_list * va)
389{
390 const lldp_chassis_id_subtype_t subtype =
391 va_arg (*va, lldp_chassis_id_subtype_t);
392 const u8 *id = va_arg (*va, u8 *);
393 const unsigned len = va_arg (*va, unsigned);
394 const int detail = va_arg (*va, int);
395 if (!id)
396 {
397 return s;
398 }
399 switch (subtype)
400 {
401 case LLDP_CHASS_ID_SUBTYPE_NAME (chassis_comp):
402 /* fallthrough */
403 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_alias):
404 /* fallthrough */
405 case LLDP_CHASS_ID_SUBTYPE_NAME (port_comp):
406 /* fallthrough */
407 case LLDP_PORT_ID_SUBTYPE_NAME (local):
408 /* fallthrough */
409 case LLDP_CHASS_ID_SUBTYPE_NAME (intf_name):
410 if (detail)
411 {
412 s = format (s, "%U(%s)", format_ascii_bytes, id, len,
413 lldp_chassis_id_subtype_str (subtype));
414 }
415 else
416 {
417 s = format (s, "%U", format_ascii_bytes, id, len);
418 }
419 break;
420 case LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr):
421 if (ETHER_ADDR_LEN == len)
422 {
423 if (detail)
424 {
425 s = format (s, "%U(%s)", format_mac_address, id,
426 lldp_chassis_id_subtype_str (subtype));
427 }
428 else
429 {
430 s = format (s, "%U", format_mac_address, id);
431 }
432 break;
433 }
434 /* fallthrough */
435 case LLDP_CHASS_ID_SUBTYPE_NAME (net_addr):
436 /* TODO */
437 default:
438 if (detail)
439 {
440 s = format (s, "%U(%s)", format_hex_bytes, id, len,
441 lldp_chassis_id_subtype_str (subtype));
442 }
443 else
444 {
445 s = format (s, "%U", format_hex_bytes, id, len);
446 }
447 break;
448 }
449 return s;
450}
451
452/*
453 * convert a tlv code to human-readable string
454 */
455static const char *
456lldp_tlv_code_str (lldp_tlv_code_t t)
457{
458 switch (t)
459 {
460#define F(n, t, s) \
461 case n: \
462 return s;
463 foreach_lldp_tlv_type (F)
464#undef F
465 }
466 return "unknown lldp tlv";
467}
468
469/*
470 * format a single LLDP TLV
471 *
472 * @param s format string
473 * @param va variable list - pointer to lldp_tlv_t is expected
474 */
475u8 *
476format_lldp_tlv (u8 * s, va_list * va)
477{
478 const lldp_tlv_t *tlv = va_arg (*va, lldp_tlv_t *);
479 if (!tlv)
480 {
481 return s;
482 }
483 u16 l = lldp_tlv_get_length (tlv);
484 switch (lldp_tlv_get_code (tlv))
485 {
486 case LLDP_TLV_NAME (chassis_id):
487 s = format (s, "%U", format_lldp_chassis_id,
488 ((lldp_chassis_id_tlv_t *) tlv)->subtype,
489 ((lldp_chassis_id_tlv_t *) tlv)->id,
490 l - STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype), 1);
491 break;
492 case LLDP_TLV_NAME (port_id):
493 s = format (s, "%U", format_lldp_port_id,
494 ((lldp_port_id_tlv_t *) tlv)->subtype,
495 ((lldp_port_id_tlv_t *) tlv)->id,
496 l - STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype), 1);
497 break;
498 case LLDP_TLV_NAME (ttl):
499 s = format (s, "%d", ntohs (((lldp_ttl_tlv_t *) tlv)->ttl));
500 break;
501 case LLDP_TLV_NAME (sys_name):
502 /* fallthrough */
503 case LLDP_TLV_NAME (sys_desc):
504 s = format (s, "%U", format_ascii_bytes, tlv->v, l);
505 break;
506 default:
507 s = format (s, "%U", format_hex_bytes, tlv->v, l);
508 }
509
510 return s;
511}
512
513static u8 *
514format_time_ago (u8 * s, va_list * va)
515{
516 f64 ago = va_arg (*va, double);
517 f64 now = va_arg (*va, double);
518 if (ago < 0.01)
519 {
520 return format (s, "never");
521 }
522 return format (s, "%.1fs ago", now - ago);
523}
524
525static u8 *
526format_lldp_intfs_detail (u8 * s, vlib_main_t * vm, const lldp_main_t * lm)
527{
528 vnet_main_t *vnm = &vnet_main;
529 const lldp_intf_t *n;
530 const vnet_hw_interface_t *hw;
531 const vnet_sw_interface_t *sw;
532 s = format (s, "LLDP configuration:\n");
533 if (lm->sys_name)
534 {
535 s = format (s, "Configured system name: %U\n", format_ascii_bytes,
536 lm->sys_name, vec_len (lm->sys_name));
537 }
Steve Shin9a6fcef2017-10-11 13:55:16 -0700538
Klement Sekerade4582b2016-09-13 12:27:08 +0200539 s = format (s, "Configured tx-hold: %d\n", (int) lm->msg_tx_hold);
540 s = format (s, "Configured tx-interval: %d\n", (int) lm->msg_tx_interval);
541 s = format (s, "\nLLDP-enabled interface table:\n");
542 f64 now = vlib_time_now (vm);
543
544 /* *INDENT-OFF* */
545 pool_foreach(
546 n, lm->intfs, ({
547 hw = vnet_get_hw_interface(vnm, n->hw_if_index);
548 sw = vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
Steve Shin9a6fcef2017-10-11 13:55:16 -0700549
550 s = format(s, "\nLocal Interface name: %s\n"
551 "Local Port Description: %s\n",
552 hw->name, n->port_desc);
553 if (n->mgmt_ip4)
554 {
555 s = format (s, "Local Management address: %U\n",
556 format_ip4_address, n->mgmt_ip4, vec_len (n->mgmt_ip4));
557 }
558
559 if (n->mgmt_ip6)
560 {
561 s = format (s, "Local Management address IPV6: %U\n",
562 format_ip6_address, n->mgmt_ip6, vec_len (n->mgmt_ip6));
563 }
564
565 if (n->mgmt_oid)
566 {
567 s = format (s, "Local Management address OID: %U\n",
568 format_ascii_bytes, n->mgmt_oid, vec_len (n->mgmt_oid));
569 }
570
Klement Sekerade4582b2016-09-13 12:27:08 +0200571 /* Interface shutdown */
Steve Shin042a6212017-07-07 14:57:46 -0700572 if (!(sw->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP |
573 VNET_SW_INTERFACE_FLAG_BOND_SLAVE)))
Klement Sekerade4582b2016-09-13 12:27:08 +0200574 {
Steve Shin9a6fcef2017-10-11 13:55:16 -0700575 s = format(s, "Interface/peer state: interface down\n"
576 "Last packet sent: %U\n",
577 format_time_ago, n->last_sent, now);
Klement Sekerade4582b2016-09-13 12:27:08 +0200578 }
579 else if (now < n->last_heard + n->ttl)
580 {
581 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700582 "Interface/peer state: active\n"
583 "Peer chassis ID: %U\nRemote port ID: %U\n"
584 "Last packet sent: %U\nLast packet received: %U\n",
585 format_lldp_chassis_id, n->chassis_id_subtype,
586 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200587 format_lldp_port_id, n->port_id_subtype, n->port_id,
588 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
589 now, format_time_ago, n->last_heard, now);
590 }
591 else
592 {
Steve Shin99a0e602017-07-01 04:16:20 +0000593 s = format(s,
Steve Shin9a6fcef2017-10-11 13:55:16 -0700594 "Interface/peer state: inactive(timeout)\n"
595 "Last known peer chassis ID: %U\n"
596 "Last known peer port ID: %U\nLast packet sent: %U\n"
597 "Last packet received: %U\n",
598 format_lldp_chassis_id, n->chassis_id_subtype,
599 n->chassis_id, vec_len(n->chassis_id), 1,
Klement Sekerade4582b2016-09-13 12:27:08 +0200600 format_lldp_port_id, n->port_id_subtype, n->port_id,
601 vec_len(n->port_id), 1, format_time_ago, n->last_sent,
602 now, format_time_ago, n->last_heard, now);
603 }
604 }));
605 /* *INDENT-ON* */
606 return s;
607}
608
609static u8 *
610format_lldp_intfs (u8 * s, va_list * va)
611{
612 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
613 const lldp_main_t *lm = va_arg (*va, lldp_main_t *);
614 const int detail = va_arg (*va, int);
615 vnet_main_t *vnm = &vnet_main;
616 const lldp_intf_t *n;
617
618 if (detail)
619 {
620 return format_lldp_intfs_detail (s, vm, lm);
621 }
622
623 f64 now = vlib_time_now (vm);
624 s = format (s, "%-25s %-25s %-25s %=15s %=15s %=10s\n", "Local interface",
625 "Peer chassis ID", "Remote port ID", "Last heard", "Last sent",
626 "Status");
627
628 /* *INDENT-OFF* */
629 pool_foreach(
630 n, lm->intfs, ({
631 const vnet_hw_interface_t *hw =
632 vnet_get_hw_interface(vnm, n->hw_if_index);
633 const vnet_sw_interface_t *sw =
634 vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
635 /* Interface shutdown */
636 if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
637 continue;
638 if (now < n->last_heard + n->ttl)
639 {
640 s = format(s, "%-25s %-25U %-25U %=15U %=15U %=10s\n", hw->name,
641 format_lldp_chassis_id, n->chassis_id_subtype,
642 n->chassis_id, vec_len(n->chassis_id), 0,
643 format_lldp_port_id, n->port_id_subtype, n->port_id,
644 vec_len(n->port_id), 0, format_time_ago, n->last_heard,
645 now, format_time_ago, n->last_sent, now, "active");
646 }
647 else
648 {
649 s = format(s, "%-25s %-25s %-25s %=15U %=15U %=10s\n", hw->name,
650 "", "", format_time_ago, n->last_heard, now,
651 format_time_ago, n->last_sent, now, "inactive");
652 }
653 }));
654 /* *INDENT-ON* */
655 return s;
656}
657
658static clib_error_t *
659show_lldp (vlib_main_t * vm, unformat_input_t * input,
660 CLIB_UNUSED (vlib_cli_command_t * lmd))
661{
662 lldp_main_t *lm = &lldp_main;
663
664 if (unformat (input, "detail"))
665 {
666 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 1);
667 }
668 else
669 {
670 vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 0);
671 }
672 return 0;
673}
674
675/* *INDENT-OFF* */
676VLIB_CLI_COMMAND(show_lldp_command, static) = {
677 .path = "show lldp",
678 .short_help = "show lldp [detail]",
679 .function = show_lldp,
680};
681/* *INDENT-ON* */
682
683/*
684 * packet trace format function, very similar to
685 * lldp_packet_scan except that we call the per TLV format
686 * functions instead of the per TLV processing functions
687 */
688u8 *
689lldp_input_format_trace (u8 * s, va_list * args)
690{
691 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
692 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
693 const lldp_input_trace_t *t = va_arg (*args, lldp_input_trace_t *);
694 const u8 *cur;
695 const lldp_tlv_t *tlv;
696 cur = t->data;
697 while (((cur + lldp_tlv_get_length ((lldp_tlv_t *) cur)) <
698 t->data + t->len))
699 {
700 tlv = (lldp_tlv_t *) cur;
701 if (cur == t->data)
702 {
703 s = format (s, "TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
704 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
705 format_lldp_tlv, tlv);
706 }
707 else
708 {
709 s = format (s, " TLV #%d(%s): %U\n", lldp_tlv_get_code (tlv),
710 lldp_tlv_code_str (lldp_tlv_get_code (tlv)),
711 format_lldp_tlv, tlv);
712 }
713 cur += STRUCT_SIZE_OF (lldp_tlv_t, head) + lldp_tlv_get_length (tlv);
714 }
715
716 return s;
717}
718
719/*
720 * fd.io coding-style-patch-verification: ON
721 *
722 * Local Variables:
723 * eval: (c-set-style "gnu")
724 * End:
725 */