chiark / gitweb /
21e12f65e3fe7c46c03e0f85a6df751668b4b493
[elogind.git] / src / libsystemd / sd-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 <netinet/ether.h>
23
24 #include "util.h"
25 #include "macro.h"
26 #include "sd-rtnl.h"
27 #include "socket-util.h"
28 #include "rtnl-util.h"
29 #include "event-util.h"
30
31 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
32         _cleanup_rtnl_message_unref_ sd_rtnl_message *message;
33         uint16_t type;
34         const char *mac = "98:fe:94:3f:c6:18", *name = "test";
35         unsigned int mtu = 1450;
36         void *data;
37
38         /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
39         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &message) >= 0);
40         assert(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
41         assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
42         assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
43
44         assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
45
46         assert(sd_rtnl_message_read(message, &type, &data) > 0);
47         assert(type == IFLA_IFNAME);
48         assert(streq(name, (char *) data));
49
50         assert(sd_rtnl_message_read(message, &type, &data) > 0);
51         assert(type == IFLA_ADDRESS);
52         assert(streq(mac, ether_ntoa(data)));
53
54         assert(sd_rtnl_message_read(message, &type, &data) > 0);
55         assert(type == IFLA_MTU);
56         assert(mtu == *(unsigned int *) data);
57 }
58
59
60 static void test_link_get(sd_rtnl *rtnl, int ifindex) {
61         sd_rtnl_message *m;
62         sd_rtnl_message *r;
63         unsigned int mtu = 1500;
64         unsigned int *mtu_reply;
65         void *data;
66         uint16_t type;
67
68         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
69         assert(m);
70
71         /* u8 test cases  */
72         assert(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
73         assert(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
74         assert(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
75
76         /* u32 test cases */
77         assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
78         assert(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
79         assert(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
80         assert(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
81         assert(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
82
83         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
84
85         /* u8 read back */
86         assert(sd_rtnl_message_read(m, &type, &data) == 1);
87         assert(type == IFLA_CARRIER);
88
89         assert(sd_rtnl_message_read(m, &type, &data) == 1);
90         assert(type == IFLA_OPERSTATE);
91
92         assert(sd_rtnl_message_read(m, &type, &data) == 1);
93         assert(type == IFLA_LINKMODE);
94
95         /* u32 read back */
96         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
97         assert(type == IFLA_MTU);
98         assert(*mtu_reply == mtu);
99
100         assert(sd_rtnl_message_read(m, &type, &data) == 1);
101         assert(type == IFLA_GROUP);
102
103         assert(sd_rtnl_message_read(m, &type, &data) == 1);
104         assert(type == IFLA_TXQLEN);
105
106         assert(sd_rtnl_message_read(m, &type, &data) == 1);
107         assert(type == IFLA_NUM_TX_QUEUES);
108
109         assert(sd_rtnl_message_read(m, &type, &data) == 1);
110         assert(type == IFLA_NUM_RX_QUEUES);
111
112         while (sd_rtnl_message_read(r, &type, &data) > 0) {
113                 switch (type) {
114 //                        case IFLA_MTU:
115 //                                assert(*(unsigned int *) data == 65536);
116 //                                break;
117 //                        case IFLA_QDISC:
118 //                                assert(streq((char *) data, "noqueue"));
119 //                                break;
120                         case IFLA_IFNAME:
121                                 assert(streq((char *) data, "lo"));
122                                 break;
123                 }
124         }
125
126         assert(sd_rtnl_flush(rtnl) >= 0);
127         assert((m = sd_rtnl_message_unref(m)) == NULL);
128
129 }
130
131 static void test_route(void) {
132         _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
133         struct in_addr addr;
134         uint32_t index = 2;
135         uint16_t type;
136         void *data;
137         int r;
138
139         r = sd_rtnl_message_new_route(RTM_NEWROUTE, AF_INET, &req);
140         if (r < 0) {
141                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
142                 return;
143         }
144
145         addr.s_addr = htonl(INADDR_LOOPBACK);
146
147         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
148         if (r < 0) {
149                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
150                 return;
151         }
152
153         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
154         if (r < 0) {
155                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
156                 return;
157         }
158
159         assert(rtnl_message_seal(NULL, req) >= 0);
160
161         assert(sd_rtnl_message_read(req, &type, &data) > 0);
162         assert(type == RTA_GATEWAY);
163         assert(((struct in_addr *)data)->s_addr == addr.s_addr);
164
165         assert(sd_rtnl_message_read(req, &type, &data) > 0);
166         assert(type == RTA_OIF);
167         assert(*(uint32_t *) data == index);
168 }
169
170 static void test_multiple(void) {
171         sd_rtnl *rtnl1, *rtnl2;
172
173         assert(sd_rtnl_open(0, &rtnl1) >= 0);
174         assert(sd_rtnl_open(0, &rtnl2) >= 0);
175
176         rtnl1 = sd_rtnl_unref(rtnl1);
177         rtnl2 = sd_rtnl_unref(rtnl2);
178 }
179
180 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
181         void *data;
182         uint16_t type;
183         char *ifname = userdata;
184
185         assert(rtnl);
186         assert(m);
187
188         log_info("got link info about %s", ifname);
189         free(ifname);
190
191         while (sd_rtnl_message_read(m, &type, &data) > 0) {
192                 switch (type) {
193 //                        case IFLA_MTU:
194 //                                assert(*(unsigned int *) data == 65536);
195 //                                break;
196 //                        case IFLA_QDISC:
197 //                                assert(streq((char *) data, "noqueue"));
198 //                                break;
199                         case IFLA_IFNAME:
200                                 assert(streq((char *) data, "lo"));
201                                 break;
202                 }
203         }
204
205         return 1;
206 }
207
208 static void test_event_loop(int ifindex) {
209         _cleanup_event_unref_ sd_event *event = NULL;
210         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
211         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
212         char *ifname;
213
214         ifname = strdup("lo2");
215         assert(ifname);
216
217         assert(sd_rtnl_open(0, &rtnl) >= 0);
218         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
219
220         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
221
222         assert(sd_event_default(&event) >= 0);
223
224         assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
225
226         assert(sd_event_run(event, 0) >= 0);
227
228         assert(sd_rtnl_detach_event(rtnl) >= 0);
229 }
230
231 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
232         int *counter = userdata;
233
234         (*counter) --;
235
236         log_info("got reply, %d left in pipe", *counter);
237
238         return sd_rtnl_message_get_errno(m);
239 }
240
241 static void test_async(int ifindex) {
242         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
243         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
244         uint32_t serial;
245         char *ifname;
246
247         ifname = strdup("lo");
248         assert(ifname);
249
250         assert(sd_rtnl_open(0, &rtnl) >= 0);
251
252         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
253
254         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
255
256         assert(sd_rtnl_wait(rtnl, 0) >= 0);
257         assert(sd_rtnl_process(rtnl, &r) >= 0);
258 }
259
260 static void test_pipe(int ifindex) {
261         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
262         _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
263         int counter = 0;
264
265         assert(sd_rtnl_open(0, &rtnl) >= 0);
266
267         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m1) >= 0);
268         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m2) >= 0);
269
270         counter ++;
271         assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
272
273         counter ++;
274         assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
275
276         while (counter > 0) {
277                 assert(sd_rtnl_wait(rtnl, 0) >= 0);
278                 assert(sd_rtnl_process(rtnl, NULL) >= 0);
279         }
280 }
281
282 static void test_container(void) {
283         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
284         uint16_t type;
285         void *data;
286
287         assert(sd_rtnl_message_new_link(RTM_NEWLINK, 0, &m) >= 0);
288
289         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
290         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP);
291         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
292         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
293         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
294         assert(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
295         assert(sd_rtnl_message_close_container(m) >= 0);
296         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
297         assert(sd_rtnl_message_close_container(m) >= 0);
298         assert(sd_rtnl_message_close_container(m) == -EINVAL);
299
300         assert(rtnl_message_seal(NULL, m) >= 0);
301
302         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
303         assert(type == IFLA_LINKINFO);
304         assert(data == NULL);
305         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
306         assert(type == IFLA_INFO_KIND);
307         assert(streq("kind", (char *)data));
308         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
309         assert(type == IFLA_INFO_DATA);
310         assert(data == NULL);
311         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
312         assert(type == IFLA_VLAN_ID);
313         assert(*(uint16_t *)data == 100);
314         assert(sd_rtnl_message_read(m, &type, &data) == 0);
315         assert(sd_rtnl_message_exit_container(m) >= 0);
316         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
317         assert(type == IFLA_INFO_KIND);
318         assert(streq("kind", (char *)data));
319         assert(sd_rtnl_message_read(m, &type, &data) == 0);
320         assert(sd_rtnl_message_exit_container(m) >= 0);
321         assert(sd_rtnl_message_exit_container(m) == -EINVAL);
322 }
323
324 static void test_match(void) {
325         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
326
327         assert(sd_rtnl_open(0, &rtnl) >= 0);
328
329         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
330         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
331
332         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
333         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
334         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
335 }
336
337 int main(void) {
338         sd_rtnl *rtnl;
339         sd_rtnl_message *m;
340         sd_rtnl_message *r;
341         void *data;
342         int if_loopback;
343         uint16_t type;
344
345         test_match();
346
347         test_multiple();
348
349         test_route();
350
351         test_container();
352
353         assert(sd_rtnl_open(0, &rtnl) >= 0);
354         assert(rtnl);
355
356         if_loopback = (int) if_nametoindex("lo");
357         assert(if_loopback > 0);
358
359         test_async(if_loopback);
360
361         test_pipe(if_loopback);
362
363         test_event_loop(if_loopback);
364
365         test_link_configure(rtnl, if_loopback);
366
367         assert(sd_rtnl_message_new_link(RTM_GETLINK, if_loopback, &m) >= 0);
368         assert(m);
369
370         assert(sd_rtnl_message_get_type(m, &type) >= 0);
371         assert(type == RTM_GETLINK);
372
373         assert(sd_rtnl_message_read(m, &type, &data) == -EPERM);
374
375         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
376         assert(sd_rtnl_message_get_type(r, &type) >= 0);
377         assert(type == RTM_NEWLINK);
378
379         assert(sd_rtnl_message_read(m, &type, &data) == 0);
380         assert((r = sd_rtnl_message_unref(r)) == NULL);
381
382         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
383         assert((m = sd_rtnl_message_unref(m)) == NULL);
384         assert((r = sd_rtnl_message_unref(r)) == NULL);
385
386         test_link_get(rtnl, if_loopback);
387
388         assert(sd_rtnl_flush(rtnl) >= 0);
389         assert((m = sd_rtnl_message_unref(m)) == NULL);
390         assert((r = sd_rtnl_message_unref(r)) == NULL);
391         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
392
393         return EXIT_SUCCESS;
394 }