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