1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
24 #include <sys/param.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <arpa/inet.h>
35 display_cap(struct writer
*w
, lldpctl_atom_t
*chassis
, u_int16_t bit
,
38 if (lldpctl_atom_get_int(chassis
, lldpctl_k_chassis_cap_available
) & bit
) {
39 tag_start(w
, "capability", "Capability");
40 tag_attr(w
, "type", "", symbol
);
41 tag_attr(w
, "enabled", "",
42 (lldpctl_atom_get_int(chassis
, lldpctl_k_chassis_cap_enabled
) &
51 display_med_capability(struct writer
*w
, long int available
, int cap
,
54 if (available
& cap
) {
55 tag_start(w
, "capability", "Capability");
56 tag_attr(w
, "type", "", symbol
);
57 tag_attr(w
, "available", "", "yes");
63 display_med(struct writer
*w
, lldpctl_atom_t
*port
, lldpctl_atom_t
*chassis
)
65 lldpctl_atom_t
*medpolicies
, *medpolicy
;
66 lldpctl_atom_t
*medlocations
, *medlocation
;
67 lldpctl_atom_t
*caelements
, *caelement
;
68 lldpctl_atom_t
*medpower
;
69 long int cap
= lldpctl_atom_get_int(chassis
, lldpctl_k_chassis_med_cap
);
72 if (lldpctl_atom_get_int(chassis
, lldpctl_k_chassis_med_type
) <= 0) return;
74 tag_start(w
, "lldp-med", "LLDP-MED");
76 tag_datatag(w
, "device-type", "Device Type",
77 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_med_type
));
79 display_med_capability(w
, cap
, LLDP_MED_CAP_CAP
, "Capabilities");
80 display_med_capability(w
, cap
, LLDP_MED_CAP_POLICY
, "Policy");
81 display_med_capability(w
, cap
, LLDP_MED_CAP_LOCATION
, "Location");
82 display_med_capability(w
, cap
, LLDP_MED_CAP_MDI_PSE
, "MDI/PSE");
83 display_med_capability(w
, cap
, LLDP_MED_CAP_MDI_PD
, "MDI/PD");
84 display_med_capability(w
, cap
, LLDP_MED_CAP_IV
, "Inventory");
86 /* LLDP MED policies */
87 medpolicies
= lldpctl_atom_get(port
, lldpctl_k_port_med_policies
);
88 lldpctl_atom_foreach(medpolicies
, medpolicy
)
90 if (lldpctl_atom_get_int(medpolicy
, lldpctl_k_med_policy_type
) <= 0)
93 tag_start(w
, "policy", "LLDP-MED Network Policy for");
94 tag_attr(w
, "apptype", "",
95 lldpctl_atom_get_str(medpolicy
, lldpctl_k_med_policy_type
));
96 tag_attr(w
, "defined", "Defined",
97 (lldpctl_atom_get_int(medpolicy
, lldpctl_k_med_policy_unknown
) >
102 if (lldpctl_atom_get_int(medpolicy
, lldpctl_k_med_policy_tagged
) > 0) {
104 lldpctl_atom_get_int(medpolicy
, lldpctl_k_med_policy_vid
);
105 tag_start(w
, "vlan", "VLAN");
107 tag_attr(w
, "vid", "", "priority");
108 } else if (vid
== 4095) {
109 tag_attr(w
, "vid", "", "reserved");
111 tag_attr(w
, "vid", "",
112 lldpctl_atom_get_str(medpolicy
,
113 lldpctl_k_med_policy_vid
));
118 tag_datatag(w
, "priority", "Priority",
119 lldpctl_atom_get_str(medpolicy
, lldpctl_k_med_policy_priority
));
120 /* Also give a numeric value */
122 lldpctl_atom_get_int(medpolicy
, lldpctl_k_med_policy_priority
);
123 char spcp
[2] = { pcp
+ '0', '\0' };
124 tag_datatag(w
, "pcp", "PCP", spcp
);
125 tag_datatag(w
, "dscp", "DSCP Value",
126 lldpctl_atom_get_str(medpolicy
, lldpctl_k_med_policy_dscp
));
130 lldpctl_atom_dec_ref(medpolicies
);
132 /* LLDP MED locations */
133 medlocations
= lldpctl_atom_get(port
, lldpctl_k_port_med_locations
);
134 lldpctl_atom_foreach(medlocations
, medlocation
)
137 lldpctl_atom_get_int(medlocation
, lldpctl_k_med_location_format
);
138 if (format
<= 0) continue;
139 tag_start(w
, "location", "LLDP-MED Location Identification");
140 tag_attr(w
, "type", "Type",
141 lldpctl_atom_get_str(medlocation
, lldpctl_k_med_location_format
));
144 case LLDP_MED_LOCFORMAT_COORD
:
145 tag_attr(w
, "geoid", "Geoid",
146 lldpctl_atom_get_str(medlocation
,
147 lldpctl_k_med_location_geoid
));
148 tag_datatag(w
, "lat", "Latitude",
149 lldpctl_atom_get_str(medlocation
,
150 lldpctl_k_med_location_latitude
));
151 tag_datatag(w
, "lon", "Longitude",
152 lldpctl_atom_get_str(medlocation
,
153 lldpctl_k_med_location_longitude
));
154 tag_start(w
, "altitude", "Altitude");
155 tag_attr(w
, "unit", "",
156 lldpctl_atom_get_str(medlocation
,
157 lldpctl_k_med_location_altitude_unit
));
159 lldpctl_atom_get_str(medlocation
,
160 lldpctl_k_med_location_altitude
));
163 case LLDP_MED_LOCFORMAT_CIVIC
:
164 tag_datatag(w
, "country", "Country",
165 lldpctl_atom_get_str(medlocation
,
166 lldpctl_k_med_location_country
));
167 caelements
= lldpctl_atom_get(medlocation
,
168 lldpctl_k_med_location_ca_elements
);
169 lldpctl_atom_foreach(caelements
, caelement
)
171 type
= lldpctl_atom_get_str(caelement
,
172 lldpctl_k_med_civicaddress_type
);
173 tag_datatag(w
, totag(type
), type
,
174 lldpctl_atom_get_str(caelement
,
175 lldpctl_k_med_civicaddress_value
));
177 lldpctl_atom_dec_ref(caelements
);
179 case LLDP_MED_LOCFORMAT_ELIN
:
180 tag_datatag(w
, "ecs", "ECS ELIN",
181 lldpctl_atom_get_str(medlocation
,
182 lldpctl_k_med_location_elin
));
188 lldpctl_atom_dec_ref(medlocations
);
191 medpower
= lldpctl_atom_get(port
, lldpctl_k_port_med_power
);
192 if (lldpctl_atom_get_int(medpower
, lldpctl_k_med_power_type
) > 0) {
193 tag_start(w
, "poe", "Extended Power-over-Ethernet");
195 tag_datatag(w
, "device-type", "Power Type & Source",
196 lldpctl_atom_get_str(medpower
, lldpctl_k_med_power_type
));
197 tag_datatag(w
, "source", "Power Source",
198 lldpctl_atom_get_str(medpower
, lldpctl_k_med_power_source
));
199 tag_datatag(w
, "priority", "Power priority",
200 lldpctl_atom_get_str(medpower
, lldpctl_k_med_power_priority
));
201 tag_datatag(w
, "power", "Power Value",
202 lldpctl_atom_get_str(medpower
, lldpctl_k_med_power_val
));
206 lldpctl_atom_dec_ref(medpower
);
208 /* LLDP MED inventory */
211 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_med_inventory_hw
);
213 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_med_inventory_sw
);
215 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_med_inventory_fw
);
217 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_med_inventory_sn
);
218 const char *manuf
= lldpctl_atom_get_str(chassis
,
219 lldpctl_k_chassis_med_inventory_manuf
);
220 const char *model
= lldpctl_atom_get_str(chassis
,
221 lldpctl_k_chassis_med_inventory_model
);
222 const char *asset
= lldpctl_atom_get_str(chassis
,
223 lldpctl_k_chassis_med_inventory_asset
);
224 if (!(hw
|| sw
|| fw
|| sn
|| manuf
|| model
|| asset
)) break;
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
);
241 display_chassis(struct writer
*w
, lldpctl_atom_t
*chassis
, int details
)
243 lldpctl_atom_t
*mgmts
, *mgmt
;
245 tag_start(w
, "chassis", "Chassis");
246 tag_start(w
, "id", "ChassisID");
247 tag_attr(w
, "type", "",
248 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_id_subtype
));
249 tag_data(w
, lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_id
));
251 tag_datatag(w
, "name", "SysName",
252 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_name
));
253 if (details
== DISPLAY_BRIEF
) {
257 tag_datatag(w
, "descr", "SysDescr",
258 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_descr
));
260 /* Management addresses */
261 mgmts
= lldpctl_atom_get(chassis
, lldpctl_k_chassis_mgmt
);
262 lldpctl_atom_foreach(mgmts
, mgmt
)
264 tag_datatag(w
, "mgmt-ip", "MgmtIP",
265 lldpctl_atom_get_str(mgmt
, lldpctl_k_mgmt_ip
));
266 if (lldpctl_atom_get_int(mgmt
, lldpctl_k_mgmt_iface_index
))
267 tag_datatag(w
, "mgmt-iface", "MgmtIface",
268 lldpctl_atom_get_str(mgmt
, lldpctl_k_mgmt_iface_index
));
270 lldpctl_atom_dec_ref(mgmts
);
273 display_cap(w
, chassis
, LLDP_CAP_OTHER
, "Other");
274 display_cap(w
, chassis
, LLDP_CAP_REPEATER
, "Repeater");
275 display_cap(w
, chassis
, LLDP_CAP_BRIDGE
, "Bridge");
276 display_cap(w
, chassis
, LLDP_CAP_ROUTER
, "Router");
277 display_cap(w
, chassis
, LLDP_CAP_WLAN
, "Wlan");
278 display_cap(w
, chassis
, LLDP_CAP_TELEPHONE
, "Tel");
279 display_cap(w
, chassis
, LLDP_CAP_DOCSIS
, "Docsis");
280 display_cap(w
, chassis
, LLDP_CAP_STATION
, "Station");
281 display_cap(w
, chassis
, LLDP_CAP_CVLAN
, "CVLAN");
282 display_cap(w
, chassis
, LLDP_CAP_SVLAN
, "SVLAN");
283 display_cap(w
, chassis
, LLDP_CAP_TPMRCOMP
, "TPMR");
289 display_custom_tlvs(struct writer
*w
, lldpctl_atom_t
*neighbor
)
291 lldpctl_atom_t
*custom_list
, *custom
;
292 int have_custom_tlvs
= 0;
294 const uint8_t *oui
, *oui_info
;
295 char buf
[1600]; /* should be enough for printing */
297 custom_list
= lldpctl_atom_get(neighbor
, lldpctl_k_custom_tlvs
);
298 lldpctl_atom_foreach(custom_list
, custom
)
300 /* This tag gets added only once, if there are any custom TLVs */
301 if (!have_custom_tlvs
) {
302 tag_start(w
, "unknown-tlvs", "Unknown TLVs");
306 oui
= lldpctl_atom_get_buffer(custom
, lldpctl_k_custom_tlv_oui
, &len
);
308 oui_info
= lldpctl_atom_get_buffer(custom
,
309 lldpctl_k_custom_tlv_oui_info_string
, &len
);
311 tag_start(w
, "unknown-tlv", "TLV");
313 /* Add OUI as attribute */
314 snprintf(buf
, sizeof(buf
), "%02X,%02X,%02X", oui
[0], oui
[1], oui
[2]);
315 tag_attr(w
, "oui", "OUI", buf
);
316 snprintf(buf
, sizeof(buf
), "%d",
317 (int)lldpctl_atom_get_int(custom
,
318 lldpctl_k_custom_tlv_oui_subtype
));
319 tag_attr(w
, "subtype", "SubType", buf
);
320 snprintf(buf
, sizeof(buf
), "%d", (int)len
);
321 tag_attr(w
, "len", "Len", buf
);
323 for (slen
= 0, i
= 0; i
< len
; ++i
)
324 slen
+= snprintf(buf
+ slen
,
325 sizeof(buf
) > slen
? sizeof(buf
) - slen
: 0,
326 "%02X%s", oui_info
[i
], ((i
< len
- 1) ? "," : ""));
331 lldpctl_atom_dec_ref(custom_list
);
333 if (have_custom_tlvs
) tag_end(w
);
337 display_autoneg(struct writer
*w
, int advertised
, int bithd
, int bitfd
,
340 if (!((advertised
& bithd
) || (advertised
& bitfd
))) return;
342 tag_start(w
, "advertised", "Adv");
343 tag_attr(w
, "type", "", desc
);
344 if (bitfd
!= bithd
) {
345 tag_attr(w
, "hd", "HD", (advertised
& bithd
) ? "yes" : "no");
346 tag_attr(w
, "fd", "FD", (advertised
& bitfd
) ? "yes" : "no");
352 display_port(struct writer
*w
, lldpctl_atom_t
*port
, int details
)
355 char buf
[5]; /* should be enough for printing */
357 tag_start(w
, "port", "Port");
358 tag_start(w
, "id", "PortID");
359 tag_attr(w
, "type", "", lldpctl_atom_get_str(port
, lldpctl_k_port_id_subtype
));
360 tag_data(w
, lldpctl_atom_get_str(port
, lldpctl_k_port_id
));
363 tag_datatag(w
, "descr", "PortDescr",
364 lldpctl_atom_get_str(port
, lldpctl_k_port_descr
));
366 if ((vlan_tx_tag
= lldpctl_atom_get_int(port
, lldpctl_k_port_vlan_tx
)) != -1) {
367 tag_start(w
, "vlanTX", "VlanTX");
368 snprintf(buf
, sizeof(buf
), "%d", vlan_tx_tag
& 0xfff);
369 tag_attr(w
, "id", "VID", buf
);
370 snprintf(buf
, sizeof(buf
), "%d", (vlan_tx_tag
>> 13) & 0x7);
371 tag_attr(w
, "prio", "Prio", buf
);
372 snprintf(buf
, sizeof(buf
), "%d", (vlan_tx_tag
>> 12) & 0x1);
373 tag_attr(w
, "dei", "DEI", buf
);
377 if (details
&& lldpctl_atom_get_int(port
, lldpctl_k_port_ttl
) > 0)
378 tag_datatag(w
, "ttl", "TTL",
379 lldpctl_atom_get_str(port
, lldpctl_k_port_ttl
));
382 if (details
== DISPLAY_DETAILS
) {
383 tag_datatag(w
, "mfs", "MFS",
384 lldpctl_atom_get_str(port
, lldpctl_k_port_dot3_mfs
));
385 tag_datatag(w
, "aggregation", "Port is aggregated. PortAggregID",
386 lldpctl_atom_get_str(port
, lldpctl_k_port_dot3_aggregid
));
388 long int autoneg_support
, autoneg_enabled
, autoneg_advertised
, mautype
;
390 lldpctl_atom_get_int(port
, lldpctl_k_port_dot3_autoneg_support
);
392 lldpctl_atom_get_int(port
, lldpctl_k_port_dot3_autoneg_enabled
);
394 lldpctl_atom_get_int(port
, lldpctl_k_port_dot3_autoneg_advertised
);
395 mautype
= lldpctl_atom_get_int(port
, lldpctl_k_port_dot3_mautype
);
396 if (autoneg_support
> 0 || autoneg_enabled
> 0 || mautype
> 0) {
397 tag_start(w
, "auto-negotiation", "PMD autoneg");
398 tag_attr(w
, "supported", "supported",
399 (autoneg_support
> 0) ? "yes" : "no");
400 tag_attr(w
, "enabled", "enabled",
401 (autoneg_enabled
> 0) ? "yes" : "no");
403 if (autoneg_enabled
> 0) {
404 if (autoneg_advertised
< 0) autoneg_advertised
= 0;
405 display_autoneg(w
, autoneg_advertised
,
406 LLDP_DOT3_LINK_AUTONEG_10BASE_T
,
407 LLDP_DOT3_LINK_AUTONEG_10BASET_FD
, "10Base-T");
408 display_autoneg(w
, autoneg_advertised
,
409 LLDP_DOT3_LINK_AUTONEG_100BASE_TX
,
410 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
, "100Base-TX");
411 display_autoneg(w
, autoneg_advertised
,
412 LLDP_DOT3_LINK_AUTONEG_100BASE_T2
,
413 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD
, "100Base-T2");
414 display_autoneg(w
, autoneg_advertised
,
415 LLDP_DOT3_LINK_AUTONEG_100BASE_T4
,
416 LLDP_DOT3_LINK_AUTONEG_100BASE_T4
, "100Base-T4");
417 display_autoneg(w
, autoneg_advertised
,
418 LLDP_DOT3_LINK_AUTONEG_1000BASE_X
,
419 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD
, "1000Base-X");
420 display_autoneg(w
, autoneg_advertised
,
421 LLDP_DOT3_LINK_AUTONEG_1000BASE_T
,
422 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
, "1000Base-T");
424 tag_datatag(w
, "current", "MAU oper type",
425 lldpctl_atom_get_str(port
, lldpctl_k_port_dot3_mautype
));
429 lldpctl_atom_t
*dot3_power
=
430 lldpctl_atom_get(port
, lldpctl_k_port_dot3_power
);
432 lldpctl_atom_get_int(dot3_power
, lldpctl_k_dot3_power_devicetype
);
433 if (devicetype
> 0) {
434 tag_start(w
, "power", "MDI Power");
435 tag_attr(w
, "supported", "Supported",
436 (lldpctl_atom_get_int(dot3_power
,
437 lldpctl_k_dot3_power_supported
) > 0) ?
440 tag_attr(w
, "enabled", "Enabled",
441 (lldpctl_atom_get_int(dot3_power
,
442 lldpctl_k_dot3_power_enabled
) > 0) ?
445 tag_attr(w
, "paircontrol", "Pair control",
446 (lldpctl_atom_get_int(dot3_power
,
447 lldpctl_k_dot3_power_paircontrol
) > 0) ?
450 tag_start(w
, "device-type", "Device type");
452 lldpctl_atom_get_str(dot3_power
,
453 lldpctl_k_dot3_power_devicetype
));
456 tag_start(w
, "pairs", "Power pairs");
458 lldpctl_atom_get_str(dot3_power
,
459 lldpctl_k_dot3_power_pairs
));
461 tag_start(w
, "class", "Class");
463 lldpctl_atom_get_str(dot3_power
,
464 lldpctl_k_dot3_power_class
));
468 if (lldpctl_atom_get_int(dot3_power
,
469 lldpctl_k_dot3_power_type
) >
470 LLDP_DOT3_POWER_8023AT_OFF
) {
471 tag_start(w
, "power-type", "Power type");
473 lldpctl_atom_get_str(dot3_power
,
474 lldpctl_k_dot3_power_type
));
477 tag_start(w
, "source", "Power Source");
479 lldpctl_atom_get_str(dot3_power
,
480 lldpctl_k_dot3_power_source
));
483 tag_start(w
, "priority", "Power Priority");
485 lldpctl_atom_get_str(dot3_power
,
486 lldpctl_k_dot3_power_priority
));
489 tag_start(w
, "requested", "PD requested power Value");
491 lldpctl_atom_get_str(dot3_power
,
492 lldpctl_k_dot3_power_requested
));
495 tag_start(w
, "allocated", "PSE allocated power Value");
497 lldpctl_atom_get_str(dot3_power
,
498 lldpctl_k_dot3_power_allocated
));
503 if (lldpctl_atom_get_int(dot3_power
,
504 lldpctl_k_dot3_power_type_ext
) >
505 LLDP_DOT3_POWER_8023BT_OFF
) {
506 tag_start(w
, "requested-a", "Requested mode A");
508 lldpctl_atom_get_str(dot3_power
,
509 lldpctl_k_dot3_power_requested_a
));
511 tag_start(w
, "requested-b", "Requested mode B");
513 lldpctl_atom_get_str(dot3_power
,
514 lldpctl_k_dot3_power_requested_b
));
516 tag_start(w
, "allocated-a", "Allocated alternative A");
518 lldpctl_atom_get_str(dot3_power
,
519 lldpctl_k_dot3_power_allocated_a
));
521 tag_start(w
, "allocated-b", "Allocated alternative B");
523 lldpctl_atom_get_str(dot3_power
,
524 lldpctl_k_dot3_power_allocated_b
));
526 tag_start(w
, "pse-powering-status",
527 "PSE powering status");
529 lldpctl_atom_get_str(dot3_power
,
530 lldpctl_k_dot3_power_pse_status
));
532 tag_start(w
, "pd-powering-status",
533 "PD powering status");
535 lldpctl_atom_get_str(dot3_power
,
536 lldpctl_k_dot3_power_pd_status
));
538 tag_start(w
, "power-pairs-ext", "Power pairs extra");
540 lldpctl_atom_get_str(dot3_power
,
541 lldpctl_k_dot3_power_pse_pairs_ext
));
543 tag_start(w
, "power-class-ext-a", "Class extra A");
545 lldpctl_atom_get_str(dot3_power
,
546 lldpctl_k_dot3_power_class_a
));
548 tag_start(w
, "power-class-ext-b", "Class extra B");
550 lldpctl_atom_get_str(dot3_power
,
551 lldpctl_k_dot3_power_class_b
));
553 tag_start(w
, "power-class-ext", "Class extra");
555 lldpctl_atom_get_str(dot3_power
,
556 lldpctl_k_dot3_power_class_ext
));
558 tag_start(w
, "power-type-ext", "Power type extra");
560 lldpctl_atom_get_str(dot3_power
,
561 lldpctl_k_dot3_power_type_ext
));
563 tag_start(w
, "pd-load", "PD load");
565 lldpctl_atom_get_str(dot3_power
,
566 lldpctl_k_dot3_power_pd_load
));
568 tag_start(w
, "max-power",
569 "PSE maximum available power");
571 lldpctl_atom_get_str(dot3_power
,
572 lldpctl_k_dot3_power_pse_max
));
578 lldpctl_atom_dec_ref(dot3_power
);
585 display_local_ttl(struct writer
*w
, lldpctl_conn_t
*conn
, int details
)
589 long int tx_interval
;
591 lldpctl_atom_t
*configuration
;
592 configuration
= lldpctl_get_configuration(conn
);
593 if (!configuration
) {
594 log_warnx("lldpctl", "not able to get configuration. %s",
595 lldpctl_last_strerror(conn
));
599 tx_hold
= lldpctl_atom_get_int(configuration
, lldpctl_k_config_tx_hold
);
601 lldpctl_atom_get_int(configuration
, lldpctl_k_config_tx_interval_ms
);
603 tx_interval
= MIN((tx_interval
* tx_hold
+ 999) / 1000, 65535);
605 if (asprintf(&ttl
, "%lu", tx_interval
) == -1) {
606 log_warnx("lldpctl", "not enough memory to build TTL.");
610 tag_start(w
, "ttl", "TTL");
611 tag_attr(w
, "ttl", "", ttl
);
615 lldpctl_atom_dec_ref(configuration
);
619 display_vlans(struct writer
*w
, lldpctl_atom_t
*port
)
621 lldpctl_atom_t
*vlans
, *vlan
;
625 pvid
= lldpctl_atom_get_int(port
, lldpctl_k_port_vlan_pvid
);
627 vlans
= lldpctl_atom_get(port
, lldpctl_k_port_vlans
);
628 lldpctl_atom_foreach(vlans
, vlan
)
630 vid
= lldpctl_atom_get_int(vlan
, lldpctl_k_vlan_id
);
632 tag_start(w
, "vlan", "VLAN");
633 tag_attr(w
, "vlan-id", "",
634 lldpctl_atom_get_str(vlan
, lldpctl_k_vlan_id
));
636 tag_attr(w
, "pvid", "pvid", "yes");
639 tag_attr(w
, "pvid", "pvid", "no");
641 tag_data(w
, lldpctl_atom_get_str(vlan
, lldpctl_k_vlan_name
));
644 lldpctl_atom_dec_ref(vlans
);
646 if (!foundpvid
&& pvid
> 0) {
647 tag_start(w
, "vlan", "VLAN");
648 tag_attr(w
, "vlan-id", "",
649 lldpctl_atom_get_str(port
, lldpctl_k_port_vlan_pvid
));
650 tag_attr(w
, "pvid", "pvid", "yes");
656 display_ppvids(struct writer
*w
, lldpctl_atom_t
*port
)
658 lldpctl_atom_t
*ppvids
, *ppvid
;
659 ppvids
= lldpctl_atom_get(port
, lldpctl_k_port_ppvids
);
660 lldpctl_atom_foreach(ppvids
, ppvid
)
662 int status
= lldpctl_atom_get_int(ppvid
, lldpctl_k_ppvid_status
);
663 tag_start(w
, "ppvid", "PPVID");
664 if (lldpctl_atom_get_int(ppvid
, lldpctl_k_ppvid_id
) > 0)
665 tag_attr(w
, "value", "",
666 lldpctl_atom_get_str(ppvid
, lldpctl_k_ppvid_id
));
667 tag_attr(w
, "supported", "supported",
668 (status
& LLDP_PPVID_CAP_SUPPORTED
) ? "yes" : "no");
669 tag_attr(w
, "enabled", "enabled",
670 (status
& LLDP_PPVID_CAP_ENABLED
) ? "yes" : "no");
673 lldpctl_atom_dec_ref(ppvids
);
677 display_pids(struct writer
*w
, lldpctl_atom_t
*port
)
679 lldpctl_atom_t
*pids
, *pid
;
680 pids
= lldpctl_atom_get(port
, lldpctl_k_port_pis
);
681 lldpctl_atom_foreach(pids
, pid
)
683 const char *pi
= lldpctl_atom_get_str(pid
, lldpctl_k_pi_id
);
684 if (pi
&& strlen(pi
) > 0) tag_datatag(w
, "pi", "PI", pi
);
686 lldpctl_atom_dec_ref(pids
);
690 display_age(time_t lastchange
)
692 static char sage
[30];
693 int age
= (int)(time(NULL
) - lastchange
);
694 if (snprintf(sage
, sizeof(sage
), "%d day%s, %02d:%02d:%02d",
695 age
/ (60 * 60 * 24), (age
/ (60 * 60 * 24) > 1) ? "s" : "",
696 (age
/ (60 * 60)) % 24, (age
/ 60) % 60, age
% 60) >= sizeof(sage
))
703 display_local_chassis(lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
,
706 tag_start(w
, "local-chassis", "Local chassis");
708 lldpctl_atom_t
*chassis
= lldpctl_get_local_chassis(conn
);
709 display_chassis(w
, chassis
, details
);
710 if (details
== DISPLAY_DETAILS
) {
711 display_med(w
, NULL
, chassis
);
713 lldpctl_atom_dec_ref(chassis
);
719 display_interface(lldpctl_conn_t
*conn
, struct writer
*w
, int hidden
,
720 lldpctl_atom_t
*iface
, lldpctl_atom_t
*port
, int details
, int protocol
)
724 if (!hidden
&& lldpctl_atom_get_int(port
, lldpctl_k_port_hidden
)) return;
726 /* user might have specified protocol to filter on display */
727 if ((protocol
!= LLDPD_MODE_MAX
) &&
728 (protocol
!= lldpctl_atom_get_int(port
, lldpctl_k_port_protocol
)))
731 /* Infer local / remote port from the port index (remote == 0) */
732 local
= lldpctl_atom_get_int(port
, lldpctl_k_port_index
) > 0 ? 1 : 0;
734 lldpctl_atom_t
*chassis
= lldpctl_atom_get(port
, lldpctl_k_port_chassis
);
736 tag_start(w
, "interface", "Interface");
737 tag_attr(w
, "name", "", lldpctl_atom_get_str(iface
, lldpctl_k_interface_name
));
739 tag_attr(w
, "via", "via",
740 lldpctl_atom_get_str(port
, lldpctl_k_port_protocol
));
741 if (details
> DISPLAY_BRIEF
) {
742 tag_attr(w
, "rid", "RID",
743 lldpctl_atom_get_str(chassis
, lldpctl_k_chassis_index
));
744 tag_attr(w
, "age", "Time",
746 lldpctl_atom_get_int(port
, lldpctl_k_port_age
)));
749 tag_datatag(w
, "status", "Administrative status",
750 lldpctl_atom_get_str(port
, lldpctl_k_port_status
));
753 display_chassis(w
, chassis
, details
);
754 display_port(w
, port
, details
);
755 if (details
&& local
&& conn
) display_local_ttl(w
, conn
, details
);
756 if (details
== DISPLAY_DETAILS
) {
757 display_vlans(w
, port
);
758 display_ppvids(w
, port
);
759 display_pids(w
, port
);
760 display_med(w
, port
, chassis
);
763 lldpctl_atom_dec_ref(chassis
);
765 display_custom_tlvs(w
, port
);
771 * Display information about interfaces.
773 * @param conn Connection to lldpd.
775 * @param env Environment from which we may find the list of ports.
776 * @param hidden Whatever to show hidden ports.
777 * @param details Level of details we need (DISPLAY_*).
780 display_interfaces(lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
,
781 int hidden
, int details
)
783 lldpctl_atom_t
*iface
;
784 int protocol
= LLDPD_MODE_MAX
;
785 const char *proto_str
;
787 /* user might have specified protocol to filter display results */
788 proto_str
= cmdenv_get(env
, "protocol");
791 log_debug("display", "filter protocol: %s ", proto_str
);
794 for (lldpctl_map_t
*protocol_map
=
795 lldpctl_key_get_map(lldpctl_k_port_protocol
);
796 protocol_map
->string
; protocol_map
++) {
797 if (!strcasecmp(proto_str
, protocol_map
->string
)) {
798 protocol
= protocol_map
->value
;
804 tag_start(w
, "lldp", "LLDP neighbors");
805 while ((iface
= cmd_iterate_on_interfaces(conn
, env
))) {
806 lldpctl_atom_t
*port
;
807 lldpctl_atom_t
*neighbors
;
808 lldpctl_atom_t
*neighbor
;
809 port
= lldpctl_get_port(iface
);
810 neighbors
= lldpctl_atom_get(port
, lldpctl_k_port_neighbors
);
811 lldpctl_atom_foreach(neighbors
, neighbor
)
813 display_interface(conn
, w
, hidden
, iface
, neighbor
, details
,
816 lldpctl_atom_dec_ref(neighbors
);
817 lldpctl_atom_dec_ref(port
);
823 * Display information about local interfaces.
825 * @param conn Connection to lldpd.
827 * @param hidden Whatever to show hidden ports.
828 * @param env Environment from which we may find the list of ports.
829 * @param details Level of details we need (DISPLAY_*).
832 display_local_interfaces(lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
,
833 int hidden
, int details
)
835 lldpctl_atom_t
*iface
;
836 int protocol
= LLDPD_MODE_MAX
;
838 tag_start(w
, "lldp", "LLDP interfaces");
839 while ((iface
= cmd_iterate_on_interfaces(conn
, env
))) {
840 lldpctl_atom_t
*port
;
841 port
= lldpctl_get_port(iface
);
842 display_interface(conn
, w
, hidden
, iface
, port
, details
, protocol
);
843 lldpctl_atom_dec_ref(port
);
849 display_stat(struct writer
*w
, const char *tag
, const char *descr
,
850 long unsigned int cnt
)
854 tag_start(w
, tag
, descr
);
855 snprintf(buf
, sizeof(buf
), "%lu", cnt
);
856 tag_attr(w
, tag
, "", buf
);
861 display_interface_stats(lldpctl_conn_t
*conn
, struct writer
*w
, lldpctl_atom_t
*port
)
863 tag_start(w
, "interface", "Interface");
864 tag_attr(w
, "name", "", lldpctl_atom_get_str(port
, lldpctl_k_port_name
));
866 display_stat(w
, "tx", "Transmitted",
867 lldpctl_atom_get_int(port
, lldpctl_k_tx_cnt
));
868 display_stat(w
, "rx", "Received", lldpctl_atom_get_int(port
, lldpctl_k_rx_cnt
));
870 display_stat(w
, "rx_discarded_cnt", "Discarded",
871 lldpctl_atom_get_int(port
, lldpctl_k_rx_discarded_cnt
));
873 display_stat(w
, "rx_unrecognized_cnt", "Unrecognized",
874 lldpctl_atom_get_int(port
, lldpctl_k_rx_unrecognized_cnt
));
876 display_stat(w
, "ageout_cnt", "Ageout",
877 lldpctl_atom_get_int(port
, lldpctl_k_ageout_cnt
));
879 display_stat(w
, "insert_cnt", "Inserted",
880 lldpctl_atom_get_int(port
, lldpctl_k_insert_cnt
));
882 display_stat(w
, "delete_cnt", "Deleted",
883 lldpctl_atom_get_int(port
, lldpctl_k_delete_cnt
));
889 * Display interface stats
891 * @param conn Connection to lldpd.
893 * @param env Environment from which we may find the list of ports.
896 display_interfaces_stats(lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
)
898 lldpctl_atom_t
*iface
;
900 u_int64_t h_tx_cnt
= 0;
901 u_int64_t h_rx_cnt
= 0;
902 u_int64_t h_rx_discarded_cnt
= 0;
903 u_int64_t h_rx_unrecognized_cnt
= 0;
904 u_int64_t h_ageout_cnt
= 0;
905 u_int64_t h_insert_cnt
= 0;
906 u_int64_t h_delete_cnt
= 0;
908 if (cmdenv_get(env
, "summary")) summary
= 1;
910 tag_start(w
, "lldp", (summary
? "LLDP Global statistics" : "LLDP statistics"));
911 while ((iface
= cmd_iterate_on_interfaces(conn
, env
))) {
912 lldpctl_atom_t
*port
;
913 port
= lldpctl_get_port(iface
);
915 display_interface_stats(conn
, w
, port
);
917 h_tx_cnt
+= lldpctl_atom_get_int(port
, lldpctl_k_tx_cnt
);
918 h_rx_cnt
+= lldpctl_atom_get_int(port
, lldpctl_k_rx_cnt
);
919 h_rx_discarded_cnt
+=
920 lldpctl_atom_get_int(port
, lldpctl_k_rx_discarded_cnt
);
921 h_rx_unrecognized_cnt
+=
922 lldpctl_atom_get_int(port
, lldpctl_k_rx_unrecognized_cnt
);
924 lldpctl_atom_get_int(port
, lldpctl_k_ageout_cnt
);
926 lldpctl_atom_get_int(port
, lldpctl_k_insert_cnt
);
928 lldpctl_atom_get_int(port
, lldpctl_k_delete_cnt
);
930 lldpctl_atom_dec_ref(port
);
934 tag_start(w
, "summary", "Summary of stats");
935 display_stat(w
, "tx", "Transmitted", h_tx_cnt
);
936 display_stat(w
, "rx", "Received", h_rx_cnt
);
937 display_stat(w
, "rx_discarded_cnt", "Discarded", h_rx_discarded_cnt
);
939 display_stat(w
, "rx_unrecognized_cnt", "Unrecognized",
940 h_rx_unrecognized_cnt
);
942 display_stat(w
, "ageout_cnt", "Ageout", h_ageout_cnt
);
944 display_stat(w
, "insert_cnt", "Inserted", h_insert_cnt
);
946 display_stat(w
, "delete_cnt", "Deleted", h_delete_cnt
);
955 if (str
== NULL
|| strlen(str
) == 0) return "(none)";
960 display_configuration(lldpctl_conn_t
*conn
, struct writer
*w
)
962 lldpctl_atom_t
*configuration
;
964 configuration
= lldpctl_get_configuration(conn
);
965 if (!configuration
) {
966 log_warnx("lldpctl", "not able to get configuration. %s",
967 lldpctl_last_strerror(conn
));
971 tag_start(w
, "configuration", "Global configuration");
972 tag_start(w
, "config", "Configuration");
974 tag_datatag(w
, "tx-delay", "Transmit delay",
975 lldpctl_atom_get_str(configuration
, lldpctl_k_config_tx_interval
));
976 tag_datatag(w
, "tx-delay-ms", "Transmit delay in milliseconds",
977 lldpctl_atom_get_str(configuration
, lldpctl_k_config_tx_interval_ms
));
978 tag_datatag(w
, "tx-hold", "Transmit hold",
979 lldpctl_atom_get_str(configuration
, lldpctl_k_config_tx_hold
));
980 tag_datatag(w
, "max-neighbors", "Maximum number of neighbors",
981 lldpctl_atom_get_str(configuration
, lldpctl_k_config_max_neighbors
));
982 tag_datatag(w
, "rx-only", "Receive mode",
983 lldpctl_atom_get_int(configuration
, lldpctl_k_config_receiveonly
) ? "yes" :
985 tag_datatag(w
, "mgmt-pattern", "Pattern for management addresses",
986 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_mgmt_pattern
)));
987 tag_datatag(w
, "iface-pattern", "Interface pattern",
988 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_iface_pattern
)));
989 tag_datatag(w
, "perm-iface-pattern", "Permanent interface pattern",
990 N(lldpctl_atom_get_str(configuration
,
991 lldpctl_k_config_perm_iface_pattern
)));
992 tag_datatag(w
, "cid-pattern", "Interface pattern for chassis ID",
993 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_cid_pattern
)));
994 tag_datatag(w
, "cid-string", "Override chassis ID with",
995 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_cid_string
)));
996 tag_datatag(w
, "description", "Override description with",
997 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_description
)));
998 tag_datatag(w
, "platform", "Override platform with",
999 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_platform
)));
1000 tag_datatag(w
, "hostname", "Override system name with",
1001 N(lldpctl_atom_get_str(configuration
, lldpctl_k_config_hostname
)));
1002 tag_datatag(w
, "capabilities", "Override system capabilities",
1003 lldpctl_atom_get_int(configuration
, lldpctl_k_config_chassis_cap_override
) ?
1006 tag_datatag(w
, "advertise-version", "Advertise version",
1007 lldpctl_atom_get_int(configuration
, lldpctl_k_config_advertise_version
) ?
1010 tag_datatag(w
, "ifdescr-update", "Update interface descriptions",
1011 lldpctl_atom_get_int(configuration
, lldpctl_k_config_ifdescr_update
) ?
1014 tag_datatag(w
, "iface-promisc", "Promiscuous mode on managed interfaces",
1015 lldpctl_atom_get_int(configuration
, lldpctl_k_config_iface_promisc
) ?
1018 tag_datatag(w
, "lldpmed-no-inventory", "Disable LLDP-MED inventory",
1019 (lldpctl_atom_get_int(configuration
,
1020 lldpctl_k_config_lldpmed_noinventory
) == 0) ?
1023 tag_datatag(w
, "lldpmed-faststart", "LLDP-MED fast start mechanism",
1024 (lldpctl_atom_get_int(configuration
, lldpctl_k_config_fast_start_enabled
) ==
1028 tag_datatag(w
, "lldpmed-faststart-interval", "LLDP-MED fast start interval",
1029 N(lldpctl_atom_get_str(configuration
,
1030 lldpctl_k_config_fast_start_interval
)));
1031 tag_datatag(w
, "bond-slave-src-mac-type",
1032 "Source MAC for LLDP frames on bond slaves",
1033 lldpctl_atom_get_str(configuration
,
1034 lldpctl_k_config_bond_slave_src_mac_type
));
1035 tag_datatag(w
, "lldp-portid-type", "Port ID TLV subtype for LLDP frames",
1036 lldpctl_atom_get_str(configuration
, lldpctl_k_config_lldp_portid_type
));
1037 tag_datatag(w
, "lldp-agent-type", "Agent type",
1038 lldpctl_atom_get_str(configuration
, lldpctl_k_config_lldp_agent_type
));
1043 lldpctl_atom_dec_ref(configuration
);