1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <linux/rtnetlink.h>
23 #include <netinet/ether.h>
28 #include "socket-util.h"
29 #include "rtnl-util.h"
30 #include "event-util.h"
32 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
33 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
35 const char *mac = "98:fe:94:3f:c6:18", *name = "test";
36 unsigned int mtu = 1450;
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);
45 assert(sd_rtnl_message_read(message, &type, &data) >= 0);
46 assert(type == IFLA_IFNAME);
47 assert(streq(name, (char *) data));
49 assert(sd_rtnl_message_read(message, &type, &data) >= 0);
50 assert(type == IFLA_ADDRESS);
51 assert(streq(mac, ether_ntoa(data)));
53 assert(sd_rtnl_message_read(message, &type, &data) >= 0);
54 assert(type == IFLA_MTU);
55 assert(mtu == *(unsigned int *) data);
57 assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
60 static void test_route(void) {
61 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
62 uint32_t addr = htonl(INADDR_LOOPBACK);
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);
72 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
76 r = sd_rtnl_message_append(req, RTA_GATEWAY, &addr);
78 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
82 r = sd_rtnl_message_append(req, RTA_OIF, &index);
84 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
88 assert(sd_rtnl_message_read(req, &type, &data) > 0);
89 assert(type == RTA_GATEWAY);
90 assert(*(uint32_t *) data == addr);
92 assert(sd_rtnl_message_read(req, &type, &data) > 0);
93 assert(type == RTA_OIF);
94 assert(*(uint32_t *) data == index);
97 static void test_multiple(void) {
98 sd_rtnl *rtnl1, *rtnl2;
100 assert(sd_rtnl_open(0, &rtnl1) >= 0);
101 assert(sd_rtnl_open(0, &rtnl2) >= 0);
103 rtnl1 = sd_rtnl_unref(rtnl1);
104 rtnl2 = sd_rtnl_unref(rtnl2);
107 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
110 char *ifname = userdata;
115 log_info("got link info about %s", ifname);
118 while (sd_rtnl_message_read(m, &type, &data) > 0) {
121 // assert(*(unsigned int *) data == 65536);
124 // assert(streq((char *) data, "noqueue"));
127 assert(streq((char *) data, "lo"));
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;
141 ifname = strdup("lo2");
144 assert(sd_rtnl_open(0, &rtnl) >= 0);
145 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m) >= 0);
147 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
149 assert(sd_event_default(&event) >= 0);
151 assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
153 assert(sd_event_run(event, 0) >= 0);
155 assert(sd_rtnl_detach_event(rtnl) >= 0);
158 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
159 int *counter = userdata;
163 log_info("got reply, %d left in pipe", *counter);
165 return sd_rtnl_message_get_errno(m);
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;
174 ifname = strdup("lo");
177 assert(sd_rtnl_open(0, &rtnl) >= 0);
179 assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m) >= 0);
181 assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
183 assert(sd_rtnl_wait(rtnl, 0) >= 0);
184 assert(sd_rtnl_process(rtnl, &r) >= 0);
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;
192 assert(sd_rtnl_open(0, &rtnl) >= 0);
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);
198 assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
201 assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
203 while (counter > 0) {
204 assert(sd_rtnl_wait(rtnl, 0) >= 0);
205 assert(sd_rtnl_process(rtnl, NULL) >= 0);
209 static void test_container(void) {
210 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
214 assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, 0, 0, &m) >= 0);
216 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
217 assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
218 assert(sd_rtnl_message_append(m, IFLA_INFO_KIND, "kind") >= 0);
219 assert(sd_rtnl_message_close_container(m) >= 0);
220 assert(sd_rtnl_message_close_container(m) == -EINVAL);
222 assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
224 /* TODO: add support for entering containers
225 assert(sd_rtnl_message_read(m, &type, &data) > 0);
226 assert(type == IFLA_INFO_KIND);
227 assert(streq("kind", (char *) data));
229 assert(sd_rtnl_message_read(m, &type, &data) == 0);
240 unsigned int mtu = 0;
241 unsigned int *mtu_reply;
249 assert(sd_rtnl_open(0, &rtnl) >= 0);
252 if_loopback = (int) if_nametoindex("lo");
253 assert(if_loopback > 0);
255 test_async(if_loopback);
257 test_pipe(if_loopback);
259 test_event_loop(if_loopback);
261 test_link_configure(rtnl, if_loopback);
263 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
266 assert(sd_rtnl_message_get_type(m, &type) >= 0);
267 assert(type == RTM_GETLINK);
269 assert(sd_rtnl_message_read(m, &type, &data) == 0);
271 assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
272 assert(sd_rtnl_message_get_type(r, &type) >= 0);
273 assert(type == RTM_NEWLINK);
275 assert(sd_rtnl_message_read(m, &type, &data) == 0);
276 assert((r = sd_rtnl_message_unref(r)) == NULL);
278 assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
279 assert((m = sd_rtnl_message_unref(m)) == NULL);
280 assert((r = sd_rtnl_message_unref(r)) == NULL);
282 assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
285 assert(sd_rtnl_message_append(m, IFLA_MTU, &mtu) >= 0);
286 assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
288 assert(type == IFLA_MTU);
289 assert(*mtu_reply == 0);
291 assert(sd_rtnl_message_read(m, &type, &data) == 0);
293 assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
294 while (sd_rtnl_message_read(r, &type, &data) > 0) {
297 // assert(*(unsigned int *) data == 65536);
300 // assert(streq((char *) data, "noqueue"));
303 assert(streq((char *) data, "lo"));
308 assert(sd_rtnl_flush(rtnl) >= 0);
310 assert((m = sd_rtnl_message_unref(m)) == NULL);
311 assert((r = sd_rtnl_message_unref(r)) == NULL);
312 assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);