]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-lldp.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / libsystemd-network / test-lldp.c
CommitLineData
ad1ad5c8
SS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright (C) 2014 Tom Gundersen
7 Copyright (C) 2014 Susant Sahani
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
07630cea
LP
23#include <arpa/inet.h>
24#include <net/ethernet.h>
ad1ad5c8 25#include <stdio.h>
ad1ad5c8 26#include <string.h>
ad1ad5c8 27
6fd255cf 28#include "sd-event.h"
07630cea
LP
29#include "sd-lldp.h"
30
6fd255cf 31#include "event-util.h"
6fd255cf 32#include "lldp-network.h"
07630cea
LP
33#include "lldp-tlv.h"
34#include "lldp.h"
35#include "macro.h"
36#include "string-util.h"
ad1ad5c8
SS
37
38#define TEST_LLDP_PORT "em1"
39#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
40#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
41
6fd255cf
BG
42static int test_fd[2];
43
ad1ad5c8
SS
44static struct ether_addr mac_addr = {
45 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
46};
47
48static int lldp_build_tlv_packet(tlv_packet **ret) {
176c355b 49 _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
ad1ad5c8 50 const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
804138a0
LP
51 struct ether_header ether = {
52 .ether_type = htons(ETHERTYPE_LLDP),
53 };
ad1ad5c8
SS
54
55 /* Append ethernet header */
ad1ad5c8
SS
56 memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
57 memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
ad1ad5c8
SS
58
59 assert_se(tlv_packet_new(&m) >= 0);
60
61 assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
62
63 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
64
65 assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
66 assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
67
68 assert_se(lldp_tlv_packet_close_container(m) >= 0);
69
70 /* port name */
71 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
72
73 assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
74 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
75
76 assert_se(lldp_tlv_packet_close_container(m) >= 0);
77
78 /* ttl */
79 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
80
81 assert_se(tlv_packet_append_u16(m, 170) >= 0);
82
83 assert_se(lldp_tlv_packet_close_container(m) >= 0);
84
85 /* system name */
86 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
87
88 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
89 strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
90 assert_se(lldp_tlv_packet_close_container(m) >= 0);
91
92 /* system descrition */
93 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
94
95 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
96 strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
97
98 assert_se(lldp_tlv_packet_close_container(m) >= 0);
99
100 /* Mark end of packet */
101 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
102 assert_se(lldp_tlv_packet_close_container(m) >= 0);
103
104 *ret = m;
105
106 m = NULL;
107
108 return 0;
109}
110
111static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
112 uint8_t *p, subtype;
113 uint16_t length;
114
115 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
116 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
117
118 switch (subtype) {
119 case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
120
121 *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
122 assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
123
124 assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
125
126 break;
127 default:
128 assert_not_reached("Unhandled option");
129 }
130
131 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
132
133 return 0;
134}
135
136static int lldp_parse_port_id_tlv(tlv_packet *m) {
33256079
LP
137 _cleanup_free_ char *p = NULL;
138 char *str = NULL;
ad1ad5c8
SS
139 uint16_t length;
140 uint8_t subtype;
141
142 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
143
144 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
145
146 switch (subtype) {
147 case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
148 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
149
b762fbd1 150 p = strndup(str, length-1);
889cec8d 151 assert_se(p);
ad1ad5c8
SS
152
153 assert_se(streq(p, TEST_LLDP_PORT) == 1);
154 break;
155 default:
156 assert_not_reached("Unhandled option");
157 }
158
159 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
160
161 return 0;
162}
163
164static int lldp_parse_system_name_tlv(tlv_packet *m) {
33256079
LP
165 _cleanup_free_ char *p = NULL;
166 char *str = NULL;
ad1ad5c8
SS
167 uint16_t length;
168
169 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
170 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
171
b762fbd1 172 p = strndup(str, length);
2e1a569b 173 assert_se(p);
ad1ad5c8
SS
174
175 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
176
177 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
178
179 return 1;
180}
181
182static int lldp_parse_system_desc_tlv(tlv_packet *m) {
33256079
LP
183 _cleanup_free_ char *p = NULL;
184 char *str = NULL;
ad1ad5c8
SS
185 uint16_t length;
186
187 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
188 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
189
b762fbd1 190 p = strndup(str, length);
889cec8d 191 assert_se(p);
ad1ad5c8
SS
192
193 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
194
195 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
196
197 return 0;
198}
199
200static int lldp_parse_ttl_tlv(tlv_packet *m) {
201 uint16_t ttl;
202
203 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
204 assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
205
206 assert_se(ttl == 170);
207
208 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
209
210 return 0;
211}
212
4fc6de5d
BG
213static int lldp_get_destination_type(tlv_packet *m) {
214 int dest;
215
216 assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
217 assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
218
219 return 0;
220}
221
ad1ad5c8
SS
222static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
223 uint8_t subtype;
224
225 assert_se(tlv_packet_parse_pdu(m, len) >= 0);
226 assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
227 assert_se(lldp_parse_port_id_tlv(m) >= 0);
228 assert_se(lldp_parse_system_name_tlv(m) >= 0);
229 assert_se(lldp_parse_ttl_tlv(m) >= 0);
230 assert_se(lldp_parse_system_desc_tlv(m) >= 0);
231
4fc6de5d
BG
232 assert_se(lldp_get_destination_type(m) >= 0);
233
ad1ad5c8
SS
234 return 0;
235}
236
6fd255cf 237static void test_parser(void) {
176c355b 238 _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
ad1ad5c8
SS
239
240 /* form a packet */
241 lldp_build_tlv_packet(&tlv);
ad1ad5c8
SS
242 /* parse the packet */
243 tlv_packet_parse_pdu(tlv, tlv->length);
ad1ad5c8
SS
244 /* verify */
245 lldp_parse_tlv_packet(tlv, tlv->length);
6fd255cf
BG
246}
247
248int lldp_network_bind_raw_socket(int ifindex) {
249 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
250 return -errno;
251
252 return test_fd[0];
253}
254
255static int lldp_handler_calls;
256static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
257 lldp_handler_calls++;
258}
259
260static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
261 int r;
262
263 r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
264 if (r)
265 return r;
266
267 r = sd_lldp_attach_event(*lldp, e, 0);
268 if (r)
269 return r;
270
271 r = sd_lldp_set_callback(*lldp, cb, cb_data);
272 if (r)
273 return r;
274
275 r = sd_lldp_start(*lldp);
276 if (r)
277 return r;
278
279 return 0;
280}
281
282static int stop_lldp(sd_lldp *lldp) {
283 int r;
284
285 r = sd_lldp_stop(lldp);
286 if (r)
287 return r;
288
289 r = sd_lldp_detach_event(lldp);
290 if (r)
291 return r;
292
293 sd_lldp_free(lldp);
294 safe_close(test_fd[1]);
295
296 return 0;
297}
298
299static void test_receive_basic_packet(sd_event *e) {
300 sd_lldp *lldp;
301 sd_lldp_packet **packets;
302 uint8_t type, *data;
303 uint16_t length, ttl;
304 int dest_type;
305 char *str;
306 uint8_t frame[] = {
307 /* Ethernet header */
308 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
309 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
310 0x88, 0xcc, /* Ethertype */
311 /* LLDP mandatory TLVs */
312 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
313 0x03, 0x04, 0x05,
314 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
315 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
316 /* LLDP optional TLVs */
317 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
318 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
319 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
320 0x00, 0x00 /* End Of LLDPDU */
321 };
322
323 lldp_handler_calls = 0;
324 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
325
326 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
327 sd_event_run(e, 0);
328 assert_se(lldp_handler_calls == 1);
329 assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
330
331 assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
332 assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
333 assert_se(length == ETH_ALEN);
334 assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
335
336 assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
337 assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
338 assert_se(length == 3);
339 assert_se(strneq((char *) data, "1/3", 3));
340
341 assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
342 assert_se(length == 4);
343 assert_se(strneq(str, "Port", 4));
344
345 assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
346 assert_se(length == 3);
347 assert_se(strneq(str, "SYS", 3));
348
349 assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
350 assert_se(length == 4); /* This is the real length in the TLV packet */
351 assert_se(strneq(str, "foo", 3));
352
353 assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
354 assert_se(ttl == 120);
355
356 assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
357 assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
358
359 sd_lldp_packet_unref(packets[0]);
360 free(packets);
361
362 assert_se(stop_lldp(lldp) == 0);
363}
364
365static void test_receive_incomplete_packet(sd_event *e) {
366 sd_lldp *lldp;
367 sd_lldp_packet **packets;
368 uint8_t frame[] = {
369 /* Ethernet header */
370 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
371 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
372 0x88, 0xcc, /* Ethertype */
373 /* LLDP mandatory TLVs */
374 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
375 0x03, 0x04, 0x05,
376 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
377 /* Missing TTL */
378 0x00, 0x00 /* End Of LLDPDU */
379 };
380
381 lldp_handler_calls = 0;
382 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
383
384 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
385 sd_event_run(e, 0);
386 assert_se(lldp_handler_calls == 0);
387 assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
388
389 assert_se(stop_lldp(lldp) == 0);
390}
391
392static void test_receive_oui_packet(sd_event *e) {
393 sd_lldp *lldp;
394 sd_lldp_packet **packets;
395 uint32_t id32;
396 uint16_t id16, len;
397 uint8_t flags;
398 char *str;
399 uint8_t frame[] = {
400 /* Ethernet header */
401 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
402 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
403 0x88, 0xcc, /* Ethertype */
404 /* LLDP mandatory TLVs */
405 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
406 0x03, 0x04, 0x05,
407 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
408 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
409 /* LLDP optional TLVs */
410 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
411 0x12, 0x34,
412 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
413 0x01, 0x77, 0x88,
414 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
415 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
416 0x6e, 0x35, 0x31,
417 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
418 0x01, 0x02,
419 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
420 0x01, 0x00, 0x14, 0x00, 0x12,
421 0x00, 0x00 /* End of LLDPDU */
422 };
423
424 lldp_handler_calls = 0;
425 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
426
427 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
428 sd_event_run(e, 0);
429 assert_se(lldp_handler_calls == 1);
430 assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
431
432 assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
433 assert_se(id16 == 0x1234);
434
435 assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
436 assert_se(flags == 1);
437 assert_se(id16 == 0x7788);
438
439 assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
440 assert_se(id16 == 0x1234);
441 assert_se(len == 6);
442 assert_se(strneq(str, "Vlan51", 6));
443
444 assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
445 assert_se(id16 == 0x0102);
446
447 assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
448 assert_se(flags == 1);
449 assert_se(id32 == 0x00140012);
450
451 sd_lldp_packet_unref(packets[0]);
452 free(packets);
453
454 assert_se(stop_lldp(lldp) == 0);
455}
456
457int main(int argc, char *argv[]) {
458 _cleanup_event_unref_ sd_event *e = NULL;
459
460 test_parser();
461
462 /* LLDP reception tests */
463 assert_se(sd_event_new(&e) == 0);
464 test_receive_basic_packet(e);
465 test_receive_incomplete_packet(e);
466 test_receive_oui_packet(e);
ad1ad5c8
SS
467
468 return 0;
469}