chiark / gitweb /
bfcfc85d93ee70ce3058c49e2a8d0c6b079c0736
[elogind.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 }