]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-lldp.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd-network / test-lldp.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
ad1ad5c8
SS
2/***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Tom Gundersen
6 Copyright (C) 2014 Susant Sahani
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
07630cea
LP
22#include <arpa/inet.h>
23#include <net/ethernet.h>
ad1ad5c8 24#include <stdio.h>
ad1ad5c8 25#include <string.h>
34437b4f 26#include <unistd.h>
ad1ad5c8 27
6fd255cf 28#include "sd-event.h"
07630cea
LP
29#include "sd-lldp.h"
30
b5efdb8a 31#include "alloc-util.h"
3ffd4af2 32#include "fd-util.h"
6fd255cf 33#include "lldp-network.h"
07630cea
LP
34#include "macro.h"
35#include "string-util.h"
ad1ad5c8
SS
36
37#define TEST_LLDP_PORT "em1"
38#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
39#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
40
34437b4f
LP
41static int test_fd[2] = { -1, -1 };
42static int lldp_handler_calls;
6fd255cf
BG
43
44int lldp_network_bind_raw_socket(int ifindex) {
45 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
46 return -errno;
47
48 return test_fd[0];
49}
50
90dffb22 51static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
6fd255cf
BG
52 lldp_handler_calls++;
53}
54
ccf86354 55static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
6fd255cf
BG
56 int r;
57
fc6a313b 58 r = sd_lldp_new(lldp);
bd8650e9 59 if (r < 0)
6fd255cf
BG
60 return r;
61
fc6a313b 62 r = sd_lldp_set_ifindex(*lldp, 42);
bd8650e9 63 if (r < 0)
6fd255cf
BG
64 return r;
65
66 r = sd_lldp_set_callback(*lldp, cb, cb_data);
bd8650e9 67 if (r < 0)
6fd255cf
BG
68 return r;
69
fc6a313b
LP
70 r = sd_lldp_attach_event(*lldp, e, 0);
71 if (r < 0)
72 return r;
73
6fd255cf 74 r = sd_lldp_start(*lldp);
bd8650e9 75 if (r < 0)
6fd255cf
BG
76 return r;
77
78 return 0;
79}
80
81static int stop_lldp(sd_lldp *lldp) {
82 int r;
83
84 r = sd_lldp_stop(lldp);
bd8650e9 85 if (r < 0)
6fd255cf
BG
86 return r;
87
88 r = sd_lldp_detach_event(lldp);
bd8650e9 89 if (r < 0)
6fd255cf
BG
90 return r;
91
4afd3348 92 sd_lldp_unref(lldp);
6fd255cf
BG
93 safe_close(test_fd[1]);
94
95 return 0;
96}
97
98static void test_receive_basic_packet(sd_event *e) {
34437b4f
LP
99
100 static const uint8_t frame[] = {
6fd255cf 101 /* Ethernet header */
13e785f7 102 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
6fd255cf
BG
103 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
104 0x88, 0xcc, /* Ethertype */
105 /* LLDP mandatory TLVs */
106 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
107 0x03, 0x04, 0x05,
108 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
13e785f7 109 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
6fd255cf
BG
110 /* LLDP optional TLVs */
111 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
112 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
113 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
114 0x00, 0x00 /* End Of LLDPDU */
115 };
116
34437b4f
LP
117 sd_lldp *lldp;
118 sd_lldp_neighbor **neighbors;
119 uint8_t type;
120 const void *data;
121 uint16_t ttl;
122 size_t length;
123 const char *str;
124
6fd255cf
BG
125 lldp_handler_calls = 0;
126 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
127
128 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
129 sd_event_run(e, 0);
130 assert_se(lldp_handler_calls == 1);
34437b4f 131 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
6fd255cf 132
34437b4f 133 assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
6afa6767 134 assert_se(type == SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
6fd255cf
BG
135 assert_se(length == ETH_ALEN);
136 assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
137
34437b4f 138 assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
6afa6767 139 assert_se(type == SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME);
6fd255cf
BG
140 assert_se(length == 3);
141 assert_se(strneq((char *) data, "1/3", 3));
142
34437b4f
LP
143 assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0);
144 assert_se(streq(str, "Port"));
6fd255cf 145
34437b4f
LP
146 assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0);
147 assert_se(streq(str, "SYS"));
6fd255cf 148
34437b4f
LP
149 assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0);
150 assert_se(streq(str, "foo"));
6fd255cf 151
34437b4f 152 assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0);
6fd255cf
BG
153 assert_se(ttl == 120);
154
34437b4f
LP
155 sd_lldp_neighbor_unref(neighbors[0]);
156 free(neighbors);
6fd255cf
BG
157
158 assert_se(stop_lldp(lldp) == 0);
159}
160
161static void test_receive_incomplete_packet(sd_event *e) {
162 sd_lldp *lldp;
34437b4f 163 sd_lldp_neighbor **neighbors;
6fd255cf
BG
164 uint8_t frame[] = {
165 /* Ethernet header */
13e785f7 166 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
6fd255cf
BG
167 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
168 0x88, 0xcc, /* Ethertype */
169 /* LLDP mandatory TLVs */
170 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
171 0x03, 0x04, 0x05,
172 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
173 /* Missing TTL */
174 0x00, 0x00 /* End Of LLDPDU */
175 };
176
177 lldp_handler_calls = 0;
178 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
179
180 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
181 sd_event_run(e, 0);
182 assert_se(lldp_handler_calls == 0);
34437b4f 183 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0);
6fd255cf
BG
184
185 assert_se(stop_lldp(lldp) == 0);
186}
187
188static void test_receive_oui_packet(sd_event *e) {
189 sd_lldp *lldp;
34437b4f 190 sd_lldp_neighbor **neighbors;
6fd255cf
BG
191 uint8_t frame[] = {
192 /* Ethernet header */
13e785f7 193 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
6fd255cf
BG
194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
195 0x88, 0xcc, /* Ethertype */
196 /* LLDP mandatory TLVs */
197 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
198 0x03, 0x04, 0x05,
199 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
13e785f7 200 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
6fd255cf
BG
201 /* LLDP optional TLVs */
202 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
203 0x12, 0x34,
204 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
205 0x01, 0x77, 0x88,
206 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
207 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
208 0x6e, 0x35, 0x31,
209 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
210 0x01, 0x02,
211 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
212 0x01, 0x00, 0x14, 0x00, 0x12,
213 0x00, 0x00 /* End of LLDPDU */
214 };
215
216 lldp_handler_calls = 0;
217 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
218
219 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
220 sd_event_run(e, 0);
221 assert_se(lldp_handler_calls == 1);
34437b4f
LP
222 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
223
224 assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
6afa6767 225 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_CHASSIS_ID) > 0);
34437b4f 226 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 227 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_PORT_ID) > 0);
34437b4f 228 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 229 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_TTL) > 0);
34437b4f 230 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 231 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
34437b4f 232 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 233 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
34437b4f 234 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 235 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
34437b4f 236 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 237 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
34437b4f 238 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 239 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
34437b4f 240 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
6afa6767 241 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0);
34437b4f
LP
242 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
243
244 sd_lldp_neighbor_unref(neighbors[0]);
245 free(neighbors);
6fd255cf
BG
246
247 assert_se(stop_lldp(lldp) == 0);
248}
249
250int main(int argc, char *argv[]) {
4afd3348 251 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
6fd255cf 252
34437b4f 253 log_set_max_level(LOG_DEBUG);
6fd255cf
BG
254
255 /* LLDP reception tests */
256 assert_se(sd_event_new(&e) == 0);
257 test_receive_basic_packet(e);
258 test_receive_incomplete_packet(e);
259 test_receive_oui_packet(e);
ad1ad5c8
SS
260
261 return 0;
262}