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