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