chiark / gitweb /
rtnl: add event loop integration
[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, 0, 0, &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, 0, 0, 0,
69                                       RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
70                                       RTN_UNICAST, 0, &req);
71         if (r < 0) {
72                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
73                 return;
74         }
75
76         r = sd_rtnl_message_append(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(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(*(uint32_t *) data == 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, 0, 0, &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, 0, 0, &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, 0, 0, &m1) >= 0);
195         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &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 int main(void) {
210         sd_rtnl *rtnl;
211         sd_rtnl_message *m;
212         sd_rtnl_message *r;
213         void *data;
214         int if_loopback;
215         uint16_t type;
216         unsigned int mtu = 0;
217         unsigned int *mtu_reply;
218
219         test_multiple();
220
221         test_route();
222
223         assert(sd_rtnl_open(0, &rtnl) >= 0);
224         assert(rtnl);
225
226         if_loopback = (int) if_nametoindex("lo");
227         assert(if_loopback > 0);
228
229         test_async(if_loopback);
230
231         test_pipe(if_loopback);
232
233         test_event_loop(if_loopback);
234
235         test_link_configure(rtnl, if_loopback);
236
237         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
238         assert(m);
239
240         assert(sd_rtnl_message_get_type(m, &type) >= 0);
241         assert(type == RTM_GETLINK);
242
243         assert(sd_rtnl_message_read(m, &type, &data) == 0);
244
245         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
246         assert(sd_rtnl_message_get_type(r, &type) >= 0);
247         assert(type == RTM_NEWLINK);
248
249         assert(sd_rtnl_message_read(m, &type, &data) == 0);
250         assert((r = sd_rtnl_message_unref(r)) == NULL);
251
252         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
253         assert((m = sd_rtnl_message_unref(m)) == NULL);
254         assert((r = sd_rtnl_message_unref(r)) == NULL);
255
256         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
257         assert(m);
258
259         assert(sd_rtnl_message_append(m, IFLA_MTU, &mtu) >= 0);
260         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
261
262         assert(type == IFLA_MTU);
263         assert(*mtu_reply == 0);
264
265         assert(sd_rtnl_message_read(m, &type, &data) == 0);
266
267         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
268         while (sd_rtnl_message_read(r, &type, &data) > 0) {
269                 switch (type) {
270 //                        case IFLA_MTU:
271 //                                assert(*(unsigned int *) data == 65536);
272 //                                break;
273 //                        case IFLA_QDISC:
274 //                                assert(streq((char *) data, "noqueue"));
275 //                                break;
276                         case IFLA_IFNAME:
277                                 assert(streq((char *) data, "lo"));
278                                 break;
279                 }
280         }
281
282         assert(sd_rtnl_flush(rtnl) >= 0);
283
284         assert((m = sd_rtnl_message_unref(m)) == NULL);
285         assert((r = sd_rtnl_message_unref(r)) == NULL);
286         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
287
288         return EXIT_SUCCESS;
289 }