chiark / gitweb /
rtnl: add call_async and call_async_cancel
[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
31 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
32         _cleanup_sd_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_link_new(RTM_GETLINK, ifindex, 0, 0, &message) >= 0);
40         assert(sd_rtnl_message_append(message, IFLA_IFNAME, name) >= 0);
41         assert(sd_rtnl_message_append(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
42         assert(sd_rtnl_message_append(message, IFLA_MTU, &mtu) >= 0);
43
44         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
45         assert(type == IFLA_IFNAME);
46         assert(streq(name, (char *) data));
47
48         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
49         assert(type == IFLA_ADDRESS);
50         assert(streq(mac, ether_ntoa(data)));
51
52         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
53         assert(type == IFLA_MTU);
54         assert(mtu == *(unsigned int *) data);
55
56         assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
57 }
58
59 static void test_route(void) {
60         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
61         uint32_t addr = htonl(INADDR_LOOPBACK);
62         uint32_t index = 2;
63         uint16_t type;
64         void *data;
65         int r;
66
67         r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, 0, 0, 0,
68                                       RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
69                                       RTN_UNICAST, 0, &req);
70         if (r < 0) {
71                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
72                 return;
73         }
74
75         r = sd_rtnl_message_append(req, RTA_GATEWAY, &addr);
76         if (r < 0) {
77                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
78                 return;
79         }
80
81         r = sd_rtnl_message_append(req, RTA_OIF, &index);
82         if (r < 0) {
83                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
84                 return;
85         }
86
87         assert(sd_rtnl_message_read(req, &type, &data) > 0);
88         assert(type == RTA_GATEWAY);
89         assert(*(uint32_t *) data == addr);
90
91         assert(sd_rtnl_message_read(req, &type, &data) > 0);
92         assert(type == RTA_OIF);
93         assert(*(uint32_t *) data == index);
94 }
95
96 static void test_multiple(void) {
97         sd_rtnl *rtnl1, *rtnl2;
98
99         assert(sd_rtnl_open(0, &rtnl1) >= 0);
100         assert(sd_rtnl_open(0, &rtnl2) >= 0);
101
102         rtnl1 = sd_rtnl_unref(rtnl1);
103         rtnl2 = sd_rtnl_unref(rtnl2);
104 }
105
106 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
107         void *data;
108         uint16_t type;
109         char *ifname = userdata;
110
111         assert(rtnl);
112         assert(m);
113
114         log_info("got link info about %s", ifname);
115         free(ifname);
116
117         while (sd_rtnl_message_read(m, &type, &data) > 0) {
118                 switch (type) {
119 //                        case IFLA_MTU:
120 //                                assert(*(unsigned int *) data == 65536);
121 //                                break;
122 //                        case IFLA_QDISC:
123 //                                assert(streq((char *) data, "noqueue"));
124 //                                break;
125                         case IFLA_IFNAME:
126                                 assert(streq((char *) data, "lo"));
127                                 break;
128                 }
129         }
130
131         return 1;
132 }
133
134 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
135         int *counter = userdata;
136
137         (*counter) --;
138
139         log_info("got reply, %d left in pipe", *counter);
140
141         return sd_rtnl_message_get_errno(m);
142 }
143
144 static void test_async(void) {
145         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
146         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
147         int if_loopback;
148         uint32_t serial;
149         char *ifname;
150
151         ifname = strdup("lo");
152
153         assert(sd_rtnl_open(0, &rtnl) >= 0);
154
155         if_loopback = (int) if_nametoindex("lo");
156         assert(if_loopback > 0);
157
158         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
159
160         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
161
162         assert(sd_rtnl_wait(rtnl, 0) >= 0);
163         assert(sd_rtnl_process(rtnl, &r) >= 0);
164 }
165
166 static void test_pipe(void) {
167         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
168         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
169         int counter = 0;
170         int if_loopback;
171
172         assert(sd_rtnl_open(0, &rtnl) >= 0);
173
174         if_loopback = (int) if_nametoindex("lo");
175         assert(if_loopback > 0);
176
177         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m1) >= 0);
178         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m2) >= 0);
179
180         counter ++;
181         assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
182
183         counter ++;
184         assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
185
186         while (counter > 0) {
187                 assert(sd_rtnl_wait(rtnl, 0) >= 0);
188                 assert(sd_rtnl_process(rtnl, NULL) >= 0);
189         }
190 }
191
192 int main(void) {
193         sd_rtnl *rtnl;
194         sd_rtnl_message *m;
195         sd_rtnl_message *r;
196         void *data;
197         int if_loopback;
198         uint16_t type;
199         unsigned int mtu = 0;
200         unsigned int *mtu_reply;
201
202         test_multiple();
203
204         test_route();
205
206         test_async();
207
208         test_pipe();
209
210         assert(sd_rtnl_open(0, &rtnl) >= 0);
211         assert(rtnl);
212
213         if_loopback = (int) if_nametoindex("lo");
214         assert(if_loopback > 0);
215
216         test_link_configure(rtnl, if_loopback);
217
218         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
219         assert(m);
220
221         assert(sd_rtnl_message_get_type(m, &type) >= 0);
222         assert(type == RTM_GETLINK);
223
224         assert(sd_rtnl_message_read(m, &type, &data) == 0);
225
226         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
227         assert(sd_rtnl_message_get_type(r, &type) >= 0);
228         assert(type == RTM_NEWLINK);
229
230         assert(sd_rtnl_message_read(m, &type, &data) == 0);
231         assert((r = sd_rtnl_message_unref(r)) == NULL);
232
233         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
234         assert((m = sd_rtnl_message_unref(m)) == NULL);
235         assert((r = sd_rtnl_message_unref(r)) == NULL);
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_append(m, IFLA_MTU, &mtu) >= 0);
241         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
242
243         assert(type == IFLA_MTU);
244         assert(*mtu_reply == 0);
245
246         assert(sd_rtnl_message_read(m, &type, &data) == 0);
247
248         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
249         while (sd_rtnl_message_read(r, &type, &data) > 0) {
250                 switch (type) {
251 //                        case IFLA_MTU:
252 //                                assert(*(unsigned int *) data == 65536);
253 //                                break;
254 //                        case IFLA_QDISC:
255 //                                assert(streq((char *) data, "noqueue"));
256 //                                break;
257                         case IFLA_IFNAME:
258                                 assert(streq((char *) data, "lo"));
259                                 break;
260                 }
261         }
262
263         assert((m = sd_rtnl_message_unref(m)) == NULL);
264         assert((r = sd_rtnl_message_unref(r)) == NULL);
265         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
266
267         return EXIT_SUCCESS;
268 }