]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-lldp.c
util-lib: split out allocation calls into alloc-util.[ch]
[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 "alloc-util.h"
32 #include "event-util.h"
33 #include "fd-util.h"
34 #include "lldp-network.h"
35 #include "lldp-tlv.h"
36 #include "lldp.h"
37 #include "macro.h"
38 #include "string-util.h"
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
44 static int test_fd[2];
45
46 static struct ether_addr mac_addr = {
47 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
48 };
49
50 static int lldp_build_tlv_packet(tlv_packet **ret) {
51 _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
52 const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
53 struct ether_header ether = {
54 .ether_type = htons(ETHERTYPE_LLDP),
55 };
56
57 /* Append ethernet header */
58 memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
59 memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
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
113 static 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
138 static int lldp_parse_port_id_tlv(tlv_packet *m) {
139 _cleanup_free_ char *p = NULL;
140 char *str = NULL;
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
152 p = strndup(str, length-1);
153 assert_se(p);
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
166 static int lldp_parse_system_name_tlv(tlv_packet *m) {
167 _cleanup_free_ char *p = NULL;
168 char *str = NULL;
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
174 p = strndup(str, length);
175 assert_se(p);
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
184 static int lldp_parse_system_desc_tlv(tlv_packet *m) {
185 _cleanup_free_ char *p = NULL;
186 char *str = NULL;
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
192 p = strndup(str, length);
193 assert_se(p);
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
202 static 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
215 static 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
224 static 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
234 assert_se(lldp_get_destination_type(m) >= 0);
235
236 return 0;
237 }
238
239 static void test_parser(void) {
240 _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
241
242 /* form a packet */
243 lldp_build_tlv_packet(&tlv);
244 /* parse the packet */
245 tlv_packet_parse_pdu(tlv, tlv->length);
246 /* verify */
247 lldp_parse_tlv_packet(tlv, tlv->length);
248 }
249
250 int 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
257 static int lldp_handler_calls;
258 static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
259 lldp_handler_calls++;
260 }
261
262 static 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
284 static 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
301 static 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
367 static 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
394 static 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
459 int 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);
469
470 return 0;
471 }