]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-lldp.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd-network / test-lldp.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Tom Gundersen
6 Copyright (C) 2014 Susant Sahani
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <arpa/inet.h>
23 #include <net/ethernet.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "sd-event.h"
29 #include "sd-lldp.h"
30
31 #include "alloc-util.h"
32 #include "fd-util.h"
33 #include "lldp-network.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] = { -1, -1 };
42 static int lldp_handler_calls;
43
44 int lldp_network_bind_raw_socket(int ifindex) {
45 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
46 return -errno;
47
48 return test_fd[0];
49 }
50
51 static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
52 lldp_handler_calls++;
53 }
54
55 static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
56 int r;
57
58 r = sd_lldp_new(lldp);
59 if (r < 0)
60 return r;
61
62 r = sd_lldp_set_ifindex(*lldp, 42);
63 if (r < 0)
64 return r;
65
66 r = sd_lldp_set_callback(*lldp, cb, cb_data);
67 if (r < 0)
68 return r;
69
70 r = sd_lldp_attach_event(*lldp, e, 0);
71 if (r < 0)
72 return r;
73
74 r = sd_lldp_start(*lldp);
75 if (r < 0)
76 return r;
77
78 return 0;
79 }
80
81 static int stop_lldp(sd_lldp *lldp) {
82 int r;
83
84 r = sd_lldp_stop(lldp);
85 if (r < 0)
86 return r;
87
88 r = sd_lldp_detach_event(lldp);
89 if (r < 0)
90 return r;
91
92 sd_lldp_unref(lldp);
93 safe_close(test_fd[1]);
94
95 return 0;
96 }
97
98 static void test_receive_basic_packet(sd_event *e) {
99
100 static const uint8_t frame[] = {
101 /* Ethernet header */
102 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
103 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
104 0x88, 0xcc, /* Ethertype */
105 /* LLDP mandatory TLVs */
106 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
107 0x03, 0x04, 0x05,
108 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
109 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
110 /* LLDP optional TLVs */
111 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
112 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
113 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
114 0x00, 0x00 /* End Of LLDPDU */
115 };
116
117 sd_lldp *lldp;
118 sd_lldp_neighbor **neighbors;
119 uint8_t type;
120 const void *data;
121 uint16_t ttl;
122 size_t length;
123 const char *str;
124
125 lldp_handler_calls = 0;
126 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
127
128 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
129 sd_event_run(e, 0);
130 assert_se(lldp_handler_calls == 1);
131 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
132
133 assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
134 assert_se(type == SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
135 assert_se(length == ETH_ALEN);
136 assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
137
138 assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
139 assert_se(type == SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME);
140 assert_se(length == 3);
141 assert_se(strneq((char *) data, "1/3", 3));
142
143 assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0);
144 assert_se(streq(str, "Port"));
145
146 assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0);
147 assert_se(streq(str, "SYS"));
148
149 assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0);
150 assert_se(streq(str, "foo"));
151
152 assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0);
153 assert_se(ttl == 120);
154
155 sd_lldp_neighbor_unref(neighbors[0]);
156 free(neighbors);
157
158 assert_se(stop_lldp(lldp) == 0);
159 }
160
161 static void test_receive_incomplete_packet(sd_event *e) {
162 sd_lldp *lldp;
163 sd_lldp_neighbor **neighbors;
164 uint8_t frame[] = {
165 /* Ethernet header */
166 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
167 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
168 0x88, 0xcc, /* Ethertype */
169 /* LLDP mandatory TLVs */
170 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
171 0x03, 0x04, 0x05,
172 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
173 /* Missing TTL */
174 0x00, 0x00 /* End Of LLDPDU */
175 };
176
177 lldp_handler_calls = 0;
178 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
179
180 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
181 sd_event_run(e, 0);
182 assert_se(lldp_handler_calls == 0);
183 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0);
184
185 assert_se(stop_lldp(lldp) == 0);
186 }
187
188 static void test_receive_oui_packet(sd_event *e) {
189 sd_lldp *lldp;
190 sd_lldp_neighbor **neighbors;
191 uint8_t frame[] = {
192 /* Ethernet header */
193 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
195 0x88, 0xcc, /* Ethertype */
196 /* LLDP mandatory TLVs */
197 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
198 0x03, 0x04, 0x05,
199 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
200 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
201 /* LLDP optional TLVs */
202 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
203 0x12, 0x34,
204 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
205 0x01, 0x77, 0x88,
206 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
207 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
208 0x6e, 0x35, 0x31,
209 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
210 0x01, 0x02,
211 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
212 0x01, 0x00, 0x14, 0x00, 0x12,
213 0x00, 0x00 /* End of LLDPDU */
214 };
215
216 lldp_handler_calls = 0;
217 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
218
219 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
220 sd_event_run(e, 0);
221 assert_se(lldp_handler_calls == 1);
222 assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
223
224 assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
225 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_CHASSIS_ID) > 0);
226 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
227 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_PORT_ID) > 0);
228 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
229 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_TTL) > 0);
230 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
231 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
232 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
233 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
234 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
235 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
236 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
237 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
238 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
239 assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
240 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
241 assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0);
242 assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
243
244 sd_lldp_neighbor_unref(neighbors[0]);
245 free(neighbors);
246
247 assert_se(stop_lldp(lldp) == 0);
248 }
249
250 int main(int argc, char *argv[]) {
251 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
252
253 log_set_max_level(LOG_DEBUG);
254
255 /* LLDP reception tests */
256 assert_se(sd_event_new(&e) == 0);
257 test_receive_basic_packet(e);
258 test_receive_incomplete_packet(e);
259 test_receive_oui_packet(e);
260
261 return 0;
262 }