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/types.h>
25 #include <sys/socket.h>
27 #include <arpa/inet.h>
33 display_cap(struct writer
* w
, lldpctl_atom_t
*chassis
, u_int8_t bit
, char *symbol
)
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
)?
46 display_med_capability(struct writer
*w
, long int available
, int cap
,
49 if (available
& cap
) {
50 tag_start(w
, "capability", "Capability");
51 tag_attr(w
, "type", "", symbol
);
57 totag(const char *value
)
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
++) {
67 case ' ': result
[i
] = '-'; break;
68 default: result
[i
] = tolower(value
[i
]); break;
75 display_med(struct writer
*w
, lldpctl_atom_t
*port
)
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
);
83 if (lldpctl_atom_get_int(port
, lldpctl_k_chassis_med_type
) <= 0)
86 tag_start(w
, "lldp-med", "LLDP-MED");
88 tag_datatag(w
, "device-type", "Device Type",
89 lldpctl_atom_get_str(port
, lldpctl_k_chassis_med_type
));
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");
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;
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");
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");
116 tag_attr(w
, "vid", "", "priority");
117 } else if (vid
== 4095) {
118 tag_attr(w
, "vid", "", "reserved");
120 tag_attr(w
, "vid", "",
121 lldpctl_atom_get_str(medpolicy
,
122 lldpctl_k_med_policy_vid
));
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
));
136 lldpctl_atom_dec_ref(medpolicies
);
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
));
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
));
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
));
180 lldpctl_atom_dec_ref(caelements
);
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
));
191 lldpctl_atom_dec_ref(medlocations
);
194 if (lldpctl_atom_get_int(port
, lldpctl_k_med_power_type
) > 0) {
195 tag_start(w
, "poe", "Extended Power-over-Ethernet");
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
));
207 /* LLDP MED inventory */
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;
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
* neighbor
)
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(neighbor
,
249 lldpctl_k_chassis_id_subtype
));
250 tag_data(w
, lldpctl_atom_get_str(neighbor
,
251 lldpctl_k_chassis_id
));
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
));
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
));
264 lldpctl_atom_dec_ref(mgmts
);
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");
280 display_autoneg(struct writer
* w
, int advertised
, int bithd
, int bitfd
, char *desc
)
282 if (!((advertised
& bithd
) ||
283 (advertised
& bitfd
)))
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");
294 display_port(struct writer
*w
, lldpctl_atom_t
*port
)
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
));
303 tag_datatag(w
, "descr", "PortDescr",
304 lldpctl_atom_get_str(port
, lldpctl_k_port_descr
));
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
));
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");
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
,
334 display_autoneg(w
, autoneg_advertised
,
335 LLDP_DOT3_LINK_AUTONEG_100BASE_TX
,
336 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
,
338 display_autoneg(w
, autoneg_advertised
,
339 LLDP_DOT3_LINK_AUTONEG_100BASE_T2
,
340 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD
,
342 display_autoneg(w
, autoneg_advertised
,
343 LLDP_DOT3_LINK_AUTONEG_1000BASE_X
,
344 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD
,
346 display_autoneg(w
, autoneg_advertised
,
347 LLDP_DOT3_LINK_AUTONEG_1000BASE_T
,
348 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
,
351 tag_datatag(w
, "current", "MAU oper type",
352 lldpctl_atom_get_str(port
, lldpctl_k_port_dot3_mautype
));
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
));;
377 tag_start(w
, "pairs", "Power pairs");
378 tag_data(w
, lldpctl_atom_get_str(dot3_power
,
379 lldpctl_k_dot3_power_pairs
));
381 tag_start(w
, "class", "Class");
382 tag_data(w
, lldpctl_atom_get_str(dot3_power
,
383 lldpctl_k_dot3_power_class
));
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
));
394 tag_start(w
, "source", "Power Source");
395 tag_data(w
, lldpctl_atom_get_str(dot3_power
,
396 lldpctl_k_dot3_power_source
));
399 tag_start(w
, "priority", "Power Priority");
400 tag_data(w
, lldpctl_atom_get_str(dot3_power
,
401 lldpctl_k_dot3_power_priority
));
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
));
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
));
417 lldpctl_atom_dec_ref(dot3_power
);
424 display_vlans(struct writer
*w
, lldpctl_atom_t
*port
)
426 lldpctl_atom_t
*vlans
, *vlan
;
430 pvid
= lldpctl_atom_get_int(port
,
431 lldpctl_k_port_vlan_pvid
);
433 vlans
= lldpctl_atom_get(port
, lldpctl_k_port_vlans
);
434 lldpctl_atom_foreach(vlans
, vlan
) {
435 vid
= lldpctl_atom_get_int(vlan
,
440 tag_start(w
, "vlan", "VLAN");
441 tag_attr(w
, "vlan-id", "",
442 lldpctl_atom_get_str(vlan
, lldpctl_k_vlan_id
));
444 tag_attr(w
, "pvid", "pvid", "yes");
445 tag_data(w
, lldpctl_atom_get_str(vlan
,
446 lldpctl_k_vlan_name
));
449 lldpctl_atom_dec_ref(vlans
);
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");
462 display_ppvids(struct writer
*w
, lldpctl_atom_t
*port
)
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");
481 lldpctl_atom_dec_ref(ppvids
);
485 display_pids(struct writer
*w
, lldpctl_atom_t
*port
)
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
);
494 lldpctl_atom_dec_ref(pids
);
498 display_age(time_t lastchange
)
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",
505 (age
/ (60*60*24) > 1)?"s":"",
506 (age
/ (60*60)) % 24,
508 age
% 60) >= sizeof(sage
))
515 display_interfaces(lldpctl_conn_t
*conn
, const char *fmt
, int hidden
,
516 int argc
, char *argv
[])
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
;
526 iface_list
= lldpctl_get_interfaces(conn
);
528 LLOG_WARNX("not able to get the list of interfaces: %s", lldpctl_strerror(lldpctl_last_error(conn
)));
532 if (strcmp(fmt
, "plain") == 0) {
533 w
= txt_init(stdout
);
534 } else if (strcmp(fmt
, "keyvalue") == 0) {
538 else if (strcmp(fmt
,"xml") == 0 ) {
539 w
= xml_init(stdout
);
543 w
= txt_init(stdout
);
546 tag_start(w
, "lldp", "LLDP neighbors");
547 lldpctl_atom_foreach(iface_list
, iface
) {
549 for (i
= optind
; i
< argc
; i
++)
551 lldpctl_atom_get_str(iface
,
552 lldpctl_k_interface_name
)) == 0)
557 port
= lldpctl_get_port(iface
);
558 neighbors
= lldpctl_atom_get(port
, lldpctl_k_port_neighbors
);
559 lldpctl_atom_foreach(neighbors
, neighbor
) {
561 lldpctl_atom_get_int(neighbor
, lldpctl_k_port_hidden
))
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
)));
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
);
583 lldpctl_atom_dec_ref(neighbors
);
584 lldpctl_atom_dec_ref(port
);
586 lldpctl_atom_dec_ref(iface_list
);