From: Andreas Hofmeister Date: Sun, 28 Feb 2010 14:24:35 +0000 (+0100) Subject: Implement a basic "writer" infrastructure to emit structured text. X-Git-Tag: 0.5.0~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f4d33e6bf103d96c94ec392fd263b1bc78f8d616;p=thirdparty%2Flldpd.git Implement a basic "writer" infrastructure to emit structured text. This patch implements a basic plain text writer and uses that in display.c. --- diff --git a/src/Makefile.am b/src/Makefile.am index d8a94768..87703134 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ lldpd_SOURCES = main.c lldpd_LDADD = liblldpd.la ## lldpctl -lldpctl_SOURCES = lldpctl.c display.c +lldpctl_SOURCES = lldpctl.c display.c writer.h text_writer.c lldpctl_LDADD = libcommon.la ## With SNMP... diff --git a/src/display.c b/src/display.c index 04f53983..3c066bdb 100644 --- a/src/display.c +++ b/src/display.c @@ -15,6 +15,7 @@ */ #include "lldpd.h" +#include "writer.h" #include #include @@ -39,7 +40,69 @@ struct value_string { char *string; }; +static const struct value_string lldpd_protocol_map[] = { + { LLDPD_MODE_LLDP, "LLDP" }, + { LLDPD_MODE_CDPV1, "CDPv1"}, + { LLDPD_MODE_CDPV2, "CDPv2"}, + { LLDPD_MODE_EDP, "EDP" }, + { LLDPD_MODE_FDP, "FDP"}, + { LLDPD_MODE_SONMP, "SONMP"}, + { 0, NULL } +}; + +static const struct value_string chassis_id_subtype_map[] = { + { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname"}, + { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" }, + { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" }, + { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" }, + { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" }, + { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" }, + { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" }, + { 0, NULL}, +}; + +static const struct value_string port_id_subtype_map[] = { + { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"}, + { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" }, + { LLDP_PORTID_SUBTYPE_LOCAL, "local" }, + { LLDP_PORTID_SUBTYPE_LLADDR, "mac" }, + { LLDP_PORTID_SUBTYPE_ADDR, "ip" }, + { LLDP_PORTID_SUBTYPE_PORT, "unhandled" }, + { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" }, + { 0, NULL}, +}; + #ifdef ENABLE_LLDPMED +static const struct value_string chassis_med_type_map[] = { + { LLDPMED_CLASS_I, "Generic Endpoint (Class I)" }, + { LLDPMED_CLASS_II, "Media Endpoint (Class II)" }, + { LLDPMED_CLASS_III, "Communication Device Endpoint (Class III)" }, + { LLDPMED_NETWORK_DEVICE, "Network Connectivity Device" }, + { 0, NULL }, +}; + +static const struct value_string lldpmed_capabilit_map[] = { + {LLDPMED_CAP_CAP, "Capabilities"}, + {LLDPMED_CAP_POLICY, "Policy"}, + {LLDPMED_CAP_LOCATION, "Location"}, + {LLDPMED_CAP_MDI_PSE, "MDI/PSE"}, + {LLDPMED_CAP_MDI_PD, "MDI/PD"}, + {LLDPMED_CAP_IV, "Inventory"}, + { 0, NULL }, +}; + +static const struct value_string port_med_policy_map[] = { + { LLDPMED_APPTYPE_VOICE , "Voice"}, + { LLDPMED_APPTYPE_VOICESIGNAL, "Voice Signaling"}, + { LLDPMED_APPTYPE_GUESTVOICE, "Guest Voice"}, + { LLDPMED_APPTYPE_GUESTVOICESIGNAL, "Guest Voice Signaling"}, + { LLDPMED_APPTYPE_SOFTPHONEVOICE, "Softphone Voice"}, + { LLDPMED_APPTYPE_VIDEOCONFERENCE, "Video Conferencing"}, + { LLDPMED_APPTYPE_VIDEOSTREAM, "Streaming Video"}, + { LLDPMED_APPTYPE_VIDEOSIGNAL, "Video Signaling"}, + { 0, NULL }, +}; + static const struct value_string civic_address_type_values[] = { { 0, "Language" }, { 1, "National subdivisions" }, @@ -65,6 +128,61 @@ static const struct value_string civic_address_type_values[] = { { 128, "Script" }, { 0, NULL } }; + +static const struct value_string civic_address_type_tags[] = { + { 0, "language" }, + { 1, "country-subdivision" }, + { 2, "county" }, + { 3, "city" }, + { 4, "city-division" }, + { 5, "block" }, + { 6, "street" }, + { 16, "direction" }, + { 17, "street-suffix" }, + { 18, "street-suffix" }, + { 19, "number" }, + { 20, "number-suffix" }, + { 21, "landmark" }, + { 22, "additional" }, + { 23, "name" }, + { 24, "zip" }, + { 25, "building" }, + { 26, "unit" }, + { 27, "floor" }, + { 28, "room" }, + { 29, "place-type" }, + { 128, "Script" }, + { 0, NULL } +}; + +static const struct value_string port_med_geoid_map[] = { + { 1, "WGS84" }, + { 2, "NAD83" }, + { 3, "NAD83/MLLW" }, + { 0, NULL }, +}; + +static const struct value_string port_med_pow_devicetype_map[] = { + { LLDPMED_POW_TYPE_PSE, "PSE Device" }, + { LLDPMED_POW_TYPE_PD, "PD Device" }, + { 0, NULL }, +}; + +static const struct value_string port_med_pow_source_map[] = { + { LLDPMED_POW_SOURCE_PRIMARY, "Primary Power Source" }, + { LLDPMED_POW_SOURCE_BACKUP, "Backup Power Source / Power Conservation Mode" }, + { LLDPMED_POW_SOURCE_PSE, "PSE" }, + { LLDPMED_POW_SOURCE_LOCAL, "Local"}, + { LLDPMED_POW_SOURCE_BOTH, "PSE + Local"}, + { 0, NULL }, +}; + +static const struct value_string port_med_pow_priority_map[] = { + { LLDPMED_POW_PRIO_CRITICAL, "critical" }, + { LLDPMED_POW_PRIO_HIGH, "high" }, + { LLDPMED_POW_PRIO_LOW, "low" }, + { 0, NULL }, +}; #endif #ifdef ENABLE_DOT3 @@ -126,6 +244,42 @@ static const struct value_string operational_mau_type_values[] = { }; #endif +static const struct value_string chassis_capability_map[] = { + { LLDP_CAP_OTHER, "Other" }, + { LLDP_CAP_REPEATER, "Repeater"}, + { LLDP_CAP_BRIDGE, "Bridge"}, + { LLDP_CAP_ROUTER, "Router"}, + { LLDP_CAP_WLAN, "Wlan"}, + { LLDP_CAP_TELEPHONE,"Telephone"}, + { LLDP_CAP_DOCSIS, "Docsis"}, + { LLDP_CAP_STATION, "Station"}, + { 0, NULL}, +}; + + +static const char* +map_lookup(const struct value_string * list, int n) +{ + + unsigned int i; + + for( i = 0; list[i].string != NULL; i ++ ) { + if( list[i].value == n ) { + return list[i].string; + } + } + + return "unknown"; +} + +static char* +u2str(unsigned n) +{ + static char buf[21]; + snprintf(buf, sizeof(buf), "%u", n); + return buf; +} + static char* dump(void *data, int size, int max, char sep) { @@ -282,36 +436,21 @@ get_nb_port(int s, char *interface) } static void -display_cap(struct lldpd_chassis *chassis, u_int8_t bit, char *symbol) -{ - if (chassis->c_cap_available & bit) - printf("%s(%c) ", symbol, - (chassis->c_cap_enabled & bit)?'E':'d'); -} - -static void -pretty_print(char *string) +display_cap(struct writer * w, struct lldpd_chassis *chassis, u_int8_t bit, char *symbol) { - char *s = NULL; - if (((s = strchr(string, '\n')) == NULL) && (strlen(string) < 60)) { - printf("%s\n", string); - return; - } else - printf("\n"); - while (s != NULL) { - *s = '\0'; - printf(" %s\n", string); - *s = '\n'; - string = s + 1; - s = strchr(string, '\n'); + if (chassis->c_cap_available & bit) { + tag_start(w, "capability", "Capability"); + tag_attr (w, "type", "", symbol ); + tag_attr (w, "enabled", "", (chassis->c_cap_enabled & bit)?"on":"off"); + tag_end (w); } - printf(" %s\n", string); } #ifdef ENABLE_LLDPMED static int -display_fixed_precision(u_int64_t value, int intpart, int floatpart, int displaysign) +display_fixed_precision(u_int64_t value, int intpart, int floatpart, int displaysign, char ** res) { + static char buf[64]; u_int64_t tmp = value; int negative = 0; u_int32_t integer = 0; @@ -323,178 +462,169 @@ display_fixed_precision(u_int64_t value, int intpart, int floatpart, int display integer = (u_int32_t)((tmp & (((1ULL << intpart)-1) << floatpart)) >> floatpart); tmp = (tmp & ((1<< floatpart) - 1))*10000/(1ULL << floatpart); - printf("%s%u.%04llu", displaysign?(negative?"-":"+"):"", + snprintf(buf, sizeof(buf),"%s%u.%04llu", displaysign?(negative?"-":"+"):"", integer, (unsigned long long int)tmp); + + *res = buf; + return negative; } static void -display_latitude_or_longitude(int option, u_int64_t value) +display_latitude_or_longitude(struct writer *w, int option, u_int64_t value) { + static char buf[70]; int negative; - negative = display_fixed_precision(value, 9, 25, 0); + char * str; + + if ( option == 0 ) { + tag_start(w, "lat", "Latitude"); + } else { + tag_start(w, "lon", "Longitude"); + } + negative = display_fixed_precision(value, 9, 25, 0, &str); if (option == 0) - printf("%s", negative?" South":" North"); + snprintf(buf, sizeof(buf), "%s %s", str, negative?" S":" N"); else - printf("%s", negative?" West":" East"); + snprintf(buf, sizeof(buf), "%s %s", str, negative?" W":" E"); + + tag_data(w, buf); + tag_end(w); } static void -display_med(struct lldpd_chassis *chassis, struct lldpd_port *port) +display_med_capability(struct writer *w, struct lldpd_chassis *chassis, int cap) +{ + if (chassis->c_med_cap_available & cap) { + tag_start(w, "capability", "Capability"); + tag_attr(w, "type", "", + map_lookup(lldpmed_capabilit_map, cap)); + tag_end(w); + } +} + +static void +display_med(struct writer *w, struct lldpd_chassis *chassis, struct lldpd_port *port) { int i; char *value; - printf(" LLDP-MED Device Type: "); - switch (chassis->c_med_type) { - case LLDPMED_CLASS_I: - printf("Generic Endpoint (Class I)"); - break; - case LLDPMED_CLASS_II: - printf("Media Endpoint (Class II)"); - break; - case LLDPMED_CLASS_III: - printf("Communication Device Endpoint (Class III)"); - break; - case LLDPMED_NETWORK_DEVICE: - printf("Network Connectivity Device"); - break; - default: - printf("Unknown (%d)", chassis->c_med_type); - break; - } - printf("\n LLDP-MED Capabilities:"); - if (chassis->c_med_cap_available & LLDPMED_CAP_CAP) - printf(" Capabilities"); - if (chassis->c_med_cap_available & LLDPMED_CAP_POLICY) - printf(" Policy"); - if (chassis->c_med_cap_available & LLDPMED_CAP_LOCATION) - printf(" Location"); - if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PSE) - printf(" MDI/PSE"); - if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PD) - printf(" MDI/PD"); - if (chassis->c_med_cap_available & LLDPMED_CAP_IV) - printf(" Inventory"); - printf("\n"); + + tag_start(w, "lldp-med", "LLDP-MED"); + + tag_datatag(w, "device-type", "Device Type", + map_lookup(chassis_med_type_map, chassis->c_med_type)); + + display_med_capability(w, chassis, LLDPMED_CAP_CAP); + display_med_capability(w, chassis, LLDPMED_CAP_POLICY); + display_med_capability(w, chassis, LLDPMED_CAP_LOCATION); + display_med_capability(w, chassis, LLDPMED_CAP_MDI_PSE); + display_med_capability(w, chassis, LLDPMED_CAP_MDI_PD); + display_med_capability(w, chassis, LLDPMED_CAP_IV); + for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) { if (i+1 == port->p_med_policy[i].type) { - printf(" LLDP-MED Network Policy for "); - switch(port->p_med_policy[i].type) { - case LLDPMED_APPTYPE_VOICE: - printf("Voice"); - break; - case LLDPMED_APPTYPE_VOICESIGNAL: - printf("Voice Signaling"); - break; - case LLDPMED_APPTYPE_GUESTVOICE: - printf("Guest Voice"); - break; - case LLDPMED_APPTYPE_GUESTVOICESIGNAL: - printf("Guest Voice Signaling"); - break; - case LLDPMED_APPTYPE_SOFTPHONEVOICE: - printf("Softphone Voice"); - break; - case LLDPMED_APPTYPE_VIDEOCONFERENCE: - printf("Video Conferencing"); - break; - case LLDPMED_APPTYPE_VIDEOSTREAM: - printf("Streaming Video"); - break; - case LLDPMED_APPTYPE_VIDEOSIGNAL: - printf("Video Signaling"); - break; - default: - printf("Reserved"); - } - printf(":\n Policy: "); - if (port->p_med_policy[i].unknown) { - printf("unknown, "); - } else { - printf("defined, "); - } - if (!port->p_med_policy[i].tagged) { - printf("un"); - } - printf("tagged"); - printf("\n VLAN ID: "); - if (port->p_med_policy[i].vid == 0) { - printf("Priority Tagged"); - } else if (port->p_med_policy[i].vid == 4095) { - printf("reserved"); - } else { - printf("%u", port->p_med_policy[i].vid); + tag_start(w, "policy", "LLDP-MED Network Policy for"); + tag_attr(w, "apptype", "AppType", + u2str(port->p_med_policy[i].type)); + tag_attr(w, "defined", "Defined", + (port->p_med_policy[i].unknown)?"no":"yes"); + + tag_datatag(w, "descr", "", + map_lookup(port_med_policy_map, port->p_med_policy[i].type)); + + if (port->p_med_policy[i].tagged) { + tag_start(w, "vlan", "VLAN"); + if (port->p_med_policy[i].vid == 0) { + tag_attr(w, "vid", "", "priority"); + } else if (port->p_med_policy[i].vid == 4095) { + tag_attr(w, "vid", "", "reserved"); + } else { + tag_attr(w, "vid", "", + u2str(port->p_med_policy[i].vid)); + } + tag_end(w); } - printf("\n Layer 2 Priority: "); - printf("%u", port->p_med_policy[i].priority); - printf("\n DSCP Value: "); - printf("%u\n", port->p_med_policy[i].dscp); + + tag_datatag(w, "priority", "Layer 2 Priority", + u2str(port->p_med_policy[i].priority)); + + tag_datatag(w, "dscp", "DSCP Value", + u2str(port->p_med_policy[i].dscp)); + + tag_end(w); } } for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) { if (i+1 == port->p_med_location[i].format) { - printf(" LLDP-MED Location Identification: "); + tag_start(w, "location", "LLDP-MED Location Identification"); + switch(port->p_med_location[i].format) { case LLDPMED_LOCFORMAT_COORD: - printf("\n Coordinate-based data: "); + tag_attr(w, "type", "Type", "coordinates"); + if (port->p_med_location[i].data_len != 16) - printf("bad data length"); + LLOG_WARN("bad data length"); else { u_int64_t l; + u_int8_t v; + char * s; + + v = *(u_int8_t*)(port->p_med_location[i].data + 15); + tag_attr(w, "geoid", "Geoid", + map_lookup(port_med_geoid_map,v)); /* Latitude and longitude */ memcpy(&l, port->p_med_location[i].data, sizeof(u_int64_t)); l = (ntohll(l) & 0x03FFFFFFFF000000ULL) >> 24; - display_latitude_or_longitude(0, l); - printf(", "); + display_latitude_or_longitude(w,0, l); memcpy(&l, port->p_med_location[i].data + 5, sizeof(u_int64_t)); l = (ntohll(l) & 0x03FFFFFFFF000000ULL) >> 24; - display_latitude_or_longitude(1, l); + display_latitude_or_longitude(w,1, l); /* Altitude */ - printf(", "); memcpy(&l, port->p_med_location[i].data + 10, sizeof(u_int64_t)); l = (ntohll(l) & 0x3FFFFFFF000000ULL) >> 24; - display_fixed_precision(l, 22, 8, 1); + display_fixed_precision(l, 22, 8, 1, &s); + + tag_start(w, "altitude", "Altitude"); switch ((*(u_int8_t*)(port->p_med_location[i].data + 10)) & 0xf0) { case (1 << 4): - printf(" meters"); break; + tag_attr(w, "unit", "", "m"); + break; case (2 << 4): - printf(" floors"); break; + tag_attr(w, "unit", "", "floor"); + break; default: - printf(" (unknown)"); + tag_attr(w, "unit", "", "unknown"); } + tag_data(w,s); + tag_end(w); - /* Datum */ - switch (*(u_int8_t*)(port->p_med_location[i].data + - 15)) { - case 1: - printf(", WGS84"); break; - case 2: - printf(", NAD83"); break; - case 3: - printf(", NAD83/MLLW"); break; - } } break; case LLDPMED_LOCFORMAT_CIVIC: - printf("Civic address: "); + tag_attr(w, "type", "Type", "address"); + if ((port->p_med_location[i].data_len < 3) || (port->p_med_location[i].data_len - 1 != *(u_int8_t*)port->p_med_location[i].data)) - printf("bad data length"); + LLOG_WARN("bad data length"); else { - int l = 4, n, catype, calength, j = 0; - printf("\n%28s: %c%c", "Country", - ((char *)port->p_med_location[i].data)[2], - ((char *)port->p_med_location[i].data)[3]); + int l = 4, n, catype, calength; + char country[3]; + country[0] = ((char *)port->p_med_location[i].data)[2]; + country[1] = ((char *)port->p_med_location[i].data)[3]; + country[2] = 0; + + tag_datatag(w, "country", "Country", country); + while ((n = (port-> p_med_location[i].data_len - l)) >= 2) { catype = *(u_int8_t*)(port-> @@ -502,29 +632,20 @@ display_med(struct lldpd_chassis *chassis, struct lldpd_port *port) calength = *(u_int8_t*)(port-> p_med_location[i].data + l + 1); if (n < 2 + calength) { - printf("bad data length"); - break; - } - for (j = 0; - civic_address_type_values[j].string != NULL; - j++) { - if (civic_address_type_values[j].value == - catype) - break; - } - if (civic_address_type_values[j].string == NULL) { - printf("unknown type %d", catype); + LLOG_WARN("bad data length"); break; } + if ((value = strndup((char *)(port-> p_med_location[i].data + l + 2), calength)) == NULL) { - printf("not enough memory"); + fatalx("not enough memory"); break; } - printf("\n%28s: %s", - civic_address_type_values[j].string, - value); + tag_datatag(w, + map_lookup(civic_address_type_tags,catype), + map_lookup(civic_address_type_values,catype), + value); free(value); l += 2 + calength; } @@ -534,69 +655,42 @@ display_med(struct lldpd_chassis *chassis, struct lldpd_port *port) if ((value = strndup((char *)(port-> p_med_location[i].data), port->p_med_location[i].data_len)) == NULL) { - printf("not enough memory"); + fatalx( "not enough memory"); break; } - printf("ECS ELIN: %s", value); + tag_attr(w, "type", "Type", "elin"); + tag_datatag(w, "ecs", "ECS ELIN", value); free(value); break; default: - printf("unknown location data format: \n %s", + LLOG_WARN("unknown location data format: \n %s", dump(port->p_med_location[i].data, port->p_med_location[i].data_len, 20, ' ')); } - printf("\n"); + tag_end(w); } } if (port->p_med_pow_devicetype) { - printf(" LLDP-MED Extended Power-over-Ethernet:\n"); - printf(" Power Type & Source: "); - switch (port->p_med_pow_devicetype) { - case LLDPMED_POW_TYPE_PSE: - printf("PSE Device"); - break; - case LLDPMED_POW_TYPE_PD: - printf("PD Device"); - break; - default: - printf("reserved"); - } - switch (port->p_med_pow_source) { - case LLDPMED_POW_SOURCE_UNKNOWN: - case LLDPMED_POW_SOURCE_RESERVED: - printf(", unknown"); break; - case LLDPMED_POW_SOURCE_PRIMARY: - printf(", Primary Power Source"); - break; - case LLDPMED_POW_SOURCE_BACKUP: - printf(", Backup Power Source / Power Conservation Mode"); - break; - case LLDPMED_POW_SOURCE_PSE: - printf(", PSE"); break; - case LLDPMED_POW_SOURCE_LOCAL: - printf(", local"); break; - case LLDPMED_POW_SOURCE_BOTH: - printf(", PSE & local"); - break; - } - printf("\n Power Priority: "); - switch (port->p_med_pow_priority) { - case LLDPMED_POW_PRIO_CRITICAL: - printf("critical"); break; - case LLDPMED_POW_PRIO_HIGH: - printf("high"); break; - case LLDPMED_POW_PRIO_LOW: - printf("low"); break; - default: - printf("unknown"); - } - printf("\n Power Value: "); + tag_start(w, "poe", "Extended Power-over-Ethernet"); + + tag_start(w, "device-type", "Power Type & Source"); + tag_data(w, map_lookup(port_med_pow_devicetype_map, port->p_med_pow_devicetype)); + tag_end(w); + + tag_start(w, "source", "Power Source"); + tag_data(w, map_lookup(port_med_pow_source_map, port->p_med_pow_source)); + tag_end(w); + + tag_start(w, "priority", "Power Priority"); + tag_data(w, map_lookup(port_med_pow_priority_map, port->p_med_pow_priority)); + tag_end(w); + if(port->p_med_pow_val < 1024) { - printf("%u mW", port->p_med_pow_val * 100); - } else { - printf("reserved"); + tag_start(w, "power", "Power Value"); + tag_data(w, u2str(port->p_med_pow_val * 100)); + tag_end(w); } - printf("\n"); + tag_end(w); } if (chassis->c_med_hw || chassis->c_med_sw || @@ -605,206 +699,208 @@ display_med(struct lldpd_chassis *chassis, struct lldpd_port *port) chassis->c_med_manuf || chassis->c_med_model || chassis->c_med_asset) { - printf(" LLDP-MED Inventory:\n"); + tag_start(w, "inventory", "Inventory"); + if (chassis->c_med_hw) - printf(" Hardware Revision: %s\n", chassis->c_med_hw); + tag_datatag(w, "hardware", "Hardware Revision", + chassis->c_med_hw); if (chassis->c_med_sw) - printf(" Software Revision: %s\n", chassis->c_med_sw); + tag_datatag(w, "software", "Software Revision", + chassis->c_med_sw); if (chassis->c_med_fw) - printf(" Firmware Revision: %s\n", chassis->c_med_fw); + tag_datatag(w, "firmware", "Firmware Revision", + chassis->c_med_fw); if (chassis->c_med_sn) - printf(" Serial Number: %s\n", chassis->c_med_sn); + tag_datatag(w, "serial", "Serial Number", + chassis->c_med_sn); if (chassis->c_med_manuf) - printf(" Manufacturer: %s\n", - chassis->c_med_manuf); + tag_datatag(w, "manufacturer", "Manufacturer", + chassis->c_med_manuf); if (chassis->c_med_model) - printf(" Model: %s\n", - chassis->c_med_model); + tag_datatag(w, "model", "Model", + chassis->c_med_model); if (chassis->c_med_asset) - printf(" Asset ID: %s\n", - chassis->c_med_asset); + tag_datatag(w, "asset", "Asset ID", + chassis->c_med_asset); + + tag_end(w); } + + tag_end(w); } #endif static void -display_chassis(struct lldpd_chassis *chassis) +display_chassis(struct writer * w, struct lldpd_chassis *chassis) { char *cid; if ((cid = (char *)malloc(chassis->c_id_len + 1)) == NULL) fatal(NULL); memcpy(cid, chassis->c_id, chassis->c_id_len); cid[chassis->c_id_len] = 0; + + tag_start(w, "chassis", "Chassis"); + tag_start(w, "id", "ChassisID"); + tag_attr (w, "type", "", map_lookup(chassis_id_subtype_map, chassis->c_id_subtype)); + switch (chassis->c_id_subtype) { case LLDP_CHASSISID_SUBTYPE_IFNAME: - printf(" ChassisID: %s (ifName)\n", cid); - break; case LLDP_CHASSISID_SUBTYPE_IFALIAS: - printf(" ChassisID: %s (ifAlias)\n", cid); - break; case LLDP_CHASSISID_SUBTYPE_LOCAL: - printf(" ChassisID: %s (local)\n", cid); + tag_data (w, cid); break; case LLDP_CHASSISID_SUBTYPE_LLADDR: - printf(" ChassisID: %s (MAC)\n", - dump(chassis->c_id, chassis->c_id_len, ETH_ALEN, ':')); + tag_data(w, dump(chassis->c_id, chassis->c_id_len, ETH_ALEN, ':')); break; case LLDP_CHASSISID_SUBTYPE_ADDR: if (*(u_int8_t*)chassis->c_id == 1) { - printf(" ChassisID: %s (IP)\n", - inet_ntoa(*(struct in_addr*)(chassis->c_id + - 1))); + tag_data(w, inet_ntoa(*(struct in_addr*)(chassis->c_id + 1))); break; } case LLDP_CHASSISID_SUBTYPE_PORT: case LLDP_CHASSISID_SUBTYPE_CHASSIS: default: - printf(" ChassisID: %s (unhandled type)\n", - dump(chassis->c_id, chassis->c_id_len, 16, ' ')); + tag_data(w, dump(chassis->c_id, chassis->c_id_len, 16, ' ')); } - printf(" SysName: %s\n", chassis->c_name); - printf(" SysDescr: "); pretty_print(chassis->c_descr); + + tag_end(w); + + tag_datatag(w, "name", "SysName", chassis->c_name); + tag_datatag(w, "descr", "SysDescr", chassis->c_descr); + if (chassis->c_mgmt.s_addr != INADDR_ANY) - printf(" MgmtIP: %s\n", inet_ntoa(chassis->c_mgmt)); - printf(" Caps: "); - display_cap(chassis, LLDP_CAP_OTHER, "Other"); - display_cap(chassis, LLDP_CAP_REPEATER, "Repeater"); - display_cap(chassis, LLDP_CAP_BRIDGE, "Bridge"); - display_cap(chassis, LLDP_CAP_ROUTER, "Router"); - display_cap(chassis, LLDP_CAP_WLAN, "Wlan"); - display_cap(chassis, LLDP_CAP_TELEPHONE, "Tel"); - display_cap(chassis, LLDP_CAP_DOCSIS, "Docsis"); - display_cap(chassis, LLDP_CAP_STATION, "Station"); - printf("\n"); + tag_datatag(w, "mgmt-ip", "MgmtIP", inet_ntoa(chassis->c_mgmt)); + + display_cap(w, chassis, LLDP_CAP_OTHER, "Other"); + display_cap(w, chassis, LLDP_CAP_REPEATER, "Repeater"); + display_cap(w, chassis, LLDP_CAP_BRIDGE, "Bridge"); + display_cap(w, chassis, LLDP_CAP_ROUTER, "Router"); + display_cap(w, chassis, LLDP_CAP_WLAN, "Wlan"); + display_cap(w, chassis, LLDP_CAP_TELEPHONE, "Tel"); + display_cap(w, chassis, LLDP_CAP_DOCSIS, "Docsis"); + display_cap(w, chassis, LLDP_CAP_STATION, "Station"); + + tag_end(w); } #ifdef ENABLE_DOT3 static void -display_autoneg(struct lldpd_port *port, int bithd, int bitfd, char *desc) +display_autoneg(struct writer * w, struct lldpd_port *port, int bithd, int bitfd, char *desc) { if (!((port->p_autoneg_advertised & bithd) || (port->p_autoneg_advertised & bitfd))) return; - printf("%s ", desc); - if (port->p_autoneg_advertised & bithd) { - printf("(HD"); - if (port->p_autoneg_advertised & bitfd) { - printf(", FD) "); - return; - } - printf(") "); - return; - } - printf("(FD) "); + + tag_start(w, "advertised", "Adv"); + tag_attr(w, "type", "", desc); + tag_attr(w, "hd", "HD", (port->p_autoneg_advertised & bithd)?"yes":"no"); + tag_attr(w, "fd", "FD", (port->p_autoneg_advertised)?"yes":"no"); + tag_end (w); } #endif static void -display_port(struct lldpd_port *port) +display_port(struct writer * w, struct lldpd_port *port) { char *pid; struct in_addr address; -#ifdef ENABLE_DOT3 - int i; -#endif if ((pid = (char *)malloc(port->p_id_len + 1)) == NULL) fatal(NULL); memcpy(pid, port->p_id, port->p_id_len); pid[port->p_id_len] = 0; + + tag_start(w, "port", "Port"); + tag_start(w, "id", "PortID"); + tag_attr (w, "type", "", map_lookup(port_id_subtype_map, port->p_id_subtype)); + switch (port->p_id_subtype) { case LLDP_PORTID_SUBTYPE_IFNAME: - printf(" PortID: %s (ifName)\n", pid); - break; case LLDP_PORTID_SUBTYPE_IFALIAS: - printf(" PortID: %s (ifAlias)\n", pid); - break; case LLDP_PORTID_SUBTYPE_LOCAL: - printf(" PortID: %s (local)\n", pid); + tag_data (w, pid); break; case LLDP_PORTID_SUBTYPE_LLADDR: - printf(" PortID: %s (MAC)\n", - dump(port->p_id, port->p_id_len, ETH_ALEN, ':')); + tag_data(w, dump(port->p_id, port->p_id_len, ETH_ALEN, ':')); break; case LLDP_PORTID_SUBTYPE_ADDR: if (*(u_int8_t*)port->p_id == 1) { memcpy(&address, port->p_id + 1, sizeof(struct in_addr)); - printf(" PortID: %s (IP)\n", - inet_ntoa(address)); + tag_data(w, inet_ntoa(address)); break; } case LLDP_PORTID_SUBTYPE_PORT: case LLDP_PORTID_SUBTYPE_AGENTCID: default: - printf(" ChassisID: %s (unhandled type)\n", - dump(port->p_id, port->p_id_len, 16, ' ')); + tag_data(w, dump(port->p_id, port->p_id_len, 16, ' ')); } - printf(" PortDescr: "); pretty_print(port->p_descr); + + tag_end(w); + + tag_datatag(w, "descr", "PortDescr", port->p_descr); + #ifdef ENABLE_DOT3 if (port->p_mfs) - printf(" MFS: %d bytes\n", port->p_mfs); + tag_datatag(w, "mfs", "MFS", u2str(port->p_mfs)); + if (port->p_aggregid) - printf("\n Port is aggregated. PortAggregID: %d\n", - port->p_aggregid); + tag_datatag(w, "aggregation", " Port is aggregated. PortAggregID", + u2str(port->p_aggregid)); if (port->p_autoneg_support || port->p_autoneg_enabled || port->p_mau_type) { - printf("\n Autoneg: %ssupported/%senabled\n", - port->p_autoneg_support?"":"not ", - port->p_autoneg_enabled?"":"not "); + tag_start(w, "auto-negotiation", "PMD autoneg"); + tag_attr (w, "supported", "supported", port->p_autoneg_support?"yes":"no"); + tag_attr (w, "enabled", "enabled", port->p_autoneg_enabled?"yes":"no"); + if (port->p_autoneg_enabled) { - printf(" PMD autoneg: "); - display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_10BASE_T, + display_autoneg(w, port, LLDP_DOT3_LINK_AUTONEG_10BASE_T, LLDP_DOT3_LINK_AUTONEG_10BASET_FD, "10Base-T"); - display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_TX, + display_autoneg(w, port, LLDP_DOT3_LINK_AUTONEG_100BASE_TX, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD, "100Base-T"); - display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_T2, + display_autoneg(w, port, LLDP_DOT3_LINK_AUTONEG_100BASE_T2, LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD, "100Base-T2"); - display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_X, + display_autoneg(w, port, LLDP_DOT3_LINK_AUTONEG_1000BASE_X, LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD, "100Base-X"); - display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_T, + display_autoneg(w, port, LLDP_DOT3_LINK_AUTONEG_1000BASE_T, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD, "1000Base-T"); - printf("\n"); } - printf(" MAU oper type: "); - for (i = 0; operational_mau_type_values[i].value != 0; i++) { - if (operational_mau_type_values[i].value == - port->p_mau_type) { - printf("%s\n", operational_mau_type_values[i].string); - break; - } - } - if (operational_mau_type_values[i].value == 0) - printf("unknown (%d)\n", port->p_mau_type); + tag_datatag(w, "current", "MAU oper type", + map_lookup(operational_mau_type_values, port->p_mau_type)); + tag_end(w); } #endif + tag_end(w); } #ifdef ENABLE_DOT1 static void -display_vlans(struct lldpd_port *port) +display_vlans(struct writer *w, struct lldpd_port *port) { - int i = 0; int foundpvid = 0; struct lldpd_vlan *vlan; TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) { if (port->p_pvid == vlan->v_vid) foundpvid = 1; - printf(" %cVLAN %4d: %-20s%c", - (port->p_pvid == vlan->v_vid)?'*':' ', - vlan->v_vid, vlan->v_name, - (i++ % 2) ? '\n' : ' '); + + tag_start(w, "vlan", "VLAN"); + tag_attr(w, "vlan-id", "", u2str(vlan->v_vid)); + if (foundpvid) + tag_attr(w, "pvid", "pvid", "yes"); + tag_data(w, vlan->v_name); + tag_end(w); + } + if (!foundpvid && port->p_pvid) { + tag_start(w, "vlan", "VLAN"); + tag_attr(w, "vlan-id", "", u2str(port->p_pvid)); + tag_attr(w, "pvid", "pvid", "yes"); } - if (!foundpvid && port->p_pvid) - printf(" *VLAN %4d\n", port->p_pvid); - else if (i % 2) - printf("\n"); } #endif @@ -828,6 +924,7 @@ display_age(struct lldpd_port *port) void display_interfaces(int s, int argc, char *argv[]) { + struct writer * w; int i, nb; struct interfaces ifs; #ifdef ENABLE_DOT1 @@ -838,13 +935,14 @@ display_interfaces(int s, int argc, char *argv[]) struct lldpd_port port; char sep[80]; + w = txt_init( stdout ); + memset(sep, '-', 79); sep[79] = 0; get_interfaces(s, &ifs); + + tag_start(w, "lldp", "LLDP neighbors"); - printf("%s\n", sep); - printf(" LLDP neighbors\n"); - printf("%s\n", sep); TAILQ_FOREACH(iff, &ifs, next) { if (optind < argc) { for (i = optind; i < argc; i++) @@ -858,37 +956,31 @@ display_interfaces(int s, int argc, char *argv[]) if (!((get_chassis(s, &chassis, iff->name, i) != -1) && (get_port(s, &port, iff->name, i) != -1))) continue; - printf("Interface: %s (via ", iff->name); - switch (port.p_protocol) { - case (LLDPD_MODE_LLDP): printf("LLDP"); break; - case (LLDPD_MODE_CDPV1): printf("CDPv1"); break; - case (LLDPD_MODE_CDPV2): printf("CDPv2"); break; - case (LLDPD_MODE_EDP): printf("EDP"); break; - case (LLDPD_MODE_FDP): printf("FDP"); break; - case (LLDPD_MODE_SONMP): printf("SONMP"); break; - default: printf("unknown protocol"); break; - } - printf(") - RID: %d", chassis.c_index); - printf(" - Time: %s\n", display_age(&port)); - display_chassis(&chassis); - printf("\n"); - display_port(&port); + tag_start(w, "interface", "Interface"); + tag_attr(w, "name", "", iff->name ); + tag_attr(w, "via" , "via", map_lookup(lldpd_protocol_map, port.p_protocol)); + tag_attr(w, "rid" , "RID", u2str(chassis.c_index)); + tag_attr(w, "age" , "Time", display_age(&port)); + + display_chassis(w,&chassis); + display_port(w, &port); #ifdef ENABLE_DOT1 if (get_vlans(s, &vls, iff->name, i) != -1) memcpy(&port.p_vlans, &vls, sizeof(struct vlans)); if (!TAILQ_EMPTY(&port.p_vlans) || port.p_pvid) { - printf("\n"); - display_vlans(&port); + display_vlans(w, &port); } #endif #ifdef ENABLE_LLDPMED if (port.p_med_cap_enabled) { - printf("\n"); - display_med(&chassis, &port); + display_med(w, &chassis, &port); } #endif - printf("%s\n", sep); + tag_end(w); /* interface */ } } + + tag_end(w); + w->finish(w); } diff --git a/src/text_writer.c b/src/text_writer.c new file mode 100644 index 00000000..b83ec9c6 --- /dev/null +++ b/src/text_writer.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010 Andreas Hofmeister + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "writer.h" +#include "lldpd.h" + +static char sep[] = "-------------------------------------------------------------------------------"; + +struct txt_writer_private { + FILE * fh; + int level; + int attrs; +}; + +void txt_start(struct writer * w , const char * tag, const char * descr ) { + struct txt_writer_private * p = w->priv; + int i = 0; + char buf[128]; + + if ( p->level == 0 ) { + fprintf( p->fh, "%s\n", sep ); + } else { + fprintf( p->fh, "\n" ); + } + + for( i = 1; i < p->level; i ++ ) { + fprintf( p->fh, " " ); + } + + snprintf(buf,sizeof(buf),"%s:", descr); + fprintf( p->fh, "%-13s", buf); + + if ( p->level == 0 ) + fprintf( p->fh, "\n%s", sep ); + + p->level ++; + p->attrs = 0; +} + +void txt_attr(struct writer * w, const char * tag, const char * descr, const char * value ) { + struct txt_writer_private * p = w->priv; + + if ( descr == NULL || strlen( descr ) == 0 ) { + fprintf( p->fh, "%s%s", (p->attrs > 0 ? ", " : " "), value ); + } else { + fprintf( p->fh, "%s%s: %s", (p->attrs > 0 ? ", " : " "), descr, value ); + } + + p->attrs ++; +} + +void txt_data(struct writer * w, const char * data) { + struct txt_writer_private * p = w->priv; + fprintf( p->fh, " %s", data ); +} + +void txt_end(struct writer * w) { + struct txt_writer_private * p = w->priv; + p->level --; + + if ( p->level == 1 ) + fprintf( p->fh, "\n%s", sep ); +} + +void txt_finish(struct writer * w) { + struct txt_writer_private * p = w->priv; + + fprintf(p->fh, "\n"); + + free( w->priv ); + w->priv = NULL; + + free( w ); +} + +struct writer * txt_init(FILE * fh) { + + struct writer * result; + struct txt_writer_private * priv; + + priv = malloc( sizeof( *priv ) ); + if ( ! priv ) { + fatalx("out of memory"); + return NULL; + } + + priv->fh = fh; + priv->level = 0; + priv->attrs = 0; + + result = malloc( sizeof( struct writer ) ); + if ( ! result ) { + fatalx("out of memory"); + return NULL; + } + + result->priv = priv; + result->start = txt_start; + result->attr = txt_attr; + result->data = txt_data; + result->end = txt_end; + result->finish= txt_finish; + + return result; +} + diff --git a/src/writer.h b/src/writer.h new file mode 100644 index 00000000..4af13797 --- /dev/null +++ b/src/writer.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010 Andreas Hofmeister + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WRITER_H +#define _WRITER_H + +#include + +struct writer { + void * priv; + void (*start)(struct writer *, const char * tag, const char * descr); + void (*attr)(struct writer *, const char * tag, const char * descr, const char * value); + void (*data)(struct writer *, const char * data); + void (*end)(struct writer *); + void (*finish)(struct writer *); +}; + +#define tag_start(w,...) w->start(w,## __VA_ARGS__) +#define tag_attr(w,...) w->attr(w,## __VA_ARGS__) +#define tag_data(w,...) w->data(w,## __VA_ARGS__) +#define tag_end(w,...) w->end(w,## __VA_ARGS__) +#define tag_datatag(w,t,d,...) { w->start(w,t,d); w->data(w,## __VA_ARGS__); w->end(w); } + +extern struct writer * txt_init( FILE * ); + +#endif /* _WRITER_H */