]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-rtnl/test-rtnl.c
rtnl: support interleaved reading and writing, and rewind
[thirdparty/systemd.git] / src / libsystemd-rtnl / test-rtnl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 <linux/rtnetlink.h>
23 #include <netinet/ether.h>
24
25 #include "util.h"
26 #include "macro.h"
27 #include "sd-rtnl.h"
28 #include "socket-util.h"
29 #include "rtnl-util.h"
30 #include "event-util.h"
31
32 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
33 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
34 uint16_t type;
35 const char *mac = "98:fe:94:3f:c6:18", *name = "test";
36 unsigned int mtu = 1450;
37 void *data;
38
39 /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
40 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &message) >= 0);
41 assert(sd_rtnl_message_append(message, IFLA_IFNAME, name) >= 0);
42 assert(sd_rtnl_message_append(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
43 assert(sd_rtnl_message_append(message, IFLA_MTU, &mtu) >= 0);
44
45 assert(sd_rtnl_message_read(message, &type, &data) > 0);
46 assert(type == IFLA_IFNAME);
47 assert(streq(name, (char *) data));
48
49 assert(sd_rtnl_message_read(message, &type, &data) > 0);
50 assert(type == IFLA_ADDRESS);
51 assert(streq(mac, ether_ntoa(data)));
52
53 assert(sd_rtnl_message_read(message, &type, &data) > 0);
54 assert(type == IFLA_MTU);
55 assert(mtu == *(unsigned int *) data);
56
57 assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
58 }
59
60 static void test_route(void) {
61 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
62 uint32_t addr = htonl(INADDR_LOOPBACK);
63 uint32_t index = 2;
64 uint16_t type;
65 void *data;
66 int r;
67
68 r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, &req);
69 if (r < 0) {
70 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
71 return;
72 }
73
74 r = sd_rtnl_message_append(req, RTA_GATEWAY, &addr);
75 if (r < 0) {
76 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
77 return;
78 }
79
80 r = sd_rtnl_message_append(req, RTA_OIF, &index);
81 if (r < 0) {
82 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
83 return;
84 }
85
86 assert(sd_rtnl_message_read(req, &type, &data) > 0);
87 assert(type == RTA_GATEWAY);
88 assert(*(uint32_t *) data == addr);
89
90 assert(sd_rtnl_message_read(req, &type, &data) > 0);
91 assert(type == RTA_OIF);
92 assert(*(uint32_t *) data == index);
93 }
94
95 static void test_multiple(void) {
96 sd_rtnl *rtnl1, *rtnl2;
97
98 assert(sd_rtnl_open(0, &rtnl1) >= 0);
99 assert(sd_rtnl_open(0, &rtnl2) >= 0);
100
101 rtnl1 = sd_rtnl_unref(rtnl1);
102 rtnl2 = sd_rtnl_unref(rtnl2);
103 }
104
105 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
106 void *data;
107 uint16_t type;
108 char *ifname = userdata;
109
110 assert(rtnl);
111 assert(m);
112
113 log_info("got link info about %s", ifname);
114 free(ifname);
115
116 while (sd_rtnl_message_read(m, &type, &data) > 0) {
117 switch (type) {
118 // case IFLA_MTU:
119 // assert(*(unsigned int *) data == 65536);
120 // break;
121 // case IFLA_QDISC:
122 // assert(streq((char *) data, "noqueue"));
123 // break;
124 case IFLA_IFNAME:
125 assert(streq((char *) data, "lo"));
126 break;
127 }
128 }
129
130 return 1;
131 }
132
133 static void test_event_loop(int ifindex) {
134 _cleanup_event_unref_ sd_event *event = NULL;
135 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
136 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
137 char *ifname;
138
139 ifname = strdup("lo2");
140 assert(ifname);
141
142 assert(sd_rtnl_open(0, &rtnl) >= 0);
143 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
144
145 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
146
147 assert(sd_event_default(&event) >= 0);
148
149 assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
150
151 assert(sd_event_run(event, 0) >= 0);
152
153 assert(sd_rtnl_detach_event(rtnl) >= 0);
154 }
155
156 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
157 int *counter = userdata;
158
159 (*counter) --;
160
161 log_info("got reply, %d left in pipe", *counter);
162
163 return sd_rtnl_message_get_errno(m);
164 }
165
166 static void test_async(int ifindex) {
167 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
168 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
169 uint32_t serial;
170 char *ifname;
171
172 ifname = strdup("lo");
173 assert(ifname);
174
175 assert(sd_rtnl_open(0, &rtnl) >= 0);
176
177 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
178
179 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
180
181 assert(sd_rtnl_wait(rtnl, 0) >= 0);
182 assert(sd_rtnl_process(rtnl, &r) >= 0);
183 }
184
185 static void test_pipe(int ifindex) {
186 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
187 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
188 int counter = 0;
189
190 assert(sd_rtnl_open(0, &rtnl) >= 0);
191
192 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m1) >= 0);
193 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m2) >= 0);
194
195 counter ++;
196 assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
197
198 counter ++;
199 assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
200
201 while (counter > 0) {
202 assert(sd_rtnl_wait(rtnl, 0) >= 0);
203 assert(sd_rtnl_process(rtnl, NULL) >= 0);
204 }
205 }
206
207 static void test_container(void) {
208 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
209 uint16_t type;
210 void *data;
211
212 assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, &m) >= 0);
213
214 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
215 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
216 assert(sd_rtnl_message_append(m, IFLA_INFO_KIND, "kind") >= 0);
217 assert(sd_rtnl_message_close_container(m) >= 0);
218 assert(sd_rtnl_message_close_container(m) == -EINVAL);
219
220 assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
221
222 /* TODO: add support for entering containers
223 assert(sd_rtnl_message_read(m, &type, &data) > 0);
224 assert(type == IFLA_INFO_KIND);
225 assert(streq("kind", (char *) data));
226
227 assert(sd_rtnl_message_read(m, &type, &data) == 0);
228 */
229 }
230
231 static void test_match(void) {
232 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
233
234 assert(sd_rtnl_open(0, &rtnl) >= 0);
235
236 assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
237 assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
238
239 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
240 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
241 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
242 }
243
244 int main(void) {
245 sd_rtnl *rtnl;
246 sd_rtnl_message *m;
247 sd_rtnl_message *r;
248 void *data;
249 int if_loopback;
250 uint16_t type;
251 unsigned int mtu = 0;
252 unsigned int *mtu_reply;
253
254 test_match();
255
256 test_multiple();
257
258 test_route();
259
260 test_container();
261
262 assert(sd_rtnl_open(0, &rtnl) >= 0);
263 assert(rtnl);
264
265 if_loopback = (int) if_nametoindex("lo");
266 assert(if_loopback > 0);
267
268 test_async(if_loopback);
269
270 test_pipe(if_loopback);
271
272 test_event_loop(if_loopback);
273
274 test_link_configure(rtnl, if_loopback);
275
276 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
277 assert(m);
278
279 assert(sd_rtnl_message_get_type(m, &type) >= 0);
280 assert(type == RTM_GETLINK);
281
282 assert(sd_rtnl_message_read(m, &type, &data) == 0);
283
284 assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
285 assert(sd_rtnl_message_get_type(r, &type) >= 0);
286 assert(type == RTM_NEWLINK);
287
288 assert(sd_rtnl_message_read(m, &type, &data) == 0);
289 assert((r = sd_rtnl_message_unref(r)) == NULL);
290
291 assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
292 assert((m = sd_rtnl_message_unref(m)) == NULL);
293 assert((r = sd_rtnl_message_unref(r)) == NULL);
294
295 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
296 assert(m);
297
298 assert(sd_rtnl_message_append(m, IFLA_MTU, &mtu) >= 0);
299 assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
300
301 assert(type == IFLA_MTU);
302 assert(*mtu_reply == 0);
303
304 assert(sd_rtnl_message_read(m, &type, &data) == 0);
305
306 assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
307 while (sd_rtnl_message_read(r, &type, &data) > 0) {
308 switch (type) {
309 // case IFLA_MTU:
310 // assert(*(unsigned int *) data == 65536);
311 // break;
312 // case IFLA_QDISC:
313 // assert(streq((char *) data, "noqueue"));
314 // break;
315 case IFLA_IFNAME:
316 assert(streq((char *) data, "lo"));
317 break;
318 }
319 }
320
321 assert(sd_rtnl_flush(rtnl) >= 0);
322
323 assert((m = sd_rtnl_message_unref(m)) == NULL);
324 assert((r = sd_rtnl_message_unref(r)) == NULL);
325 assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
326
327 return EXIT_SUCCESS;
328 }