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