chiark / gitweb /
sd-rtnl: add support for nested containers
[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 <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) == -ENOTSUP);
218         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
219         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
220         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
221         assert(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
222         assert(sd_rtnl_message_close_container(m) >= 0);
223         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
224         assert(sd_rtnl_message_close_container(m) >= 0);
225         assert(sd_rtnl_message_close_container(m) == -EINVAL);
226
227         assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
228
229 /* TODO: add support for entering containers
230         assert(sd_rtnl_message_read(m, &type, &data) > 0);
231         assert(type == IFLA_INFO_KIND);
232         assert(streq("kind", (char *) data));
233
234         assert(sd_rtnl_message_read(m, &type, &data) == 0);
235 */
236 }
237
238 static void test_match(void) {
239         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
240
241         assert(sd_rtnl_open(0, &rtnl) >= 0);
242
243         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
244         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
245
246         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
247         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
248         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
249 }
250
251 int main(void) {
252         sd_rtnl *rtnl;
253         sd_rtnl_message *m;
254         sd_rtnl_message *r;
255         void *data;
256         int if_loopback;
257         uint16_t type;
258         unsigned int mtu = 0;
259         unsigned int *mtu_reply;
260
261         test_match();
262
263         test_multiple();
264
265         test_route();
266
267         test_container();
268
269         assert(sd_rtnl_open(0, &rtnl) >= 0);
270         assert(rtnl);
271
272         if_loopback = (int) if_nametoindex("lo");
273         assert(if_loopback > 0);
274
275         test_async(if_loopback);
276
277         test_pipe(if_loopback);
278
279         test_event_loop(if_loopback);
280
281         test_link_configure(rtnl, if_loopback);
282
283         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
284         assert(m);
285
286         assert(sd_rtnl_message_get_type(m, &type) >= 0);
287         assert(type == RTM_GETLINK);
288
289         assert(sd_rtnl_message_read(m, &type, &data) == 0);
290
291         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
292         assert(sd_rtnl_message_get_type(r, &type) >= 0);
293         assert(type == RTM_NEWLINK);
294
295         assert(sd_rtnl_message_read(m, &type, &data) == 0);
296         assert((r = sd_rtnl_message_unref(r)) == NULL);
297
298         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
299         assert((m = sd_rtnl_message_unref(m)) == NULL);
300         assert((r = sd_rtnl_message_unref(r)) == NULL);
301
302         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
303         assert(m);
304
305         assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
306         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
307
308         assert(type == IFLA_MTU);
309         assert(*mtu_reply == 0);
310
311         assert(sd_rtnl_message_read(m, &type, &data) == 0);
312
313         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
314         while (sd_rtnl_message_read(r, &type, &data) > 0) {
315                 switch (type) {
316 //                        case IFLA_MTU:
317 //                                assert(*(unsigned int *) data == 65536);
318 //                                break;
319 //                        case IFLA_QDISC:
320 //                                assert(streq((char *) data, "noqueue"));
321 //                                break;
322                         case IFLA_IFNAME:
323                                 assert(streq((char *) data, "lo"));
324                                 break;
325                 }
326         }
327
328         assert(sd_rtnl_flush(rtnl) >= 0);
329
330         assert((m = sd_rtnl_message_unref(m)) == NULL);
331         assert((r = sd_rtnl_message_unref(r)) == NULL);
332         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
333
334         return EXIT_SUCCESS;
335 }