]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/client/display.c
Separate daemon and client code. Provide a client library.
[thirdparty/lldpd.git] / src / client / display.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <arpa/inet.h>
28
29 #include "../log.h"
30 #include "client.h"
31
32 static void
33 display_cap(struct writer * w, lldpctl_atom_t *chassis, u_int8_t bit, char *symbol)
34 {
35 if (lldpctl_atom_get_int(chassis, lldpctl_k_chassis_cap_available) & bit) {
36 tag_start(w, "capability", "Capability");
37 tag_attr (w, "type", "", symbol );
38 tag_attr (w, "enabled", "",
39 (lldpctl_atom_get_int(chassis, lldpctl_k_chassis_cap_enabled) & bit)?
40 "on":"off");
41 tag_end (w);
42 }
43 }
44
45 static void
46 display_med_capability(struct writer *w, long int available, int cap,
47 const char *symbol)
48 {
49 if (available & cap) {
50 tag_start(w, "capability", "Capability");
51 tag_attr(w, "type", "", symbol);
52 tag_end(w);
53 }
54 }
55
56 static char*
57 totag(const char *value)
58 {
59 int i;
60 static char *result = NULL;
61 free(result); result = NULL;
62 if (!value) return "none";
63 result = calloc(1, strlen(value));
64 if (!result) return "none";
65 for (i = 0; i < strlen(value); i++) {
66 switch (value[i]) {
67 case ' ': result[i] = '-'; break;
68 default: result[i] = tolower(value[i]); break;
69 }
70 }
71 return result;
72 }
73
74 static void
75 display_med(struct writer *w, lldpctl_atom_t *port)
76 {
77 lldpctl_atom_t *medpolicies, *medpolicy;
78 lldpctl_atom_t *medlocations, *medlocation;
79 lldpctl_atom_t *caelements, *caelement;
80 long int cap = lldpctl_atom_get_int(port, lldpctl_k_chassis_med_cap);
81 const char *type;
82
83 if (lldpctl_atom_get_int(port, lldpctl_k_chassis_med_type) <= 0)
84 return;
85
86 tag_start(w, "lldp-med", "LLDP-MED");
87
88 tag_datatag(w, "device-type", "Device Type",
89 lldpctl_atom_get_str(port, lldpctl_k_chassis_med_type));
90
91 display_med_capability(w, cap, LLDP_MED_CAP_CAP, "Capabilities");
92 display_med_capability(w, cap, LLDP_MED_CAP_POLICY, "Policy");
93 display_med_capability(w, cap, LLDP_MED_CAP_LOCATION, "Location");
94 display_med_capability(w, cap, LLDP_MED_CAP_MDI_PSE, "MDI/PSE");
95 display_med_capability(w, cap, LLDP_MED_CAP_MDI_PD, "MDI/PD");
96 display_med_capability(w, cap, LLDP_MED_CAP_IV, "Inventory");
97
98 /* LLDP MED policies */
99 medpolicies = lldpctl_atom_get(port, lldpctl_k_port_med_policies);
100 lldpctl_atom_foreach(medpolicies, medpolicy) {
101 if (lldpctl_atom_get_int(medpolicy,
102 lldpctl_k_med_policy_type) <= 0) continue;
103
104 tag_start(w, "policy", "LLDP-MED Network Policy for");
105 tag_attr(w, "apptype", "", lldpctl_atom_get_str(medpolicy, lldpctl_k_med_policy_type));
106 tag_attr(w, "defined", "Defined",
107 (lldpctl_atom_get_int(medpolicy,
108 lldpctl_k_med_policy_unknown) > 0)?"no":"yes");
109
110 if (lldpctl_atom_get_int(medpolicy,
111 lldpctl_k_med_policy_tagged) > 0) {
112 int vid = lldpctl_atom_get_int(medpolicy,
113 lldpctl_k_med_policy_vid);
114 tag_start(w, "vlan", "VLAN");
115 if (vid == 0) {
116 tag_attr(w, "vid", "", "priority");
117 } else if (vid == 4095) {
118 tag_attr(w, "vid", "", "reserved");
119 } else {
120 tag_attr(w, "vid", "",
121 lldpctl_atom_get_str(medpolicy,
122 lldpctl_k_med_policy_vid));
123 }
124 tag_end(w);
125 }
126
127 tag_datatag(w, "priority", "Priority",
128 lldpctl_atom_get_str(medpolicy,
129 lldpctl_k_med_policy_priority));
130 tag_datatag(w, "dscp", "DSCP Value",
131 lldpctl_atom_get_str(medpolicy,
132 lldpctl_k_med_policy_dscp));
133
134 tag_end(w);
135 }
136 lldpctl_atom_dec_ref(medpolicies);
137
138 /* LLDP MED locations */
139 medlocations = lldpctl_atom_get(port, lldpctl_k_port_med_locations);
140 lldpctl_atom_foreach(medlocations, medlocation) {
141 int format = lldpctl_atom_get_int(medlocation,
142 lldpctl_k_med_location_format);
143 if (format <= 0) continue;
144 tag_start(w, "location", "LLDP-MED Location Identification");
145 tag_attr(w, "type", "Type",
146 lldpctl_atom_get_str(medlocation,
147 lldpctl_k_med_location_format));
148
149 switch (format) {
150 case LLDP_MED_LOCFORMAT_COORD:
151 tag_attr(w, "geoid", "Geoid",
152 lldpctl_atom_get_str(medlocation,
153 lldpctl_k_med_location_geoid));
154 tag_datatag(w, "lat", "Latitude",
155 lldpctl_atom_get_str(medlocation,
156 lldpctl_k_med_location_latitude));
157 tag_datatag(w, "lon", "Longitude",
158 lldpctl_atom_get_str(medlocation,
159 lldpctl_k_med_location_longitude));
160 tag_start(w, "altitude", "Altitude");
161 tag_attr(w, "unit", "", lldpctl_atom_get_str(medlocation,
162 lldpctl_k_med_location_altitude_unit));
163 tag_data(w, lldpctl_atom_get_str(medlocation,
164 lldpctl_k_med_location_altitude));
165 tag_end(w);
166 break;
167 case LLDP_MED_LOCFORMAT_CIVIC:
168 tag_datatag(w, "country", "Country",
169 lldpctl_atom_get_str(medlocation,
170 lldpctl_k_med_location_country));
171 caelements = lldpctl_atom_get(medlocation,
172 lldpctl_k_med_location_ca_elements);
173 lldpctl_atom_foreach(caelements, caelement) {
174 type = lldpctl_atom_get_str(caelement,
175 lldpctl_k_med_civicaddress_type);
176 tag_datatag(w, totag(type), type,
177 lldpctl_atom_get_str(caelement,
178 lldpctl_k_med_civicaddress_value));
179 }
180 lldpctl_atom_dec_ref(caelements);
181 break;
182 case LLDP_MED_LOCFORMAT_ELIN:
183 tag_datatag(w, "ecs", "ECS ELIN",
184 lldpctl_atom_get_str(medlocation,
185 lldpctl_k_med_location_elin));
186 break;
187 }
188
189 tag_end(w);
190 }
191 lldpctl_atom_dec_ref(medlocations);
192
193 /* LLDP MED power */
194 if (lldpctl_atom_get_int(port, lldpctl_k_med_power_type) > 0) {
195 tag_start(w, "poe", "Extended Power-over-Ethernet");
196
197 tag_datatag(w, "device-type", "Power Type & Source",
198 lldpctl_atom_get_str(port, lldpctl_k_med_power_type));
199 tag_datatag(w, "source", "Power Source",
200 lldpctl_atom_get_str(port, lldpctl_k_med_power_source));
201 tag_datatag(w, "priority", "Power priority",
202 lldpctl_atom_get_str(port, lldpctl_k_med_power_priority));
203 tag_datatag(w, "power", "Power Value",
204 lldpctl_atom_get_str(port, lldpctl_k_med_power_val));
205 }
206
207 /* LLDP MED inventory */
208 do {
209 const char *hw = lldpctl_atom_get_str(port,
210 lldpctl_k_chassis_med_inventory_hw);
211 const char *sw = lldpctl_atom_get_str(port,
212 lldpctl_k_chassis_med_inventory_sw);
213 const char *fw = lldpctl_atom_get_str(port,
214 lldpctl_k_chassis_med_inventory_fw);
215 const char *sn = lldpctl_atom_get_str(port,
216 lldpctl_k_chassis_med_inventory_sn);
217 const char *manuf = lldpctl_atom_get_str(port,
218 lldpctl_k_chassis_med_inventory_manuf);
219 const char *model = lldpctl_atom_get_str(port,
220 lldpctl_k_chassis_med_inventory_model);
221 const char *asset = lldpctl_atom_get_str(port,
222 lldpctl_k_chassis_med_inventory_asset);
223 if (!(hw || sw || fw || sn ||
224 manuf || model || asset)) break;
225
226 tag_start(w, "inventory", "Inventory");
227 tag_datatag(w, "hardware", "Hardware Revision", hw);
228 tag_datatag(w, "software", "Software Revision", sw);
229 tag_datatag(w, "firmware", "Firmware Revision", fw);
230 tag_datatag(w, "serial", "Serial Number", sn);
231 tag_datatag(w, "manufacturer", "Manufacturer", manuf);
232 tag_datatag(w, "model", "Model", model);
233 tag_datatag(w, "asset", "Asset ID", asset);
234 tag_end(w);
235 } while(0);
236
237 tag_end(w);
238 }
239
240 static void
241 display_chassis(struct writer* w, lldpctl_atom_t* neighbor)
242 {
243 lldpctl_atom_t *mgmts, *mgmt;
244
245 tag_start(w, "chassis", "Chassis");
246 tag_start(w, "id", "ChassisID");
247 tag_attr (w, "type", "",
248 lldpctl_atom_get_str(neighbor,
249 lldpctl_k_chassis_id_subtype));
250 tag_data(w, lldpctl_atom_get_str(neighbor,
251 lldpctl_k_chassis_id));
252 tag_end(w);
253 tag_datatag(w, "name", "SysName",
254 lldpctl_atom_get_str(neighbor, lldpctl_k_chassis_name));
255 tag_datatag(w, "descr", "SysDescr",
256 lldpctl_atom_get_str(neighbor, lldpctl_k_chassis_descr));
257
258 /* Management addresses */
259 mgmts = lldpctl_atom_get(neighbor, lldpctl_k_chassis_mgmt);
260 lldpctl_atom_foreach(mgmts, mgmt) {
261 tag_datatag(w, "mgmt-ip", "MgmtIP",
262 lldpctl_atom_get_str(mgmt, lldpctl_k_mgmt_ip));
263 }
264 lldpctl_atom_dec_ref(mgmts);
265
266 /* Capabilities */
267 display_cap(w, neighbor, LLDP_CAP_OTHER, "Other");
268 display_cap(w, neighbor, LLDP_CAP_REPEATER, "Repeater");
269 display_cap(w, neighbor, LLDP_CAP_BRIDGE, "Bridge");
270 display_cap(w, neighbor, LLDP_CAP_ROUTER, "Router");
271 display_cap(w, neighbor, LLDP_CAP_WLAN, "Wlan");
272 display_cap(w, neighbor, LLDP_CAP_TELEPHONE, "Tel");
273 display_cap(w, neighbor, LLDP_CAP_DOCSIS, "Docsis");
274 display_cap(w, neighbor, LLDP_CAP_STATION, "Station");
275
276 tag_end(w);
277 }
278
279 static void
280 display_autoneg(struct writer * w, int advertised, int bithd, int bitfd, char *desc)
281 {
282 if (!((advertised & bithd) ||
283 (advertised & bitfd)))
284 return;
285
286 tag_start(w, "advertised", "Adv");
287 tag_attr(w, "type", "", desc);
288 tag_attr(w, "hd", "HD", (advertised & bithd)?"yes":"no");
289 tag_attr(w, "fd", "FD", (advertised)?"yes":"no");
290 tag_end (w);
291 }
292
293 static void
294 display_port(struct writer *w, lldpctl_atom_t *port)
295 {
296 tag_start(w, "port", "Port");
297 tag_start(w, "id", "PortID");
298 tag_attr (w, "type", "",
299 lldpctl_atom_get_str(port, lldpctl_k_port_id_subtype));
300 tag_data(w, lldpctl_atom_get_str(port, lldpctl_k_port_id));
301 tag_end(w);
302
303 tag_datatag(w, "descr", "PortDescr",
304 lldpctl_atom_get_str(port, lldpctl_k_port_descr));
305
306 /* Dot3 */
307 tag_datatag(w, "mfs", "MFS",
308 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_mfs));
309 tag_datatag(w, "aggregation", " Port is aggregated. PortAggregID",
310 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_aggregid));
311
312 do {
313 long int autoneg_support, autoneg_enabled, autoneg_advertised;
314 autoneg_support = lldpctl_atom_get_int(port,
315 lldpctl_k_port_dot3_autoneg_support);
316 autoneg_enabled = lldpctl_atom_get_int(port,
317 lldpctl_k_port_dot3_autoneg_enabled);
318 autoneg_advertised = lldpctl_atom_get_int(port,
319 lldpctl_k_port_dot3_autoneg_advertised);
320 if (autoneg_support > 0 || autoneg_enabled > 0) {
321 tag_start(w, "auto-negotiation", "PMD autoneg");
322 tag_attr (w, "supported", "supported",
323 (autoneg_support > 0)?"yes":"no");
324 tag_attr (w, "enabled", "enabled",
325 (autoneg_enabled > 0)?"yes":"no");
326
327 if (autoneg_enabled > 0) {
328 if (autoneg_advertised < 0)
329 autoneg_advertised = 0;
330 display_autoneg(w, autoneg_advertised,
331 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
332 LLDP_DOT3_LINK_AUTONEG_10BASET_FD,
333 "10Base-T");
334 display_autoneg(w, autoneg_advertised,
335 LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
336 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD,
337 "100Base-T");
338 display_autoneg(w, autoneg_advertised,
339 LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
340 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD,
341 "100Base-T2");
342 display_autoneg(w, autoneg_advertised,
343 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
344 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD,
345 "100Base-X");
346 display_autoneg(w, autoneg_advertised,
347 LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
348 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD,
349 "1000Base-T");
350 }
351 tag_datatag(w, "current", "MAU oper type",
352 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_mautype));
353 tag_end(w);
354 }
355 } while (0);
356
357 do {
358 lldpctl_atom_t *dot3_power = lldpctl_atom_get(port,
359 lldpctl_k_port_dot3_power);
360 int devicetype = lldpctl_atom_get_int(dot3_power,
361 lldpctl_k_dot3_power_devicetype);
362 if (devicetype > 0) {
363 tag_start(w, "power", "MDI Power");
364 tag_attr(w, "supported", "supported",
365 (lldpctl_atom_get_int(dot3_power,
366 lldpctl_k_dot3_power_supported) > 0)?"yes":"no");
367 tag_attr(w, "enabled", "enabled",
368 (lldpctl_atom_get_int(dot3_power,
369 lldpctl_k_dot3_power_enabled) > 0)?"yes":"no");
370 tag_attr(w, "paircontrol", "pair control",
371 (lldpctl_atom_get_int(dot3_power,
372 lldpctl_k_dot3_power_paircontrol) > 0)?"yes":"no");
373 tag_start(w, "device-type", "Device type");
374 tag_data(w, lldpctl_atom_get_str(dot3_power,
375 lldpctl_k_dot3_power_devicetype));;
376 tag_end(w);
377 tag_start(w, "pairs", "Power pairs");
378 tag_data(w, lldpctl_atom_get_str(dot3_power,
379 lldpctl_k_dot3_power_pairs));
380 tag_end(w);
381 tag_start(w, "class", "Class");
382 tag_data(w, lldpctl_atom_get_str(dot3_power,
383 lldpctl_k_dot3_power_class));
384 tag_end(w);
385
386 /* 802.3at */
387 if (lldpctl_atom_get_int(dot3_power,
388 lldpctl_k_dot3_power_type) > LLDP_DOT3_POWER_8023AT_OFF) {
389 tag_start(w, "power-type", "Power type");
390 tag_data(w, lldpctl_atom_get_str(dot3_power,
391 lldpctl_k_dot3_power_type));
392 tag_end(w);
393
394 tag_start(w, "source", "Power Source");
395 tag_data(w, lldpctl_atom_get_str(dot3_power,
396 lldpctl_k_dot3_power_source));
397 tag_end(w);
398
399 tag_start(w, "priority", "Power Priority");
400 tag_data(w, lldpctl_atom_get_str(dot3_power,
401 lldpctl_k_dot3_power_priority));
402 tag_end(w);
403
404 tag_start(w, "requested", "PD requested power Value");
405 tag_data(w, lldpctl_atom_get_str(dot3_power,
406 lldpctl_k_dot3_power_requested));
407 tag_end(w);
408
409 tag_start(w, "allocated", "PSE allocated power Value");
410 tag_data(w, lldpctl_atom_get_str(dot3_power,
411 lldpctl_k_dot3_power_allocated));
412 tag_end(w);
413 }
414
415 tag_end(w);
416 }
417 lldpctl_atom_dec_ref(dot3_power);
418 } while(0);
419
420 tag_end(w);
421 }
422
423 static void
424 display_vlans(struct writer *w, lldpctl_atom_t *port)
425 {
426 lldpctl_atom_t *vlans, *vlan;
427 int foundpvid = 0;
428 int pvid, vid;
429
430 pvid = lldpctl_atom_get_int(port,
431 lldpctl_k_port_vlan_pvid);
432
433 vlans = lldpctl_atom_get(port, lldpctl_k_port_vlans);
434 lldpctl_atom_foreach(vlans, vlan) {
435 vid = lldpctl_atom_get_int(vlan,
436 lldpctl_k_vlan_id);
437 if (pvid == vid)
438 foundpvid = 1;
439
440 tag_start(w, "vlan", "VLAN");
441 tag_attr(w, "vlan-id", "",
442 lldpctl_atom_get_str(vlan, lldpctl_k_vlan_id));
443 if (pvid == vid)
444 tag_attr(w, "pvid", "pvid", "yes");
445 tag_data(w, lldpctl_atom_get_str(vlan,
446 lldpctl_k_vlan_name));
447 tag_end(w);
448 }
449 lldpctl_atom_dec_ref(vlans);
450
451 if (!foundpvid && pvid > 0) {
452 tag_start(w, "vlan", "VLAN");
453 tag_attr(w, "vlan-id", "",
454 lldpctl_atom_get_str(port,
455 lldpctl_k_port_vlan_pvid));
456 tag_attr(w, "pvid", "pvid", "yes");
457 tag_end(w);
458 }
459 }
460
461 static void
462 display_ppvids(struct writer *w, lldpctl_atom_t *port)
463 {
464 lldpctl_atom_t *ppvids, *ppvid;
465 ppvids = lldpctl_atom_get(port, lldpctl_k_port_ppvids);
466 lldpctl_atom_foreach(ppvids, ppvid) {
467 int status = lldpctl_atom_get_int(ppvid,
468 lldpctl_k_ppvid_status);
469 tag_start(w, "ppvid", "PPVID");
470 if (lldpctl_atom_get_int(ppvid,
471 lldpctl_k_ppvid_id) > 0)
472 tag_attr(w, "value", "",
473 lldpctl_atom_get_str(ppvid,
474 lldpctl_k_ppvid_id));
475 tag_attr(w, "supported", "supported",
476 (status & LLDP_PPVID_CAP_SUPPORTED)?"yes":"no");
477 tag_attr(w, "enabled", "enabled",
478 (status & LLDP_PPVID_CAP_ENABLED)?"yes":"no");
479 tag_end(w);
480 }
481 lldpctl_atom_dec_ref(ppvids);
482 }
483
484 static void
485 display_pids(struct writer *w, lldpctl_atom_t *port)
486 {
487 lldpctl_atom_t *pids, *pid;
488 pids = lldpctl_atom_get(port, lldpctl_k_port_pis);
489 lldpctl_atom_foreach(pids, pid) {
490 const char *pi = lldpctl_atom_get_str(pid, lldpctl_k_pi_id);
491 if (pi && strlen(pi) > 0)
492 tag_datatag(w, "pi", "PI", pi);
493 }
494 lldpctl_atom_dec_ref(pids);
495 }
496
497 static const char*
498 display_age(time_t lastchange)
499 {
500 static char sage[30];
501 int age = (int)(time(NULL) - lastchange);
502 if (snprintf(sage, sizeof(sage),
503 "%d day%s, %02d:%02d:%02d",
504 age / (60*60*24),
505 (age / (60*60*24) > 1)?"s":"",
506 (age / (60*60)) % 24,
507 (age / 60) % 60,
508 age % 60) >= sizeof(sage))
509 return "too much";
510 else
511 return sage;
512 }
513
514 void
515 display_interfaces(lldpctl_conn_t *conn, const char *fmt, int hidden,
516 int argc, char *argv[])
517 {
518 int i;
519 struct writer * w;
520 lldpctl_atom_t *iface_list;
521 lldpctl_atom_t *iface;
522 lldpctl_atom_t *port;
523 lldpctl_atom_t *neighbors;
524 lldpctl_atom_t *neighbor;
525
526 iface_list = lldpctl_get_interfaces(conn);
527 if (!iface_list) {
528 LLOG_WARNX("not able to get the list of interfaces: %s", lldpctl_strerror(lldpctl_last_error(conn)));
529 return;
530 }
531
532 if (strcmp(fmt, "plain") == 0) {
533 w = txt_init(stdout);
534 } else if (strcmp(fmt, "keyvalue") == 0) {
535 w = kv_init(stdout);
536 }
537 #ifdef USE_XML
538 else if (strcmp(fmt,"xml") == 0 ) {
539 w = xml_init(stdout);
540 }
541 #endif
542 else {
543 w = txt_init(stdout);
544 }
545
546 tag_start(w, "lldp", "LLDP neighbors");
547 lldpctl_atom_foreach(iface_list, iface) {
548 if (optind < argc) {
549 for (i = optind; i < argc; i++)
550 if (strcmp(argv[i],
551 lldpctl_atom_get_str(iface,
552 lldpctl_k_interface_name)) == 0)
553 break;
554 if (i == argc)
555 continue;
556 }
557 port = lldpctl_get_port(iface);
558 neighbors = lldpctl_atom_get(port, lldpctl_k_port_neighbors);
559 lldpctl_atom_foreach(neighbors, neighbor) {
560 if (!hidden &&
561 lldpctl_atom_get_int(neighbor, lldpctl_k_port_hidden))
562 continue;
563
564 tag_start(w, "interface", "Interface");
565 tag_attr(w, "name", "",
566 lldpctl_atom_get_str(iface, lldpctl_k_interface_name));
567 tag_attr(w, "via" , "via",
568 lldpctl_atom_get_str(neighbor, lldpctl_k_port_protocol));
569 tag_attr(w, "rid" , "RID",
570 lldpctl_atom_get_str(neighbor, lldpctl_k_chassis_index));
571 tag_attr(w, "age" , "Time",
572 display_age(lldpctl_atom_get_int(neighbor, lldpctl_k_port_age)));
573
574 display_chassis(w, neighbor);
575 display_port(w, neighbor);
576 display_vlans(w, neighbor);
577 display_ppvids(w, neighbor);
578 display_pids(w, neighbor);
579 display_med(w, neighbor);
580
581 tag_end(w);
582 }
583 lldpctl_atom_dec_ref(neighbors);
584 lldpctl_atom_dec_ref(port);
585 }
586 lldpctl_atom_dec_ref(iface_list);
587 tag_end(w);
588 w->finish(w);
589 }