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