]> git.ipfire.org Git - thirdparty/systemd.git/blob - 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
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
23 #include <arpa/inet.h>
24 #include <net/ethernet.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "sd-event.h"
29 #include "sd-lldp.h"
30
31 #include "event-util.h"
32 #include "lldp-network.h"
33 #include "lldp-tlv.h"
34 #include "lldp.h"
35 #include "macro.h"
36 #include "string-util.h"
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
42 static int test_fd[2];
43
44 static struct ether_addr mac_addr = {
45 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
46 };
47
48 static int lldp_build_tlv_packet(tlv_packet **ret) {
49 _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
50 const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
51 struct ether_header ether = {
52 .ether_type = htons(ETHERTYPE_LLDP),
53 };
54
55 /* Append ethernet header */
56 memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
57 memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
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
111 static 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
136 static int lldp_parse_port_id_tlv(tlv_packet *m) {
137 _cleanup_free_ char *p = NULL;
138 char *str = NULL;
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
150 p = strndup(str, length-1);
151 assert_se(p);
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
164 static int lldp_parse_system_name_tlv(tlv_packet *m) {
165 _cleanup_free_ char *p = NULL;
166 char *str = NULL;
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
172 p = strndup(str, length);
173 assert_se(p);
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
182 static int lldp_parse_system_desc_tlv(tlv_packet *m) {
183 _cleanup_free_ char *p = NULL;
184 char *str = NULL;
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
190 p = strndup(str, length);
191 assert_se(p);
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
200 static 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
213 static 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
222 static 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
232 assert_se(lldp_get_destination_type(m) >= 0);
233
234 return 0;
235 }
236
237 static void test_parser(void) {
238 _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
239
240 /* form a packet */
241 lldp_build_tlv_packet(&tlv);
242 /* parse the packet */
243 tlv_packet_parse_pdu(tlv, tlv->length);
244 /* verify */
245 lldp_parse_tlv_packet(tlv, tlv->length);
246 }
247
248 int 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
255 static int lldp_handler_calls;
256 static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
257 lldp_handler_calls++;
258 }
259
260 static 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
282 static 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
299 static 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
365 static 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
392 static 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
457 int 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);
467
468 return 0;
469 }