Line data Source code
1 : /*
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/ethernet/ethernet.h>
22 : #include <vnet/ip/ip.h>
23 : #include <lldp/lldp.h>
24 : #include <lldp/lldp_node.h>
25 :
26 : #ifndef ETHER_ADDR_LEN
27 : #include <net/ethernet.h>
28 : #endif
29 :
30 : static clib_error_t *
31 0 : lldp_cfg_err_to_clib_err (lldp_cfg_err_t e)
32 : {
33 :
34 0 : switch (e)
35 : {
36 0 : case lldp_ok:
37 0 : return 0;
38 0 : case lldp_not_supported:
39 0 : return clib_error_return (0, "not supported");
40 0 : case lldp_invalid_arg:
41 0 : return clib_error_return (0, "invalid argument");
42 0 : case lldp_internal_error:
43 0 : return clib_error_return (0, "internal error");
44 : }
45 0 : return 0;
46 : }
47 :
48 : lldp_cfg_err_t
49 0 : lldp_cfg_intf_set (u32 hw_if_index, u8 ** port_desc, u8 ** mgmt_ip4,
50 : u8 ** mgmt_ip6, u8 ** mgmt_oid, int enable)
51 : {
52 0 : clib_error_t *error = 0;
53 0 : lldp_main_t *lm = &lldp_main;
54 0 : vnet_main_t *vnm = lm->vnet_main;
55 0 : ethernet_main_t *em = ðernet_main;
56 : const vnet_hw_interface_t *hi;
57 : const ethernet_interface_t *eif;
58 :
59 0 : if (pool_is_free_index (vnm->interface_main.hw_interfaces, hw_if_index))
60 : {
61 0 : return lldp_invalid_arg;
62 : }
63 :
64 0 : hi = vnet_get_hw_interface (vnm, hw_if_index);
65 0 : eif = ethernet_get_interface (em, hw_if_index);
66 0 : if (!eif)
67 : {
68 0 : return lldp_not_supported;
69 : }
70 :
71 0 : if (enable)
72 : {
73 0 : lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
74 0 : if (n)
75 : {
76 : /* already enabled */
77 0 : return lldp_ok;
78 : }
79 0 : n = lldp_create_intf (lm, hw_if_index);
80 :
81 0 : if (port_desc && *port_desc)
82 : {
83 0 : n->port_desc = *port_desc;
84 0 : *port_desc = NULL;
85 : }
86 :
87 0 : if (mgmt_ip4 && *mgmt_ip4)
88 : {
89 0 : n->mgmt_ip4 = *mgmt_ip4;
90 0 : *mgmt_ip4 = NULL;
91 : }
92 :
93 0 : if (mgmt_ip6 && *mgmt_ip6)
94 : {
95 0 : n->mgmt_ip6 = *mgmt_ip6;
96 0 : *mgmt_ip6 = NULL;
97 : }
98 :
99 0 : if (mgmt_oid && *mgmt_oid)
100 : {
101 0 : n->mgmt_oid = *mgmt_oid;
102 0 : *mgmt_oid = NULL;
103 : }
104 :
105 : /* Add MAC address to an interface's filter */
106 0 : if (hi->caps & VNET_HW_IF_CAP_MAC_FILTER)
107 : {
108 : error =
109 0 : vnet_hw_interface_add_del_mac_address (lm->vnet_main,
110 : hw_if_index,
111 : lldp_mac_addr,
112 : 1 /* is_add */ );
113 0 : if (error)
114 : {
115 0 : clib_error_free (error);
116 0 : lldp_delete_intf (lm, n);
117 0 : return lldp_internal_error;
118 : }
119 : }
120 :
121 : const vnet_sw_interface_t *sw =
122 0 : vnet_get_sw_interface (lm->vnet_main, hi->sw_if_index);
123 0 : if (sw->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP))
124 : {
125 0 : lldp_schedule_intf (lm, n);
126 : }
127 : }
128 : else
129 : {
130 0 : lldp_intf_t *n = lldp_get_intf (lm, hi->sw_if_index);
131 0 : lldp_delete_intf (lm, n);
132 : /* Remove MAC address from the interface's filter */
133 0 : if ((n) && (hi->caps & VNET_HW_IF_CAP_MAC_FILTER))
134 : {
135 : error =
136 0 : vnet_hw_interface_add_del_mac_address (lm->vnet_main,
137 : hw_if_index,
138 : lldp_mac_addr,
139 : 0 /* is_add */ );
140 0 : if (error)
141 : {
142 0 : clib_error_free (error);
143 : }
144 : }
145 : }
146 :
147 0 : return lldp_ok;
148 : }
149 :
150 : static clib_error_t *
151 0 : lldp_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
152 : vlib_cli_command_t * cmd)
153 : {
154 0 : lldp_main_t *lm = &lldp_main;
155 0 : vnet_main_t *vnm = lm->vnet_main;
156 0 : u32 sw_if_index = (u32) ~ 0;
157 0 : int enable = 1;
158 0 : u8 *port_desc = NULL;
159 0 : u8 *mgmt_ip4 = NULL, *mgmt_ip6 = NULL, *mgmt_oid = NULL;
160 : ip4_address_t ip4_addr;
161 : ip6_address_t ip6_addr;
162 :
163 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
164 : {
165 0 : if (unformat (input, "sw_if_index %d", &sw_if_index))
166 : ;
167 0 : if (unformat
168 : (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
169 : ;
170 0 : else if (unformat (input, "disable"))
171 0 : enable = 0;
172 0 : else if (unformat (input, "port-desc %s", &port_desc))
173 : ;
174 : else
175 0 : if (unformat (input, "mgmt-ip4 %U", unformat_ip4_address, &ip4_addr))
176 : {
177 0 : vec_validate (mgmt_ip4, sizeof (ip4_address_t) - 1);
178 0 : clib_memcpy (mgmt_ip4, &ip4_addr, sizeof (ip4_addr));
179 : }
180 : else
181 0 : if (unformat (input, "mgmt-ip6 %U", unformat_ip6_address, &ip6_addr))
182 : {
183 0 : vec_validate (mgmt_ip6, sizeof (ip6_address_t) - 1);
184 0 : clib_memcpy (mgmt_ip6, &ip6_addr, sizeof (ip6_addr));
185 : }
186 0 : else if (unformat (input, "mgmt-oid %s", &mgmt_oid))
187 : ;
188 : else
189 0 : break;
190 : }
191 :
192 0 : if (sw_if_index == (u32) ~ 0)
193 0 : return clib_error_return (0, "Interface name is invalid!");
194 :
195 0 : return lldp_cfg_err_to_clib_err (lldp_cfg_intf_set (sw_if_index,
196 : &port_desc, &mgmt_ip4,
197 : &mgmt_ip6, &mgmt_oid,
198 : enable));
199 : }
200 :
201 : lldp_cfg_err_t
202 0 : lldp_cfg_set (u8 ** host, int hold_time, int tx_interval)
203 : {
204 0 : lldp_main_t *lm = &lldp_main;
205 0 : int reschedule = 0;
206 :
207 0 : if (host && *host)
208 : {
209 0 : vec_free (lm->sys_name);
210 0 : lm->sys_name = *host;
211 0 : *host = NULL;
212 : }
213 :
214 0 : if (hold_time)
215 : {
216 0 : if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
217 : {
218 0 : return lldp_invalid_arg;
219 : }
220 0 : if (lm->msg_tx_hold != hold_time)
221 : {
222 0 : lm->msg_tx_hold = hold_time;
223 0 : reschedule = 1;
224 : }
225 : }
226 :
227 0 : if (tx_interval)
228 : {
229 0 : if (tx_interval < LLDP_MIN_TX_INTERVAL ||
230 : tx_interval > LLDP_MAX_TX_INTERVAL)
231 : {
232 0 : return lldp_invalid_arg;
233 : }
234 0 : if (lm->msg_tx_interval != tx_interval)
235 : {
236 0 : reschedule = 1;
237 0 : lm->msg_tx_interval = tx_interval;
238 : }
239 : }
240 :
241 0 : if (reschedule)
242 : {
243 0 : vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
244 : LLDP_EVENT_RESCHEDULE, 0);
245 : }
246 :
247 0 : return lldp_ok;
248 : }
249 :
250 : static clib_error_t *
251 0 : lldp_cfg_cmd (vlib_main_t * vm, unformat_input_t * input,
252 : vlib_cli_command_t * cmd)
253 : {
254 0 : int hold_time = 0;
255 0 : int tx_interval = 0;
256 0 : u8 *host = NULL;
257 0 : clib_error_t *ret = NULL;
258 :
259 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
260 : {
261 0 : if (unformat (input, "system-name %s", &host))
262 : {
263 : }
264 0 : else if (unformat (input, "tx-hold %d", &hold_time))
265 : {
266 0 : if (hold_time < LLDP_MIN_TX_HOLD || hold_time > LLDP_MAX_TX_HOLD)
267 : {
268 : ret =
269 0 : 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 0 : goto out;
274 : }
275 : }
276 0 : else if (unformat (input, "tx-interval %d", &tx_interval))
277 : {
278 0 : if (tx_interval < LLDP_MIN_TX_INTERVAL ||
279 0 : tx_interval > LLDP_MAX_TX_INTERVAL)
280 : {
281 : ret =
282 0 : 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 0 : goto out;
287 : }
288 : }
289 : else
290 : {
291 0 : break;
292 : }
293 : }
294 : ret =
295 0 : lldp_cfg_err_to_clib_err (lldp_cfg_set (&host, hold_time, tx_interval));
296 0 : out:
297 0 : vec_free (host);
298 0 : return ret;
299 : }
300 :
301 : /* *INDENT-OFF* */
302 121687 : VLIB_CLI_COMMAND(set_interface_lldp_cmd, static) = {
303 : .path = "set interface lldp",
304 : .short_help = "set interface lldp <interface> | sw_if_index <idx>"
305 : " [port-desc <string>] [mgmt-ip4 <string>]"
306 : " [mgmt-ip6 <string>] [mgmt-oid <string>] [disable]",
307 : .function = lldp_intf_cmd,
308 : };
309 :
310 121687 : VLIB_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 :
318 : static const char *
319 0 : lldp_chassis_id_subtype_str (lldp_chassis_id_subtype_t t)
320 : {
321 0 : switch (t)
322 : {
323 : #define F(num, val, str) \
324 : case num: \
325 : return str;
326 0 : foreach_chassis_id_subtype (F)
327 : #undef F
328 : }
329 0 : return "unknown chassis subtype";
330 : }
331 :
332 : static const char *
333 0 : lldp_port_id_subtype_str (lldp_port_id_subtype_t t)
334 : {
335 0 : switch (t)
336 : {
337 : #define F(num, val, str) \
338 : case num: \
339 : return str;
340 0 : foreach_port_id_subtype (F)
341 : #undef F
342 : }
343 0 : 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 : */
354 : u8 *
355 0 : format_lldp_port_id (u8 * s, va_list * va)
356 : {
357 0 : const lldp_port_id_subtype_t subtype = va_arg (*va, unsigned);
358 0 : const u8 *id = va_arg (*va, u8 *);
359 0 : const unsigned len = va_arg (*va, unsigned);
360 0 : const int detail = va_arg (*va, int);
361 0 : if (!id)
362 : {
363 0 : return s;
364 : }
365 0 : switch (subtype)
366 : {
367 0 : 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 0 : if (detail)
375 : {
376 0 : s = format (s, "%U(%s)", format_ascii_bytes, id, len,
377 : lldp_port_id_subtype_str (subtype));
378 : }
379 : else
380 : {
381 0 : s = format (s, "%U", format_ascii_bytes, id, len);
382 : }
383 0 : break;
384 0 : case LLDP_PORT_ID_SUBTYPE_NAME (mac_addr):
385 0 : if (ETHER_ADDR_LEN == len)
386 : {
387 0 : if (detail)
388 : {
389 0 : s = format (s, "%U(%s)", format_mac_address, id,
390 : lldp_port_id_subtype_str (subtype));
391 : }
392 : else
393 : {
394 0 : s = format (s, "%U", format_mac_address, id);
395 : }
396 0 : break;
397 : }
398 : /* fallthrough */
399 : case LLDP_PORT_ID_SUBTYPE_NAME (net_addr):
400 : /* TODO */
401 : /* fallthrough */
402 : default:
403 0 : if (detail)
404 : {
405 0 : s = format (s, "%U(%s)", format_hex_bytes, id, len,
406 : lldp_port_id_subtype_str (subtype));
407 : }
408 : else
409 : {
410 0 : s = format (s, "%U", format_hex_bytes, id, len);
411 : }
412 0 : break;
413 : }
414 0 : 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 : */
426 : u8 *
427 0 : format_lldp_chassis_id (u8 * s, va_list * va)
428 : {
429 0 : const lldp_chassis_id_subtype_t subtype =
430 : va_arg (*va, lldp_chassis_id_subtype_t);
431 0 : const u8 *id = va_arg (*va, u8 *);
432 0 : const unsigned len = va_arg (*va, unsigned);
433 0 : const int detail = va_arg (*va, int);
434 0 : if (!id)
435 : {
436 0 : return s;
437 : }
438 0 : switch (subtype)
439 : {
440 0 : 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 0 : if (detail)
450 : {
451 0 : s = format (s, "%U(%s)", format_ascii_bytes, id, len,
452 : lldp_chassis_id_subtype_str (subtype));
453 : }
454 : else
455 : {
456 0 : s = format (s, "%U", format_ascii_bytes, id, len);
457 : }
458 0 : break;
459 0 : case LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr):
460 0 : if (ETHER_ADDR_LEN == len)
461 : {
462 0 : if (detail)
463 : {
464 0 : s = format (s, "%U(%s)", format_mac_address, id,
465 : lldp_chassis_id_subtype_str (subtype));
466 : }
467 : else
468 : {
469 0 : s = format (s, "%U", format_mac_address, id);
470 : }
471 0 : break;
472 : }
473 : /* fallthrough */
474 : case LLDP_CHASS_ID_SUBTYPE_NAME (net_addr):
475 : /* TODO */
476 : default:
477 0 : if (detail)
478 : {
479 0 : s = format (s, "%U(%s)", format_hex_bytes, id, len,
480 : lldp_chassis_id_subtype_str (subtype));
481 : }
482 : else
483 : {
484 0 : s = format (s, "%U", format_hex_bytes, id, len);
485 : }
486 0 : break;
487 : }
488 0 : return s;
489 : }
490 :
491 : /*
492 : * convert a tlv code to human-readable string
493 : */
494 : static const char *
495 0 : lldp_tlv_code_str (lldp_tlv_code_t t)
496 : {
497 0 : switch (t)
498 : {
499 : #define F(n, t, s) \
500 : case n: \
501 : return s;
502 0 : foreach_lldp_tlv_type (F)
503 : #undef F
504 : }
505 0 : 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 : */
514 : u8 *
515 0 : format_lldp_tlv (u8 * s, va_list * va)
516 : {
517 0 : const lldp_tlv_t *tlv = va_arg (*va, lldp_tlv_t *);
518 0 : if (!tlv)
519 : {
520 0 : return s;
521 : }
522 0 : u16 l = lldp_tlv_get_length (tlv);
523 0 : switch (lldp_tlv_get_code (tlv))
524 : {
525 0 : case LLDP_TLV_NAME (chassis_id):
526 0 : s = format (s, "%U", format_lldp_chassis_id,
527 0 : ((lldp_chassis_id_tlv_t *) tlv)->subtype,
528 0 : ((lldp_chassis_id_tlv_t *) tlv)->id,
529 : l - STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype), 1);
530 0 : break;
531 0 : case LLDP_TLV_NAME (port_id):
532 0 : s = format (s, "%U", format_lldp_port_id,
533 0 : ((lldp_port_id_tlv_t *) tlv)->subtype,
534 0 : ((lldp_port_id_tlv_t *) tlv)->id,
535 : l - STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype), 1);
536 0 : break;
537 0 : case LLDP_TLV_NAME (ttl):
538 0 : s = format (s, "%d", ntohs (((lldp_ttl_tlv_t *) tlv)->ttl));
539 0 : break;
540 0 : case LLDP_TLV_NAME (sys_name):
541 : /* fallthrough */
542 : case LLDP_TLV_NAME (sys_desc):
543 0 : s = format (s, "%U", format_ascii_bytes, tlv->v, l);
544 0 : break;
545 0 : default:
546 0 : s = format (s, "%U", format_hex_bytes, tlv->v, l);
547 : }
548 :
549 0 : return s;
550 : }
551 :
552 : static u8 *
553 0 : format_time_ago (u8 * s, va_list * va)
554 : {
555 0 : f64 ago = va_arg (*va, double);
556 0 : f64 now = va_arg (*va, double);
557 0 : if (ago < 0.01)
558 : {
559 0 : return format (s, "never");
560 : }
561 0 : return format (s, "%.1fs ago", now - ago);
562 : }
563 :
564 : static u8 *
565 0 : format_lldp_intfs_detail (u8 * s, vlib_main_t * vm, const lldp_main_t * lm)
566 : {
567 0 : 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 0 : s = format (s, "LLDP configuration:\n");
572 0 : if (lm->sys_name)
573 : {
574 0 : s = format (s, "Configured system name: %U\n", format_ascii_bytes,
575 0 : lm->sys_name, vec_len (lm->sys_name));
576 : }
577 :
578 0 : s = format (s, "Configured tx-hold: %d\n", (int) lm->msg_tx_hold);
579 0 : s = format (s, "Configured tx-interval: %d\n", (int) lm->msg_tx_interval);
580 0 : s = format (s, "\nLLDP-enabled interface table:\n");
581 0 : f64 now = vlib_time_now (vm);
582 :
583 : /* *INDENT-OFF* */
584 0 : pool_foreach (
585 : n, lm->intfs) {
586 0 : hw = vnet_get_hw_interface(vnm, n->hw_if_index);
587 0 : sw = vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
588 :
589 0 : s = format(s, "\nLocal Interface name: %v\n"
590 : "Local Port Description: %s\n",
591 : hw->name, n->port_desc);
592 0 : if (n->mgmt_ip4)
593 : {
594 0 : s = format (s, "Local Management address: %U\n",
595 0 : format_ip4_address, n->mgmt_ip4, vec_len (n->mgmt_ip4));
596 : }
597 :
598 0 : if (n->mgmt_ip6)
599 : {
600 0 : s = format (s, "Local Management address IPV6: %U\n",
601 0 : format_ip6_address, n->mgmt_ip6, vec_len (n->mgmt_ip6));
602 : }
603 :
604 0 : if (n->mgmt_oid)
605 : {
606 0 : s = format (s, "Local Management address OID: %U\n",
607 0 : format_ascii_bytes, n->mgmt_oid, vec_len (n->mgmt_oid));
608 : }
609 :
610 : /* Interface shutdown */
611 0 : if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
612 : {
613 0 : s = format(s, "Interface/peer state: interface down\n"
614 : "Last packet sent: %U\n",
615 : format_time_ago, n->last_sent, now);
616 : }
617 0 : else if (now < n->last_heard + n->ttl)
618 : {
619 0 : s = format(s,
620 : "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 0 : format_lldp_chassis_id, n->chassis_id_subtype,
624 0 : n->chassis_id, vec_len(n->chassis_id), 1,
625 0 : format_lldp_port_id, n->port_id_subtype, n->port_id,
626 0 : 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 : {
631 0 : s = format(s,
632 : "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 0 : format_lldp_chassis_id, n->chassis_id_subtype,
637 0 : n->chassis_id, vec_len(n->chassis_id), 1,
638 0 : format_lldp_port_id, n->port_id_subtype, n->port_id,
639 0 : 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 0 : return s;
645 : }
646 :
647 : static u8 *
648 0 : format_lldp_intfs (u8 * s, va_list * va)
649 : {
650 0 : vlib_main_t *vm = va_arg (*va, vlib_main_t *);
651 0 : const lldp_main_t *lm = va_arg (*va, lldp_main_t *);
652 0 : const int detail = va_arg (*va, int);
653 0 : vnet_main_t *vnm = &vnet_main;
654 : const lldp_intf_t *n;
655 :
656 0 : if (detail)
657 : {
658 0 : return format_lldp_intfs_detail (s, vm, lm);
659 : }
660 :
661 0 : f64 now = vlib_time_now (vm);
662 0 : 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 0 : pool_foreach (
668 : n, lm->intfs) {
669 : const vnet_hw_interface_t *hw =
670 0 : vnet_get_hw_interface(vnm, n->hw_if_index);
671 : const vnet_sw_interface_t *sw =
672 0 : vnet_get_sw_interface(lm->vnet_main, hw->sw_if_index);
673 : /* Interface shutdown */
674 0 : if (!(sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
675 0 : continue;
676 0 : if (now < n->last_heard + n->ttl)
677 : {
678 0 : s = format(s, "%-25v %-25U %-25U %=15U %=15U %=10s\n", hw->name,
679 0 : format_lldp_chassis_id, n->chassis_id_subtype,
680 0 : n->chassis_id, vec_len(n->chassis_id), 0,
681 0 : format_lldp_port_id, n->port_id_subtype, n->port_id,
682 0 : 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 : {
687 0 : s = format(s, "%-25v %-25s %-25s %=15U %=15U %=10s\n", hw->name,
688 : "", "", format_time_ago, n->last_heard, now,
689 : format_time_ago, n->last_sent, now, "inactive");
690 : }
691 : }
692 : /* *INDENT-ON* */
693 0 : return s;
694 : }
695 :
696 : static clib_error_t *
697 0 : show_lldp (vlib_main_t * vm, unformat_input_t * input,
698 : CLIB_UNUSED (vlib_cli_command_t * lmd))
699 : {
700 0 : lldp_main_t *lm = &lldp_main;
701 :
702 0 : if (unformat (input, "detail"))
703 : {
704 0 : vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 1);
705 : }
706 : else
707 : {
708 0 : vlib_cli_output (vm, "%U\n", format_lldp_intfs, vm, lm, 0);
709 : }
710 0 : return 0;
711 : }
712 :
713 : /* *INDENT-OFF* */
714 121687 : VLIB_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 : */
726 : u8 *
727 0 : lldp_input_format_trace (u8 * s, va_list * args)
728 : {
729 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
730 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
731 0 : const lldp_input_trace_t *t = va_arg (*args, lldp_input_trace_t *);
732 : const u8 *cur;
733 : const lldp_tlv_t *tlv;
734 0 : cur = t->data;
735 0 : while (((cur + lldp_tlv_get_length ((lldp_tlv_t *) cur)) <
736 0 : t->data + t->len))
737 : {
738 0 : tlv = (lldp_tlv_t *) cur;
739 0 : if (cur == t->data)
740 : {
741 0 : 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 0 : 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 0 : cur += STRUCT_SIZE_OF (lldp_tlv_t, head) + lldp_tlv_get_length (tlv);
752 : }
753 :
754 0 : 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 : */
|