mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
@@ -315,6 +315,16 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* IEEE 802.1: VLAN ID */
|
||||
if (memcmp(p, SD_LLDP_OUI_802_1_VLAN_ID, sizeof(SD_LLDP_OUI_802_1_VLAN_ID)) == 0) {
|
||||
if (length != (sizeof(SD_LLDP_OUI_802_1_VLAN_ID) + sizeof(uint16_t)))
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Found 802.1 VLAN ID TLV with wrong length, ignoring.");
|
||||
|
||||
n->has_port_vlan_id = true;
|
||||
n->port_vlan_id = unaligned_read_be16(p + sizeof(SD_LLDP_OUI_802_1_VLAN_ID));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -632,6 +642,17 @@ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_port_vlan_id(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->has_port_vlan_id)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->port_vlan_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
@@ -769,6 +790,8 @@ int lldp_neighbor_build_json(sd_lldp_neighbor *n, sd_json_variant **ret) {
|
||||
*system_name = NULL, *system_description = NULL;
|
||||
uint16_t cc = 0;
|
||||
bool valid_cc;
|
||||
uint16_t vlanid = 0;
|
||||
bool valid_vlanid;
|
||||
|
||||
assert(n);
|
||||
assert(ret);
|
||||
@@ -780,6 +803,7 @@ int lldp_neighbor_build_json(sd_lldp_neighbor *n, sd_json_variant **ret) {
|
||||
(void) sd_lldp_neighbor_get_system_description(n, &system_description);
|
||||
|
||||
valid_cc = sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0;
|
||||
valid_vlanid = sd_lldp_neighbor_get_port_vlan_id(n, &vlanid) >= 0;
|
||||
|
||||
return sd_json_buildo(
|
||||
ret,
|
||||
@@ -790,5 +814,6 @@ int lldp_neighbor_build_json(sd_lldp_neighbor *n, sd_json_variant **ret) {
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("PortDescription", port_description),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemName", system_name),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemDescription", system_description),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(valid_cc, "EnabledCapabilities", SD_JSON_BUILD_UNSIGNED(cc)));
|
||||
SD_JSON_BUILD_PAIR_CONDITION(valid_cc, "EnabledCapabilities", SD_JSON_BUILD_UNSIGNED(cc)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(valid_vlanid, "VlanID", SD_JSON_BUILD_UNSIGNED(vlanid)));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "json-util.h"
|
||||
#include "lldp-neighbor.h"
|
||||
#include "lldp-network.h"
|
||||
#include "tests.h"
|
||||
|
||||
@@ -358,6 +360,61 @@ static void test_multiple_neighbors_sorted(sd_event *e) {
|
||||
assert_se(stop_lldp_rx(lldp_rx) == 0);
|
||||
}
|
||||
|
||||
static void test_receive_oui_vlanid_packet(sd_event *e) {
|
||||
sd_lldp_rx *lldp_rx;
|
||||
sd_lldp_neighbor **neighbors;
|
||||
sd_json_variant *v;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *neighbor_json = NULL;
|
||||
static const uint8_t frame[] = {
|
||||
/* Ethernet header */
|
||||
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
|
||||
0x88, 0xcc, /* Ethertype */
|
||||
/* LLDP mandatory TLVs */
|
||||
0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
|
||||
0x03, 0x04, 0x05,
|
||||
0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
|
||||
0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
|
||||
/* LLDP optional TLVs */
|
||||
0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
|
||||
0x12, 0x34,
|
||||
0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
|
||||
0x01, 0x77, 0x88,
|
||||
0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
|
||||
0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
|
||||
0x6e, 0x35, 0x31,
|
||||
0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
|
||||
0x01, 0x02,
|
||||
0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
|
||||
0x01, 0x00, 0x14, 0x00, 0x12,
|
||||
0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, /* 802.3 Power via MDI: PSE, MDI enabled */
|
||||
0x07, 0x01, 0x00,
|
||||
0x00, 0x00 /* End of LLDPDU */
|
||||
};
|
||||
uint16_t vlanid;
|
||||
|
||||
lldp_rx_handler_calls = 0;
|
||||
ASSERT_OK(start_lldp_rx(&lldp_rx, e, lldp_rx_handler, NULL));
|
||||
|
||||
ASSERT_OK_EQ_ERRNO(write(test_fd[1], frame, sizeof(frame)), (ssize_t)sizeof(frame));
|
||||
ASSERT_OK(sd_event_run(e, 0));
|
||||
ASSERT_EQ(lldp_rx_handler_calls, 1);
|
||||
ASSERT_OK_EQ(sd_lldp_rx_get_neighbors(lldp_rx, &neighbors), 1);
|
||||
|
||||
ASSERT_OK(sd_lldp_neighbor_get_port_vlan_id(neighbors[0], &vlanid));
|
||||
ASSERT_EQ(vlanid, 0x1234);
|
||||
|
||||
ASSERT_OK(lldp_neighbor_build_json(neighbors[0], &neighbor_json));
|
||||
ASSERT_NOT_NULL(v = sd_json_variant_by_key(neighbor_json, "VlanID"));
|
||||
ASSERT_EQ(sd_json_variant_type(v), SD_JSON_VARIANT_UNSIGNED);
|
||||
ASSERT_EQ(sd_json_variant_unsigned(v), UINT64_C(0x1234));
|
||||
|
||||
sd_lldp_neighbor_unref(neighbors[0]);
|
||||
free(neighbors);
|
||||
|
||||
ASSERT_OK(stop_lldp_rx(lldp_rx));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
|
||||
@@ -369,6 +426,7 @@ int main(int argc, char *argv[]) {
|
||||
test_receive_incomplete_packet(e);
|
||||
test_receive_oui_packet(e);
|
||||
test_multiple_neighbors_sorted(e);
|
||||
test_receive_oui_vlanid_packet(e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef struct LLDPNeighborInfo {
|
||||
const char *system_name;
|
||||
const char *system_description;
|
||||
uint16_t capabilities;
|
||||
uint16_t vlan_id;
|
||||
} LLDPNeighborInfo;
|
||||
|
||||
static const sd_json_dispatch_field lldp_neighbor_dispatch_table[] = {
|
||||
@@ -53,6 +54,7 @@ static const sd_json_dispatch_field lldp_neighbor_dispatch_table[] = {
|
||||
{ "SystemName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_name), 0 },
|
||||
{ "SystemDescription", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_description), 0 },
|
||||
{ "EnabledCapabilities", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(LLDPNeighborInfo, capabilities), 0 },
|
||||
{ "VlanID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(LLDPNeighborInfo, vlan_id), 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
SD_VARLINK_DEFINE_FIELD(PortDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_DEFINE_FIELD(SystemName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_DEFINE_FIELD(SystemDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
||||
SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_DEFINE_FIELD(VlanID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
||||
|
||||
static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
LLDPNeighborsByInterface,
|
||||
|
||||
@@ -84,6 +84,7 @@ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret)
|
||||
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
int sd_lldp_neighbor_get_port_vlan_id(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
|
||||
/* Low-level, iterative TLV access. This is for everything else, it iteratively goes through all available TLVs
|
||||
* (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
|
||||
|
||||
@@ -87,7 +87,13 @@ enum {
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
|
||||
|
||||
#define SD_LLDP_OUI_802_1 (const uint8_t[]) { 0x00, 0x80, 0xc2 }
|
||||
#define _SD_LLDP_OUI_802_1 0x00, 0x80, 0xc2
|
||||
#define SD_LLDP_OUI_802_1 (const uint8_t[]) { _SD_LLDP_OUI_802_1 }
|
||||
|
||||
#define SD_LLDP_OUI_802_1_SUBTYPE_VLAN_ID 0x01
|
||||
#define SD_LLDP_OUI_802_1_VLAN_ID \
|
||||
(const uint8_t[]) { _SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_ID }
|
||||
|
||||
#define SD_LLDP_OUI_802_3 (const uint8_t[]) { 0x00, 0x12, 0x0f }
|
||||
|
||||
#define _SD_LLDP_OUI_IANA 0x00, 0x00, 0x5E
|
||||
|
||||
Reference in New Issue
Block a user