]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/client/display.c
client: don't display management interface index if unknown
[thirdparty/lldpd.git] / src / client / display.c
CommitLineData
4b292b55
VB
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>
4e5f34c5 28#include <string.h>
4b292b55
VB
29
30#include "../log.h"
31#include "client.h"
32
33static void
34display_cap(struct writer * w, lldpctl_atom_t *chassis, u_int8_t bit, char *symbol)
35{
36 if (lldpctl_atom_get_int(chassis, lldpctl_k_chassis_cap_available) & bit) {
37 tag_start(w, "capability", "Capability");
38 tag_attr (w, "type", "", symbol );
39 tag_attr (w, "enabled", "",
40 (lldpctl_atom_get_int(chassis, lldpctl_k_chassis_cap_enabled) & bit)?
41 "on":"off");
42 tag_end (w);
43 }
44}
45
46static void
47display_med_capability(struct writer *w, long int available, int cap,
48 const char *symbol)
49{
50 if (available & cap) {
51 tag_start(w, "capability", "Capability");
52 tag_attr(w, "type", "", symbol);
1f8742dd 53 tag_attr(w, "available", "", "yes");
4b292b55
VB
54 tag_end(w);
55 }
56}
57
4b292b55 58static void
9439b950 59display_med(struct writer *w, lldpctl_atom_t *port, lldpctl_atom_t *chassis)
4b292b55
VB
60{
61 lldpctl_atom_t *medpolicies, *medpolicy;
62 lldpctl_atom_t *medlocations, *medlocation;
63 lldpctl_atom_t *caelements, *caelement;
60ad2804 64 lldpctl_atom_t *medpower;
9439b950 65 long int cap = lldpctl_atom_get_int(chassis, lldpctl_k_chassis_med_cap);
4b292b55
VB
66 const char *type;
67
9439b950 68 if (lldpctl_atom_get_int(chassis, lldpctl_k_chassis_med_type) <= 0)
4b292b55
VB
69 return;
70
71 tag_start(w, "lldp-med", "LLDP-MED");
72
73 tag_datatag(w, "device-type", "Device Type",
9439b950 74 lldpctl_atom_get_str(chassis, lldpctl_k_chassis_med_type));
4b292b55
VB
75
76 display_med_capability(w, cap, LLDP_MED_CAP_CAP, "Capabilities");
77 display_med_capability(w, cap, LLDP_MED_CAP_POLICY, "Policy");
78 display_med_capability(w, cap, LLDP_MED_CAP_LOCATION, "Location");
79 display_med_capability(w, cap, LLDP_MED_CAP_MDI_PSE, "MDI/PSE");
80 display_med_capability(w, cap, LLDP_MED_CAP_MDI_PD, "MDI/PD");
81 display_med_capability(w, cap, LLDP_MED_CAP_IV, "Inventory");
82
83 /* LLDP MED policies */
84 medpolicies = lldpctl_atom_get(port, lldpctl_k_port_med_policies);
85 lldpctl_atom_foreach(medpolicies, medpolicy) {
86 if (lldpctl_atom_get_int(medpolicy,
87 lldpctl_k_med_policy_type) <= 0) continue;
88
89 tag_start(w, "policy", "LLDP-MED Network Policy for");
90 tag_attr(w, "apptype", "", lldpctl_atom_get_str(medpolicy, lldpctl_k_med_policy_type));
91 tag_attr(w, "defined", "Defined",
92 (lldpctl_atom_get_int(medpolicy,
93 lldpctl_k_med_policy_unknown) > 0)?"no":"yes");
94
95 if (lldpctl_atom_get_int(medpolicy,
96 lldpctl_k_med_policy_tagged) > 0) {
97 int vid = lldpctl_atom_get_int(medpolicy,
98 lldpctl_k_med_policy_vid);
99 tag_start(w, "vlan", "VLAN");
100 if (vid == 0) {
101 tag_attr(w, "vid", "", "priority");
102 } else if (vid == 4095) {
103 tag_attr(w, "vid", "", "reserved");
104 } else {
105 tag_attr(w, "vid", "",
106 lldpctl_atom_get_str(medpolicy,
107 lldpctl_k_med_policy_vid));
108 }
109 tag_end(w);
110 }
111
112 tag_datatag(w, "priority", "Priority",
113 lldpctl_atom_get_str(medpolicy,
114 lldpctl_k_med_policy_priority));
5b12cbac
VB
115 /* Also give a numeric value */
116 int pcp = lldpctl_atom_get_int(medpolicy,
117 lldpctl_k_med_policy_priority);
118 char spcp[2] = { pcp + '0', '\0' };
119 tag_datatag(w, "pcp", "PCP", spcp);
4b292b55
VB
120 tag_datatag(w, "dscp", "DSCP Value",
121 lldpctl_atom_get_str(medpolicy,
122 lldpctl_k_med_policy_dscp));
123
124 tag_end(w);
125 }
126 lldpctl_atom_dec_ref(medpolicies);
127
128 /* LLDP MED locations */
129 medlocations = lldpctl_atom_get(port, lldpctl_k_port_med_locations);
130 lldpctl_atom_foreach(medlocations, medlocation) {
131 int format = lldpctl_atom_get_int(medlocation,
132 lldpctl_k_med_location_format);
133 if (format <= 0) continue;
134 tag_start(w, "location", "LLDP-MED Location Identification");
135 tag_attr(w, "type", "Type",
136 lldpctl_atom_get_str(medlocation,
137 lldpctl_k_med_location_format));
138
139 switch (format) {
140 case LLDP_MED_LOCFORMAT_COORD:
141 tag_attr(w, "geoid", "Geoid",
142 lldpctl_atom_get_str(medlocation,
143 lldpctl_k_med_location_geoid));
144 tag_datatag(w, "lat", "Latitude",
145 lldpctl_atom_get_str(medlocation,
146 lldpctl_k_med_location_latitude));
147 tag_datatag(w, "lon", "Longitude",
148 lldpctl_atom_get_str(medlocation,
149 lldpctl_k_med_location_longitude));
150 tag_start(w, "altitude", "Altitude");
151 tag_attr(w, "unit", "", lldpctl_atom_get_str(medlocation,
152 lldpctl_k_med_location_altitude_unit));
153 tag_data(w, lldpctl_atom_get_str(medlocation,
154 lldpctl_k_med_location_altitude));
155 tag_end(w);
156 break;
157 case LLDP_MED_LOCFORMAT_CIVIC:
158 tag_datatag(w, "country", "Country",
159 lldpctl_atom_get_str(medlocation,
160 lldpctl_k_med_location_country));
161 caelements = lldpctl_atom_get(medlocation,
162 lldpctl_k_med_location_ca_elements);
163 lldpctl_atom_foreach(caelements, caelement) {
164 type = lldpctl_atom_get_str(caelement,
165 lldpctl_k_med_civicaddress_type);
166 tag_datatag(w, totag(type), type,
167 lldpctl_atom_get_str(caelement,
168 lldpctl_k_med_civicaddress_value));
169 }
170 lldpctl_atom_dec_ref(caelements);
171 break;
172 case LLDP_MED_LOCFORMAT_ELIN:
173 tag_datatag(w, "ecs", "ECS ELIN",
174 lldpctl_atom_get_str(medlocation,
175 lldpctl_k_med_location_elin));
176 break;
177 }
178
179 tag_end(w);
180 }
181 lldpctl_atom_dec_ref(medlocations);
182
183 /* LLDP MED power */
60ad2804
VB
184 medpower = lldpctl_atom_get(port, lldpctl_k_port_med_power);
185 if (lldpctl_atom_get_int(medpower, lldpctl_k_med_power_type) > 0) {
4b292b55
VB
186 tag_start(w, "poe", "Extended Power-over-Ethernet");
187
188 tag_datatag(w, "device-type", "Power Type & Source",
60ad2804 189 lldpctl_atom_get_str(medpower, lldpctl_k_med_power_type));
4b292b55 190 tag_datatag(w, "source", "Power Source",
60ad2804 191 lldpctl_atom_get_str(medpower, lldpctl_k_med_power_source));
4b292b55 192 tag_datatag(w, "priority", "Power priority",
60ad2804 193 lldpctl_atom_get_str(medpower, lldpctl_k_med_power_priority));
4b292b55 194 tag_datatag(w, "power", "Power Value",
60ad2804
VB
195 lldpctl_atom_get_str(medpower, lldpctl_k_med_power_val));
196
197 tag_end(w);
4b292b55 198 }
60ad2804 199 lldpctl_atom_dec_ref(medpower);
4b292b55
VB
200
201 /* LLDP MED inventory */
202 do {
9439b950 203 const char *hw = lldpctl_atom_get_str(chassis,
4b292b55 204 lldpctl_k_chassis_med_inventory_hw);
9439b950 205 const char *sw = lldpctl_atom_get_str(chassis,
4b292b55 206 lldpctl_k_chassis_med_inventory_sw);
9439b950 207 const char *fw = lldpctl_atom_get_str(chassis,
4b292b55 208 lldpctl_k_chassis_med_inventory_fw);
9439b950 209 const char *sn = lldpctl_atom_get_str(chassis,
4b292b55 210 lldpctl_k_chassis_med_inventory_sn);
9439b950 211 const char *manuf = lldpctl_atom_get_str(chassis,
4b292b55 212 lldpctl_k_chassis_med_inventory_manuf);
9439b950 213 const char *model = lldpctl_atom_get_str(chassis,
4b292b55 214 lldpctl_k_chassis_med_inventory_model);
9439b950 215 const char *asset = lldpctl_atom_get_str(chassis,
4b292b55
VB
216 lldpctl_k_chassis_med_inventory_asset);
217 if (!(hw || sw || fw || sn ||
218 manuf || model || asset)) break;
219
220 tag_start(w, "inventory", "Inventory");
221 tag_datatag(w, "hardware", "Hardware Revision", hw);
222 tag_datatag(w, "software", "Software Revision", sw);
223 tag_datatag(w, "firmware", "Firmware Revision", fw);
224 tag_datatag(w, "serial", "Serial Number", sn);
225 tag_datatag(w, "manufacturer", "Manufacturer", manuf);
226 tag_datatag(w, "model", "Model", model);
227 tag_datatag(w, "asset", "Asset ID", asset);
228 tag_end(w);
229 } while(0);
230
231 tag_end(w);
232}
233
234static void
9439b950 235display_chassis(struct writer* w, lldpctl_atom_t* chassis, int details)
4b292b55
VB
236{
237 lldpctl_atom_t *mgmts, *mgmt;
238
239 tag_start(w, "chassis", "Chassis");
240 tag_start(w, "id", "ChassisID");
241 tag_attr (w, "type", "",
9439b950 242 lldpctl_atom_get_str(chassis,
4b292b55 243 lldpctl_k_chassis_id_subtype));
9439b950 244 tag_data(w, lldpctl_atom_get_str(chassis,
4b292b55
VB
245 lldpctl_k_chassis_id));
246 tag_end(w);
247 tag_datatag(w, "name", "SysName",
9439b950 248 lldpctl_atom_get_str(chassis, lldpctl_k_chassis_name));
9a775667
VB
249 if (details == DISPLAY_BRIEF) {
250 tag_end(w);
251 return;
252 }
4b292b55 253 tag_datatag(w, "descr", "SysDescr",
9439b950 254 lldpctl_atom_get_str(chassis, lldpctl_k_chassis_descr));
4b292b55
VB
255
256 /* Management addresses */
9439b950 257 mgmts = lldpctl_atom_get(chassis, lldpctl_k_chassis_mgmt);
4b292b55
VB
258 lldpctl_atom_foreach(mgmts, mgmt) {
259 tag_datatag(w, "mgmt-ip", "MgmtIP",
260 lldpctl_atom_get_str(mgmt, lldpctl_k_mgmt_ip));
30fca74b
VB
261 if (lldpctl_atom_get_int(mgmt, lldpctl_k_mgmt_iface_index))
262 tag_datatag(w, "mgmt-iface", "MgmtIface",
263 lldpctl_atom_get_str(mgmt, lldpctl_k_mgmt_iface_index));
4b292b55
VB
264 }
265 lldpctl_atom_dec_ref(mgmts);
266
267 /* Capabilities */
9439b950
VB
268 display_cap(w, chassis, LLDP_CAP_OTHER, "Other");
269 display_cap(w, chassis, LLDP_CAP_REPEATER, "Repeater");
270 display_cap(w, chassis, LLDP_CAP_BRIDGE, "Bridge");
271 display_cap(w, chassis, LLDP_CAP_ROUTER, "Router");
272 display_cap(w, chassis, LLDP_CAP_WLAN, "Wlan");
273 display_cap(w, chassis, LLDP_CAP_TELEPHONE, "Tel");
274 display_cap(w, chassis, LLDP_CAP_DOCSIS, "Docsis");
275 display_cap(w, chassis, LLDP_CAP_STATION, "Station");
4b292b55
VB
276
277 tag_end(w);
278}
279
26331a26 280static void
7830ff30 281display_custom_tlvs(struct writer* w, lldpctl_atom_t* neighbor)
26331a26
AA
282{
283 lldpctl_atom_t *custom_list, *custom;
284 int have_custom_tlvs = 0;
285 size_t i, len, slen;
286 const uint8_t *oui, *oui_info;
287 char buf[1600]; /* should be enough for printing */
288
289 custom_list = lldpctl_atom_get(neighbor, lldpctl_k_custom_tlvs);
290 lldpctl_atom_foreach(custom_list, custom) {
291 /* This tag gets added only once, if there are any custom TLVs */
292 if (!have_custom_tlvs) {
877f7db8 293 tag_start(w, "unknown-tlvs", "Unknown TLVs");
26331a26
AA
294 have_custom_tlvs++;
295 }
296 len = 0;
297 oui = lldpctl_atom_get_buffer(custom, lldpctl_k_custom_tlv_oui, &len);
298 len = 0;
299 oui_info = lldpctl_atom_get_buffer(custom, lldpctl_k_custom_tlv_oui_info_string, &len);
300 if (!oui)
301 continue;
302 tag_start(w, "unknown-tlv", "TLV");
303
304 /* Add OUI as attribute */
305 snprintf(buf, sizeof(buf), "%02X,%02X,%02X", oui[0], oui[1], oui[2]);
306 tag_attr(w, "oui", "OUI", buf);
307 snprintf(buf, sizeof(buf), "%d",
308 (int)lldpctl_atom_get_int(custom, lldpctl_k_custom_tlv_oui_subtype));
309 tag_attr(w, "subtype", "SubType", buf);
310 snprintf(buf, sizeof(buf), "%d", (int)len);
311 tag_attr(w, "len", "Len", buf);
312 if (len > 0) {
313 for (slen=0, i=0; i < len; ++i)
314 slen += snprintf(buf + slen, sizeof(buf) > slen ? sizeof(buf) - slen : 0,
315 "%02X%s", oui_info[i], ((i < len - 1) ? "," : ""));
316 tag_data(w, buf);
317 }
318 tag_end(w);
319 }
320 lldpctl_atom_dec_ref(custom_list);
321
322 if (have_custom_tlvs)
323 tag_end(w);
324}
325
326
4b292b55
VB
327static void
328display_autoneg(struct writer * w, int advertised, int bithd, int bitfd, char *desc)
329{
330 if (!((advertised & bithd) ||
331 (advertised & bitfd)))
332 return;
333
334 tag_start(w, "advertised", "Adv");
335 tag_attr(w, "type", "", desc);
20264473
VB
336 if (bitfd != bithd) {
337 tag_attr(w, "hd", "HD", (advertised & bithd)?"yes":"no");
338 tag_attr(w, "fd", "FD", (advertised & bitfd)?"yes":"no");
339 }
4b292b55
VB
340 tag_end (w);
341}
342
343static void
9a775667 344display_port(struct writer *w, lldpctl_atom_t *port, int details)
4b292b55
VB
345{
346 tag_start(w, "port", "Port");
347 tag_start(w, "id", "PortID");
348 tag_attr (w, "type", "",
349 lldpctl_atom_get_str(port, lldpctl_k_port_id_subtype));
350 tag_data(w, lldpctl_atom_get_str(port, lldpctl_k_port_id));
351 tag_end(w);
352
353 tag_datatag(w, "descr", "PortDescr",
354 lldpctl_atom_get_str(port, lldpctl_k_port_descr));
a54f6012
SW
355 if (details &&
356 lldpctl_atom_get_int(port, lldpctl_k_port_ttl) > 0)
78346c89
VB
357 tag_datatag(w, "ttl", "TTL",
358 lldpctl_atom_get_str(port, lldpctl_k_port_ttl));
4b292b55
VB
359
360 /* Dot3 */
9a775667
VB
361 if (details == DISPLAY_DETAILS) {
362 tag_datatag(w, "mfs", "MFS",
363 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_mfs));
a519a7e4 364 tag_datatag(w, "aggregation", "Port is aggregated. PortAggregID",
9a775667 365 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_aggregid));
4b292b55 366
72cf4bba 367 long int autoneg_support, autoneg_enabled, autoneg_advertised, mautype;
4b292b55
VB
368 autoneg_support = lldpctl_atom_get_int(port,
369 lldpctl_k_port_dot3_autoneg_support);
370 autoneg_enabled = lldpctl_atom_get_int(port,
371 lldpctl_k_port_dot3_autoneg_enabled);
372 autoneg_advertised = lldpctl_atom_get_int(port,
373 lldpctl_k_port_dot3_autoneg_advertised);
72cf4bba
VB
374 mautype = lldpctl_atom_get_int(port, lldpctl_k_port_dot3_mautype);
375 if (autoneg_support > 0 || autoneg_enabled > 0 || mautype > 0) {
4b292b55
VB
376 tag_start(w, "auto-negotiation", "PMD autoneg");
377 tag_attr (w, "supported", "supported",
378 (autoneg_support > 0)?"yes":"no");
379 tag_attr (w, "enabled", "enabled",
380 (autoneg_enabled > 0)?"yes":"no");
381
382 if (autoneg_enabled > 0) {
383 if (autoneg_advertised < 0)
384 autoneg_advertised = 0;
385 display_autoneg(w, autoneg_advertised,
386 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
387 LLDP_DOT3_LINK_AUTONEG_10BASET_FD,
388 "10Base-T");
389 display_autoneg(w, autoneg_advertised,
390 LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
391 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD,
20264473 392 "100Base-TX");
4b292b55
VB
393 display_autoneg(w, autoneg_advertised,
394 LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
395 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD,
396 "100Base-T2");
20264473
VB
397 display_autoneg(w, autoneg_advertised,
398 LLDP_DOT3_LINK_AUTONEG_100BASE_T4,
399 LLDP_DOT3_LINK_AUTONEG_100BASE_T4,
400 "100Base-T4");
4b292b55
VB
401 display_autoneg(w, autoneg_advertised,
402 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
403 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD,
20264473 404 "1000Base-X");
4b292b55
VB
405 display_autoneg(w, autoneg_advertised,
406 LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
407 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD,
408 "1000Base-T");
409 }
410 tag_datatag(w, "current", "MAU oper type",
411 lldpctl_atom_get_str(port, lldpctl_k_port_dot3_mautype));
412 tag_end(w);
413 }
4b292b55 414
4b292b55
VB
415 lldpctl_atom_t *dot3_power = lldpctl_atom_get(port,
416 lldpctl_k_port_dot3_power);
417 int devicetype = lldpctl_atom_get_int(dot3_power,
418 lldpctl_k_dot3_power_devicetype);
419 if (devicetype > 0) {
420 tag_start(w, "power", "MDI Power");
421 tag_attr(w, "supported", "supported",
422 (lldpctl_atom_get_int(dot3_power,
423 lldpctl_k_dot3_power_supported) > 0)?"yes":"no");
424 tag_attr(w, "enabled", "enabled",
425 (lldpctl_atom_get_int(dot3_power,
426 lldpctl_k_dot3_power_enabled) > 0)?"yes":"no");
427 tag_attr(w, "paircontrol", "pair control",
428 (lldpctl_atom_get_int(dot3_power,
429 lldpctl_k_dot3_power_paircontrol) > 0)?"yes":"no");
430 tag_start(w, "device-type", "Device type");
431 tag_data(w, lldpctl_atom_get_str(dot3_power,
432 lldpctl_k_dot3_power_devicetype));;
433 tag_end(w);
434 tag_start(w, "pairs", "Power pairs");
435 tag_data(w, lldpctl_atom_get_str(dot3_power,
436 lldpctl_k_dot3_power_pairs));
437 tag_end(w);
438 tag_start(w, "class", "Class");
439 tag_data(w, lldpctl_atom_get_str(dot3_power,
440 lldpctl_k_dot3_power_class));
441 tag_end(w);
442
443 /* 802.3at */
444 if (lldpctl_atom_get_int(dot3_power,
445 lldpctl_k_dot3_power_type) > LLDP_DOT3_POWER_8023AT_OFF) {
446 tag_start(w, "power-type", "Power type");
447 tag_data(w, lldpctl_atom_get_str(dot3_power,
448 lldpctl_k_dot3_power_type));
449 tag_end(w);
450
451 tag_start(w, "source", "Power Source");
452 tag_data(w, lldpctl_atom_get_str(dot3_power,
453 lldpctl_k_dot3_power_source));
454 tag_end(w);
455
456 tag_start(w, "priority", "Power Priority");
457 tag_data(w, lldpctl_atom_get_str(dot3_power,
458 lldpctl_k_dot3_power_priority));
459 tag_end(w);
460
461 tag_start(w, "requested", "PD requested power Value");
462 tag_data(w, lldpctl_atom_get_str(dot3_power,
463 lldpctl_k_dot3_power_requested));
464 tag_end(w);
465
466 tag_start(w, "allocated", "PSE allocated power Value");
467 tag_data(w, lldpctl_atom_get_str(dot3_power,
468 lldpctl_k_dot3_power_allocated));
469 tag_end(w);
470 }
471
472 tag_end(w);
473 }
474 lldpctl_atom_dec_ref(dot3_power);
9a775667 475 }
4b292b55
VB
476
477 tag_end(w);
478}
479
a54f6012
SW
480static void
481display_local_ttl(struct writer *w, lldpctl_conn_t *conn, int details)
482{
483 char *ttl;
484 long int tx_hold;
485 long int tx_interval;
486
487 lldpctl_atom_t *configuration;
488 configuration = lldpctl_get_configuration(conn);
489 if (!configuration) {
490 log_warnx("lldpctl", "not able to get configuration. %s",
491 lldpctl_last_strerror(conn));
492 return;
493 }
494
495 tx_hold = lldpctl_atom_get_int(configuration, lldpctl_k_config_tx_hold);
496 tx_interval = lldpctl_atom_get_int(configuration, lldpctl_k_config_tx_interval);
497
498 if (asprintf(&ttl, "%lu", tx_hold*tx_interval) == -1) {
499 log_warnx("lldpctl", "not enough memory to build TTL.");
500 goto end;
501 }
502
503 tag_start(w, "ttl", "TTL");
504 tag_attr(w, "ttl", "", ttl);
505 tag_end(w);
506 free(ttl);
507end:
508 lldpctl_atom_dec_ref(configuration);
a54f6012
SW
509}
510
4b292b55
VB
511static void
512display_vlans(struct writer *w, lldpctl_atom_t *port)
513{
514 lldpctl_atom_t *vlans, *vlan;
515 int foundpvid = 0;
516 int pvid, vid;
517
518 pvid = lldpctl_atom_get_int(port,
519 lldpctl_k_port_vlan_pvid);
520
521 vlans = lldpctl_atom_get(port, lldpctl_k_port_vlans);
522 lldpctl_atom_foreach(vlans, vlan) {
523 vid = lldpctl_atom_get_int(vlan,
524 lldpctl_k_vlan_id);
525 if (pvid == vid)
526 foundpvid = 1;
527
528 tag_start(w, "vlan", "VLAN");
529 tag_attr(w, "vlan-id", "",
530 lldpctl_atom_get_str(vlan, lldpctl_k_vlan_id));
531 if (pvid == vid)
532 tag_attr(w, "pvid", "pvid", "yes");
533 tag_data(w, lldpctl_atom_get_str(vlan,
534 lldpctl_k_vlan_name));
535 tag_end(w);
536 }
537 lldpctl_atom_dec_ref(vlans);
538
539 if (!foundpvid && pvid > 0) {
540 tag_start(w, "vlan", "VLAN");
541 tag_attr(w, "vlan-id", "",
542 lldpctl_atom_get_str(port,
543 lldpctl_k_port_vlan_pvid));
544 tag_attr(w, "pvid", "pvid", "yes");
545 tag_end(w);
546 }
547}
548
549static void
550display_ppvids(struct writer *w, lldpctl_atom_t *port)
551{
552 lldpctl_atom_t *ppvids, *ppvid;
553 ppvids = lldpctl_atom_get(port, lldpctl_k_port_ppvids);
554 lldpctl_atom_foreach(ppvids, ppvid) {
555 int status = lldpctl_atom_get_int(ppvid,
556 lldpctl_k_ppvid_status);
557 tag_start(w, "ppvid", "PPVID");
558 if (lldpctl_atom_get_int(ppvid,
559 lldpctl_k_ppvid_id) > 0)
560 tag_attr(w, "value", "",
561 lldpctl_atom_get_str(ppvid,
562 lldpctl_k_ppvid_id));
563 tag_attr(w, "supported", "supported",
564 (status & LLDP_PPVID_CAP_SUPPORTED)?"yes":"no");
565 tag_attr(w, "enabled", "enabled",
566 (status & LLDP_PPVID_CAP_ENABLED)?"yes":"no");
567 tag_end(w);
568 }
569 lldpctl_atom_dec_ref(ppvids);
570}
571
572static void
573display_pids(struct writer *w, lldpctl_atom_t *port)
574{
575 lldpctl_atom_t *pids, *pid;
576 pids = lldpctl_atom_get(port, lldpctl_k_port_pis);
577 lldpctl_atom_foreach(pids, pid) {
578 const char *pi = lldpctl_atom_get_str(pid, lldpctl_k_pi_id);
579 if (pi && strlen(pi) > 0)
580 tag_datatag(w, "pi", "PI", pi);
581 }
582 lldpctl_atom_dec_ref(pids);
583}
584
585static const char*
586display_age(time_t lastchange)
587{
588 static char sage[30];
589 int age = (int)(time(NULL) - lastchange);
590 if (snprintf(sage, sizeof(sage),
591 "%d day%s, %02d:%02d:%02d",
592 age / (60*60*24),
593 (age / (60*60*24) > 1)?"s":"",
594 (age / (60*60)) % 24,
595 (age / 60) % 60,
596 age % 60) >= sizeof(sage))
597 return "too much";
598 else
599 return sage;
600}
601
3407e638
VB
602void
603display_local_chassis(lldpctl_conn_t *conn, struct writer *w,
604 struct cmd_env *env, int details)
605{
606 tag_start(w, "local-chassis", "Local chassis");
607
608 lldpctl_atom_t *chassis = lldpctl_get_local_chassis(conn);
609 display_chassis(w, chassis, details);
610 if (details == DISPLAY_DETAILS) {
611 display_med(w, NULL, chassis);
612 }
613 lldpctl_atom_dec_ref(chassis);
614
615 tag_end(w);
616}
617
4b292b55 618void
4e90a9e0 619display_interface(lldpctl_conn_t *conn, struct writer *w, int hidden,
a54f6012 620 lldpctl_atom_t *iface, lldpctl_atom_t *port, int details, int protocol)
4e90a9e0 621{
a54f6012
SW
622 int local = 0;
623
4e90a9e0 624 if (!hidden &&
a54f6012 625 lldpctl_atom_get_int(port, lldpctl_k_port_hidden))
4e90a9e0
VB
626 return;
627
494264f0
ST
628 /* user might have specified protocol to filter on display */
629 if ((protocol != LLDPD_MODE_MAX) &&
a54f6012 630 (protocol != lldpctl_atom_get_int(port, lldpctl_k_port_protocol)))
494264f0
ST
631 return;
632
a54f6012
SW
633 /* Infer local / remote port from the port index (remote == 0) */
634 local = lldpctl_atom_get_int(port, lldpctl_k_port_index)>0?1:0;
635
636 lldpctl_atom_t *chassis = lldpctl_atom_get(port, lldpctl_k_port_chassis);
9439b950 637
4e90a9e0
VB
638 tag_start(w, "interface", "Interface");
639 tag_attr(w, "name", "",
640 lldpctl_atom_get_str(iface, lldpctl_k_interface_name));
641 tag_attr(w, "via" , "via",
a54f6012 642 lldpctl_atom_get_str(port, lldpctl_k_port_protocol));
9a775667 643 if (details > DISPLAY_BRIEF) {
a54f6012
SW
644 if (!local)
645 tag_attr(w, "rid" , "RID",
646 lldpctl_atom_get_str(chassis, lldpctl_k_chassis_index));
9a775667 647 tag_attr(w, "age" , "Time",
a54f6012 648 display_age(lldpctl_atom_get_int(port, lldpctl_k_port_age)));
9a775667
VB
649 }
650
9439b950 651 display_chassis(w, chassis, details);
a54f6012
SW
652 display_port(w, port, details);
653 if (details && local)
654 display_local_ttl(w, conn, details);
9a775667 655 if (details == DISPLAY_DETAILS) {
a54f6012
SW
656 display_vlans(w, port);
657 display_ppvids(w, port);
658 display_pids(w, port);
659 display_med(w, port, chassis);
9a775667 660 }
4e90a9e0 661
9439b950
VB
662 lldpctl_atom_dec_ref(chassis);
663
a54f6012 664 display_custom_tlvs(w, port);
26331a26 665
4e90a9e0
VB
666 tag_end(w);
667}
668
9a775667
VB
669/**
670 * Display information about interfaces.
671 *
672 * @param conn Connection to lldpd.
673 * @param w Writer.
674 * @param hidden Whatever to show hidden ports.
9cac8fed 675 * @param env Environment from which we may find the list of ports.
9a775667
VB
676 * @param details Level of details we need (DISPLAY_*).
677 */
4e90a9e0 678void
9a775667
VB
679display_interfaces(lldpctl_conn_t *conn, struct writer *w,
680 struct cmd_env *env,
681 int hidden, int details)
4b292b55 682{
4b292b55 683 lldpctl_atom_t *iface;
494264f0 684 int protocol = LLDPD_MODE_MAX;
7efa65c1 685 const char *proto_str;
494264f0
ST
686
687 /* user might have specified protocol to filter display results */
688 proto_str = cmdenv_get(env, "protocol");
689
690 if (proto_str) {
691 log_debug("display", "filter protocol: %s ", proto_str);
692
7efa65c1
VB
693 protocol = 0;
694 for (lldpctl_map_t *protocol_map =
695 lldpctl_key_get_map(lldpctl_k_port_protocol);
696 protocol_map->string;
697 protocol_map++) {
698 if (!strcasecmp(proto_str, protocol_map->string)) {
699 protocol = protocol_map->value;
700 break;
701 }
494264f0
ST
702 }
703 }
4b292b55 704
4b292b55 705 tag_start(w, "lldp", "LLDP neighbors");
9a775667
VB
706 while ((iface = cmd_iterate_on_interfaces(conn, env))) {
707 lldpctl_atom_t *port;
708 lldpctl_atom_t *neighbors;
709 lldpctl_atom_t *neighbor;
4b292b55
VB
710 port = lldpctl_get_port(iface);
711 neighbors = lldpctl_atom_get(port, lldpctl_k_port_neighbors);
712 lldpctl_atom_foreach(neighbors, neighbor) {
494264f0 713 display_interface(conn, w, hidden, iface, neighbor, details, protocol);
4b292b55
VB
714 }
715 lldpctl_atom_dec_ref(neighbors);
716 lldpctl_atom_dec_ref(port);
717 }
4b292b55 718 tag_end(w);
4b292b55 719}
8729d69f 720
a54f6012
SW
721
722/**
723 * Display information about local interfaces.
724 *
725 * @param conn Connection to lldpd.
726 * @param w Writer.
727 * @param hidden Whatever to show hidden ports.
728 * @param env Environment from which we may find the list of ports.
729 * @param details Level of details we need (DISPLAY_*).
730 */
731void
732display_local_interfaces(lldpctl_conn_t *conn, struct writer *w,
733 struct cmd_env *env,
734 int hidden, int details)
735{
736 lldpctl_atom_t *iface;
737 int protocol = LLDPD_MODE_MAX;
738
739 tag_start(w, "lldp", "LLDP interfaces");
740 while ((iface = cmd_iterate_on_interfaces(conn, env))) {
741 lldpctl_atom_t *port;
742 port = lldpctl_get_port(iface);
743 display_interface(conn, w, hidden, iface, port, details, protocol);
744 lldpctl_atom_dec_ref(port);
745 }
746 tag_end(w);
747 }
748
78356144 749void
5331eb2d 750display_stat(struct writer *w, const char *tag, const char *descr,
751 long unsigned int cnt)
78356144 752{
b0cb07f7 753 char buf[20] = {};
78356144 754
5331eb2d 755 tag_start(w, tag, descr);
a769e9cb 756 snprintf(buf, sizeof(buf), "%lu", cnt);
5331eb2d 757 tag_attr(w, tag, "", buf);
758 tag_end(w);
759}
760
761void
762display_interface_stats(lldpctl_conn_t *conn, struct writer *w,
763 lldpctl_atom_t *port)
764{
78356144 765 tag_start(w, "interface", "Interface");
766 tag_attr(w, "name", "",
767 lldpctl_atom_get_str(port, lldpctl_k_port_name));
768
5331eb2d 769 display_stat(w, "tx", "Transmitted",
770 lldpctl_atom_get_int(port, lldpctl_k_tx_cnt));
771 display_stat(w, "rx", "Received",
772 lldpctl_atom_get_int(port, lldpctl_k_rx_cnt));
78356144 773
5331eb2d 774 display_stat(w, "rx_discarded_cnt", "Discarded",
775 lldpctl_atom_get_int(port,
776 lldpctl_k_rx_discarded_cnt));
78356144 777
5331eb2d 778 display_stat(w, "rx_unrecognized_cnt", "Unrecognized",
779 lldpctl_atom_get_int(port,
780 lldpctl_k_rx_unrecognized_cnt));
78356144 781
5331eb2d 782 display_stat(w, "ageout_cnt", "Ageout",
783 lldpctl_atom_get_int(port,
784 lldpctl_k_ageout_cnt));
78356144 785
5331eb2d 786 display_stat(w, "insert_cnt", "Inserted",
787 lldpctl_atom_get_int(port,
788 lldpctl_k_insert_cnt));
78356144 789
5331eb2d 790 display_stat(w, "delete_cnt", "Deleted",
791 lldpctl_atom_get_int(port,
792 lldpctl_k_delete_cnt));
78356144 793
794 tag_end(w);
795}
796
797/**
798 * Display interface stats
799 *
800 * @param conn Connection to lldpd.
801 * @param w Writer.
78356144 802 * @param env Environment from which we may find the list of ports.
78356144 803 */
804void
805display_interfaces_stats(lldpctl_conn_t *conn, struct writer *w,
806 struct cmd_env *env)
807{
808 lldpctl_atom_t *iface;
5331eb2d 809 int summary = 0;
810 u_int64_t h_tx_cnt = 0;
811 u_int64_t h_rx_cnt = 0;
812 u_int64_t h_rx_discarded_cnt = 0;
813 u_int64_t h_rx_unrecognized_cnt = 0;
814 u_int64_t h_ageout_cnt = 0;
815 u_int64_t h_insert_cnt = 0;
816 u_int64_t h_delete_cnt = 0;
5331eb2d 817
818 if (cmdenv_get(env, "summary"))
819 summary = 1;
78356144 820
5331eb2d 821 tag_start(w, "lldp", (summary ? "LLDP Global statistics" :
822 "LLDP statistics"));
78356144 823 while ((iface = cmd_iterate_on_interfaces(conn, env))) {
824 lldpctl_atom_t *port;
825 port = lldpctl_get_port(iface);
5331eb2d 826 if (!summary)
827 display_interface_stats(conn, w, port);
828 else {
829 h_tx_cnt += lldpctl_atom_get_int(port,
830 lldpctl_k_tx_cnt);
831 h_rx_cnt += lldpctl_atom_get_int(port,
832 lldpctl_k_rx_cnt);
833 h_rx_discarded_cnt += lldpctl_atom_get_int(port,
834 lldpctl_k_rx_discarded_cnt);
835 h_rx_unrecognized_cnt += lldpctl_atom_get_int(port,
836 lldpctl_k_rx_unrecognized_cnt);
837 h_ageout_cnt += lldpctl_atom_get_int(port,
838 lldpctl_k_ageout_cnt);
839 h_insert_cnt += lldpctl_atom_get_int(port,
840 lldpctl_k_insert_cnt);
841 h_delete_cnt += lldpctl_atom_get_int(port,
842 lldpctl_k_delete_cnt);
843 }
39a39abf 844 lldpctl_atom_dec_ref(port);
5331eb2d 845 }
846
847 if (summary) {
d947819d 848 tag_start(w, "summary", "Summary of stats");
5331eb2d 849 display_stat(w, "tx", "Transmitted", h_tx_cnt);
850 display_stat(w, "rx", "Received", h_rx_cnt);
851 display_stat(w, "rx_discarded_cnt", "Discarded",
852 h_rx_discarded_cnt);
853
854 display_stat(w, "rx_unrecognized_cnt", "Unrecognized",
855 h_rx_unrecognized_cnt);
856
857 display_stat(w, "ageout_cnt", "Ageout", h_ageout_cnt);
858
859 display_stat(w, "insert_cnt", "Inserted", h_insert_cnt);
860
861 display_stat(w, "delete_cnt", "Deleted", h_delete_cnt);
862 tag_end(w);
78356144 863 }
864 tag_end(w);
865}
866
9a775667 867static const char *
8729d69f
VB
868N(const char *str) {
869 if (str == NULL || strlen(str) == 0) return "(none)";
870 return str;
871}
872
873void
874display_configuration(lldpctl_conn_t *conn, struct writer *w)
875{
876 lldpctl_atom_t *configuration;
877
878 configuration = lldpctl_get_configuration(conn);
879 if (!configuration) {
9a775667 880 log_warnx("lldpctl", "not able to get configuration. %s",
8729d69f
VB
881 lldpctl_last_strerror(conn));
882 return;
883 }
884
885 tag_start(w, "configuration", "Global configuration");
886 tag_start(w, "config", "Configuration");
887
888 tag_datatag(w, "tx-delay", "Transmit delay",
8843f168 889 lldpctl_atom_get_str(configuration, lldpctl_k_config_tx_interval));
c10302a3 890 tag_datatag(w, "tx-hold", "Transmit hold",
891 lldpctl_atom_get_str(configuration, lldpctl_k_config_tx_hold));
ba1bdf6a
VB
892 tag_datatag(w, "max-neighbors", "Maximum number of neighbors",
893 lldpctl_atom_get_str(configuration, lldpctl_k_config_max_neighbors));
8729d69f
VB
894 tag_datatag(w, "rx-only", "Receive mode",
895 lldpctl_atom_get_int(configuration, lldpctl_k_config_receiveonly)?
896 "yes":"no");
897 tag_datatag(w, "mgmt-pattern", "Pattern for management addresses",
898 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_mgmt_pattern)));
899 tag_datatag(w, "iface-pattern", "Interface pattern",
900 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_iface_pattern)));
0a78e14f
VB
901 tag_datatag(w, "perm-iface-pattern", "Permanent interface pattern",
902 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_perm_iface_pattern)));
8729d69f
VB
903 tag_datatag(w, "cid-pattern", "Interface pattern for chassis ID",
904 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_cid_pattern)));
0e5197c8 905 tag_datatag(w, "cid-string", "Override chassis ID with",
5660759b 906 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_cid_string)));
8729d69f
VB
907 tag_datatag(w, "description", "Override description with",
908 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_description)));
909 tag_datatag(w, "platform", "Override platform with",
910 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_platform)));
ce347d29
JJ
911 tag_datatag(w, "hostname", "Override system name with",
912 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_hostname)));
8729d69f
VB
913 tag_datatag(w, "advertise-version", "Advertise version",
914 lldpctl_atom_get_int(configuration, lldpctl_k_config_advertise_version)?
915 "yes":"no");
bb37268d
VB
916 tag_datatag(w, "ifdescr-update", "Update interface descriptions",
917 lldpctl_atom_get_int(configuration, lldpctl_k_config_ifdescr_update)?
918 "yes":"no");
f84199dd
VB
919 tag_datatag(w, "iface-promisc", "Promiscuous mode on managed interfaces",
920 lldpctl_atom_get_int(configuration, lldpctl_k_config_iface_promisc)?
921 "yes":"no");
8729d69f
VB
922 tag_datatag(w, "lldpmed-no-inventory", "Disable LLDP-MED inventory",
923 (lldpctl_atom_get_int(configuration, lldpctl_k_config_lldpmed_noinventory) == 0)?
924 "no":"yes");
486a6133
VB
925 tag_datatag(w, "lldpmed-faststart", "LLDP-MED fast start mechanism",
926 (lldpctl_atom_get_int(configuration, lldpctl_k_config_fast_start_enabled) == 0)?
927 "no":"yes");
928 tag_datatag(w, "lldpmed-faststart-interval", "LLDP-MED fast start interval",
929 N(lldpctl_atom_get_str(configuration, lldpctl_k_config_fast_start_interval)));
dfbd7185 930 tag_datatag(w, "bond-slave-src-mac-type",
2746d430 931 "Source MAC for LLDP frames on bond slaves",
dfbd7185
RP
932 lldpctl_atom_get_str(configuration,
933 lldpctl_k_config_bond_slave_src_mac_type));
1eadc9a1
VB
934 tag_datatag(w, "lldp-portid-type",
935 "Port ID TLV subtype for LLDP frames",
8fbd3195
ST
936 lldpctl_atom_get_str(configuration,
937 lldpctl_k_config_lldp_portid_type));
1eadc9a1
VB
938 tag_datatag(w, "lldp-agent-type",
939 "Agent type",
940 lldpctl_atom_get_str(configuration,
941 lldpctl_k_config_lldp_agent_type));
8729d69f
VB
942
943 tag_end(w);
944 tag_end(w);
945
946 lldpctl_atom_dec_ref(configuration);
947}