]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-rtnl/test-rtnl.c
rtnl: replace message_append by typesafe versions
[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_string(message, IFLA_IFNAME, name) >= 0);
42 assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
43 assert(sd_rtnl_message_append_u32(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 struct in_addr addr;
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 addr.s_addr = htonl(INADDR_LOOPBACK);
75
76 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
77 if (r < 0) {
78 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
79 return;
80 }
81
82 r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
83 if (r < 0) {
84 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
85 return;
86 }
87
88 assert(sd_rtnl_message_read(req, &type, &data) > 0);
89 assert(type == RTA_GATEWAY);
90 assert(((struct in_addr *)data)->s_addr == addr.s_addr);
91
92 assert(sd_rtnl_message_read(req, &type, &data) > 0);
93 assert(type == RTA_OIF);
94 assert(*(uint32_t *) data == index);
95 }
96
97 static void test_multiple(void) {
98 sd_rtnl *rtnl1, *rtnl2;
99
100 assert(sd_rtnl_open(0, &rtnl1) >= 0);
101 assert(sd_rtnl_open(0, &rtnl2) >= 0);
102
103 rtnl1 = sd_rtnl_unref(rtnl1);
104 rtnl2 = sd_rtnl_unref(rtnl2);
105 }
106
107 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
108 void *data;
109 uint16_t type;
110 char *ifname = userdata;
111
112 assert(rtnl);
113 assert(m);
114
115 log_info("got link info about %s", ifname);
116 free(ifname);
117
118 while (sd_rtnl_message_read(m, &type, &data) > 0) {
119 switch (type) {
120 // case IFLA_MTU:
121 // assert(*(unsigned int *) data == 65536);
122 // break;
123 // case IFLA_QDISC:
124 // assert(streq((char *) data, "noqueue"));
125 // break;
126 case IFLA_IFNAME:
127 assert(streq((char *) data, "lo"));
128 break;
129 }
130 }
131
132 return 1;
133 }
134
135 static void test_event_loop(int ifindex) {
136 _cleanup_event_unref_ sd_event *event = NULL;
137 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
138 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
139 char *ifname;
140
141 ifname = strdup("lo2");
142 assert(ifname);
143
144 assert(sd_rtnl_open(0, &rtnl) >= 0);
145 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
146
147 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
148
149 assert(sd_event_default(&event) >= 0);
150
151 assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
152
153 assert(sd_event_run(event, 0) >= 0);
154
155 assert(sd_rtnl_detach_event(rtnl) >= 0);
156 }
157
158 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
159 int *counter = userdata;
160
161 (*counter) --;
162
163 log_info("got reply, %d left in pipe", *counter);
164
165 return sd_rtnl_message_get_errno(m);
166 }
167
168 static void test_async(int ifindex) {
169 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
170 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
171 uint32_t serial;
172 char *ifname;
173
174 ifname = strdup("lo");
175 assert(ifname);
176
177 assert(sd_rtnl_open(0, &rtnl) >= 0);
178
179 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
180
181 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
182
183 assert(sd_rtnl_wait(rtnl, 0) >= 0);
184 assert(sd_rtnl_process(rtnl, &r) >= 0);
185 }
186
187 static void test_pipe(int ifindex) {
188 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
189 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
190 int counter = 0;
191
192 assert(sd_rtnl_open(0, &rtnl) >= 0);
193
194 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m1) >= 0);
195 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m2) >= 0);
196
197 counter ++;
198 assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
199
200 counter ++;
201 assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
202
203 while (counter > 0) {
204 assert(sd_rtnl_wait(rtnl, 0) >= 0);
205 assert(sd_rtnl_process(rtnl, NULL) >= 0);
206 }
207 }
208
209 static void test_container(void) {
210 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
211 uint16_t type;
212 void *data;
213
214 assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, &m) >= 0);
215
216 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
217 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
218 assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
219 assert(sd_rtnl_message_close_container(m) >= 0);
220 assert(sd_rtnl_message_close_container(m) == -EINVAL);
221
222 assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
223
224 /* TODO: add support for entering containers
225 assert(sd_rtnl_message_read(m, &type, &data) > 0);
226 assert(type == IFLA_INFO_KIND);
227 assert(streq("kind", (char *) data));
228
229 assert(sd_rtnl_message_read(m, &type, &data) == 0);
230 */
231 }
232
233 static void test_match(void) {
234 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
235
236 assert(sd_rtnl_open(0, &rtnl) >= 0);
237
238 assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
239 assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
240
241 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
242 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
243 assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
244 }
245
246 int main(void) {
247 sd_rtnl *rtnl;
248 sd_rtnl_message *m;
249 sd_rtnl_message *r;
250 void *data;
251 int if_loopback;
252 uint16_t type;
253 unsigned int mtu = 0;
254 unsigned int *mtu_reply;
255
256 test_match();
257
258 test_multiple();
259
260 test_route();
261
262 test_container();
263
264 assert(sd_rtnl_open(0, &rtnl) >= 0);
265 assert(rtnl);
266
267 if_loopback = (int) if_nametoindex("lo");
268 assert(if_loopback > 0);
269
270 test_async(if_loopback);
271
272 test_pipe(if_loopback);
273
274 test_event_loop(if_loopback);
275
276 test_link_configure(rtnl, if_loopback);
277
278 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
279 assert(m);
280
281 assert(sd_rtnl_message_get_type(m, &type) >= 0);
282 assert(type == RTM_GETLINK);
283
284 assert(sd_rtnl_message_read(m, &type, &data) == 0);
285
286 assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
287 assert(sd_rtnl_message_get_type(r, &type) >= 0);
288 assert(type == RTM_NEWLINK);
289
290 assert(sd_rtnl_message_read(m, &type, &data) == 0);
291 assert((r = sd_rtnl_message_unref(r)) == NULL);
292
293 assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
294 assert((m = sd_rtnl_message_unref(m)) == NULL);
295 assert((r = sd_rtnl_message_unref(r)) == NULL);
296
297 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
298 assert(m);
299
300 assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
301 assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
302
303 assert(type == IFLA_MTU);
304 assert(*mtu_reply == 0);
305
306 assert(sd_rtnl_message_read(m, &type, &data) == 0);
307
308 assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
309 while (sd_rtnl_message_read(r, &type, &data) > 0) {
310 switch (type) {
311 // case IFLA_MTU:
312 // assert(*(unsigned int *) data == 65536);
313 // break;
314 // case IFLA_QDISC:
315 // assert(streq((char *) data, "noqueue"));
316 // break;
317 case IFLA_IFNAME:
318 assert(streq((char *) data, "lo"));
319 break;
320 }
321 }
322
323 assert(sd_rtnl_flush(rtnl) >= 0);
324
325 assert((m = sd_rtnl_message_unref(m)) == NULL);
326 assert((r = sd_rtnl_message_unref(r)) == NULL);
327 assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
328
329 return EXIT_SUCCESS;
330 }