summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/test-lldp.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-02-19 17:58:52 +0100
committerLennart Poettering <lennart@poettering.net>2016-02-21 20:40:56 +0100
commit34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 (patch)
tree4c5069ae6356036a4f347ca7acd8df8d0332d97c /src/libsystemd-network/test-lldp.c
parent1b4cd0cf11feb7d41f2eff17f86fa55b31bb6841 (diff)
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and extending the logic a bit on the other. Specifically: - Besides the sd_lldp object only one other object is maintained now, sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for maintainging info about peers in the database. Separation between packet, TLV and chassis data is not maintained anymore. This should be a major simplification. - The sd-lldp API has been extended so that a couple of per-neighbor fields may be queried directly, without iterating through the object. Other fields that may appear multiple times, OTOH have to be iterated through. - The maximum number of entries in the neighbor database is now configurable during runtime. - The generation of callbacks from sd_lldp objects is more restricted: callbacks are only invoked when actual data changed. - The TTL information is now hooked with a timer event, so that removals from the neighbor database due to TTLs now result in a callback event. - Querying LLDP neighbor database will now return a strictly ordered array, to guarantee stability. - A "capabilities" mask may now be configured, that selects what type of LLDP neighbor data is collected. This may be used to restrict collection of LLDP info about routers instead of all neighbors. This is now exposed via networkd's LLDP= setting. - sd-lldp's API to serialize the collected data to text files has been removed. Instead, there's now an API to extract the raw binary data from LLDP neighbor objects, as well as one to convert this raw binary data back to an LLDP neighbor object. networkd will save this raw binary data to /run now, and the client side can simply parse the information. - support for parsing the more exotic TLVs has been removed, since we are not using that. Instead there are now APIs to extract the raw data from TLVs. Given how easy it is to parse the TLVs clients should do so now directly instead of relying on our APIs for that. - A lot of the APIs that parse out LLDP strings have been simplified so that they actually return strings, instead of char arrays with a length. To deal with possibly dangerous characters the strings are escaped if needed. - APIs to extract and format the chassis and port IDs as strings has been added. - lldp.h has been simplified a lot. The enums are anonymous now, since they were never used as enums, but simply as constants. Most definitions we don't actually use ourselves have eben removed.
Diffstat (limited to 'src/libsystemd-network/test-lldp.c')
-rw-r--r--src/libsystemd-network/test-lldp.c320
1 files changed, 55 insertions, 265 deletions
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index 768211a315..589117f56e 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -22,6 +22,7 @@
#include <net/ethernet.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "sd-event.h"
#include "sd-lldp.h"
@@ -29,7 +30,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "lldp-network.h"
-#include "lldp-tlv.h"
#include "lldp.h"
#include "macro.h"
#include "string-util.h"
@@ -38,211 +38,8 @@
#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
-static int test_fd[2];
-
-static struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
-};
-
-static int lldp_build_tlv_packet(tlv_packet **ret) {
- _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL;
- const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
- struct ether_header ether = {
- .ether_type = htons(ETHERTYPE_LLDP),
- };
-
- /* Append Ethernet header */
- memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
- memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
-
- assert_se(tlv_packet_new(&m) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
-
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
- assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* port name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* ttl */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
-
- assert_se(tlv_packet_append_u16(m, 170) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
- strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system descrition */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
- strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* Mark end of packet */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- *ret = m;
-
- m = NULL;
-
- return 0;
-}
-
-static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
- uint8_t *p, subtype;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
- assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
-
- assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
-
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_port_id_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
- uint8_t subtype;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length-1);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_PORT) == 1);
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_system_name_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 1;
-}
-
-static int lldp_parse_system_desc_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_ttl_tlv(tlv_packet *m) {
- uint16_t ttl;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
- assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
-
- assert_se(ttl == 170);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_get_destination_type(tlv_packet *m) {
- int dest;
-
- assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
- assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
-
- return 0;
-}
-
-static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
- uint8_t subtype;
-
- assert_se(tlv_packet_parse_pdu(m, len) >= 0);
- assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
- assert_se(lldp_parse_port_id_tlv(m) >= 0);
- assert_se(lldp_parse_system_name_tlv(m) >= 0);
- assert_se(lldp_parse_ttl_tlv(m) >= 0);
- assert_se(lldp_parse_system_desc_tlv(m) >= 0);
-
- assert_se(lldp_get_destination_type(m) >= 0);
-
- return 0;
-}
-
-static void test_parser(void) {
- _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL;
-
- /* form a packet */
- lldp_build_tlv_packet(&tlv);
- /* parse the packet */
- tlv_packet_parse_pdu(tlv, tlv->length);
- /* verify */
- lldp_parse_tlv_packet(tlv, tlv->length);
-}
+static int test_fd[2] = { -1, -1 };
+static int lldp_handler_calls;
int lldp_network_bind_raw_socket(int ifindex) {
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
@@ -251,15 +48,14 @@ int lldp_network_bind_raw_socket(int ifindex) {
return test_fd[0];
}
-static int lldp_handler_calls;
-static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
+static void lldp_handler (sd_lldp *lldp, void *userdata) {
lldp_handler_calls++;
}
static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
int r;
- r = sd_lldp_new(42, lldp);
+ r = sd_lldp_new(lldp, 42);
if (r < 0)
return r;
@@ -296,13 +92,8 @@ static int stop_lldp(sd_lldp *lldp) {
}
static void test_receive_basic_packet(sd_event *e) {
- sd_lldp *lldp;
- sd_lldp_packet **packets;
- uint8_t type, *data;
- uint16_t length, ttl;
- int dest_type;
- char *str;
- uint8_t frame[] = {
+
+ static const uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
@@ -319,51 +110,53 @@ static void test_receive_basic_packet(sd_event *e) {
0x00, 0x00 /* End Of LLDPDU */
};
+ sd_lldp *lldp;
+ sd_lldp_neighbor **neighbors;
+ uint8_t type;
+ const void *data;
+ uint16_t ttl;
+ size_t length;
+ const char *str;
+
lldp_handler_calls = 0;
assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
- assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
+ assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
assert_se(length == ETH_ALEN);
assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
- assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
+ assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
assert_se(length == 3);
assert_se(strneq((char *) data, "1/3", 3));
- assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
- assert_se(length == 4);
- assert_se(strneq(str, "Port", 4));
+ assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "Port"));
- assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
- assert_se(length == 3);
- assert_se(strneq(str, "SYS", 3));
+ assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0);
+ assert_se(streq(str, "SYS"));
- assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
- assert_se(length == 4); /* This is the real length in the TLV packet */
- assert_se(strneq(str, "foo", 3));
+ assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "foo"));
- assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
+ assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0);
assert_se(ttl == 120);
- assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
- assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
-
- sd_lldp_packet_unref(packets[0]);
- free(packets);
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_incomplete_packet(sd_event *e) {
sd_lldp *lldp;
- sd_lldp_packet **packets;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -383,18 +176,14 @@ static void test_receive_incomplete_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 0);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_oui_packet(sd_event *e) {
sd_lldp *lldp;
- sd_lldp_packet **packets;
- uint32_t id32;
- uint16_t id16, len;
- uint8_t flags;
- char *str;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -426,29 +215,30 @@ static void test_receive_oui_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
-
- assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
- assert_se(id16 == 0x1234);
-
- assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
- assert_se(flags == 1);
- assert_se(id16 == 0x7788);
-
- assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
- assert_se(id16 == 0x1234);
- assert_se(len == 6);
- assert_se(strneq(str, "Vlan51", 6));
-
- assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
- assert_se(id16 == 0x0102);
-
- assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
- assert_se(flags == 1);
- assert_se(id32 == 0x00140012);
-
- sd_lldp_packet_unref(packets[0]);
- free(packets);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
+
+ assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
+
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
@@ -456,7 +246,7 @@ static void test_receive_oui_packet(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
- test_parser();
+ log_set_max_level(LOG_DEBUG);
/* LLDP reception tests */
assert_se(sd_event_new(&e) == 0);