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