libhydra: Move all kernel plugins to libcharon
[strongswan.git] / src / libcharon / plugins / kernel_netlink / suites / test_socket.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <test_suite.h>
17
18 #include <threading/thread.h>
19
20 #include "../kernel_netlink_shared.h"
21
22 /**
23 * Netlink message drop configuration
24 */
25 static int drop_interval = 0;
26
27 /**
28 * Netlink message drop hook
29 */
30 bool netlink_msg_loss(struct nlmsghdr *hdr)
31 {
32 static refcount_t i;
33
34 if (drop_interval)
35 {
36 return ref_get(&i) % drop_interval == drop_interval - 1;
37 }
38 return FALSE;
39 }
40
41 START_TEST(test_echo)
42 {
43 netlink_socket_t *s;
44 struct nlmsghdr *out;
45 struct rtmsg *msg;
46 char dst[] = {
47 127,0,0,1
48 };
49 size_t len;
50 netlink_buf_t request = {
51 .hdr = {
52 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
53 .nlmsg_flags = NLM_F_REQUEST,
54 .nlmsg_type = RTM_GETROUTE,
55 },
56 };
57
58 msg = NLMSG_DATA(&request.hdr);
59 msg->rtm_family = AF_INET;
60 netlink_add_attribute(&request.hdr, RTA_DST,
61 chunk_from_thing(dst), sizeof(request));
62
63 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
64
65 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
66 ck_assert_int_eq(out->nlmsg_type, RTM_NEWROUTE);
67 free(out);
68 s->destroy(s);
69 }
70 END_TEST
71
72 START_TEST(test_echo_dump)
73 {
74 netlink_socket_t *s;
75 struct nlmsghdr *out, *current;
76 struct rtgenmsg *msg;
77 size_t len;
78 netlink_buf_t request = {
79 .hdr = {
80 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
81 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
82 .nlmsg_type = RTM_GETLINK,
83 },
84 };
85
86 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
87 msg = NLMSG_DATA(&request.hdr);
88 msg->rtgen_family = AF_UNSPEC;
89
90 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
91 current = out;
92 while (TRUE)
93 {
94 ck_assert(NLMSG_OK(current, len));
95 if (current->nlmsg_type == NLMSG_DONE)
96 {
97 break;
98 }
99 ck_assert_int_eq(current->nlmsg_type, RTM_NEWLINK);
100 current = NLMSG_NEXT(current, len);
101 }
102 free(out);
103 s->destroy(s);
104 }
105 END_TEST
106
107 CALLBACK(stress, void*,
108 netlink_socket_t *s)
109 {
110 struct nlmsghdr *out;
111 struct rtmsg *msg;
112 char dst[] = {
113 127,0,0,1
114 };
115 size_t len;
116 int i;
117 netlink_buf_t request = {
118 .hdr = {
119 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
120 .nlmsg_flags = NLM_F_REQUEST,
121 .nlmsg_type = RTM_GETROUTE,
122 },
123 };
124
125 for (i = 0; i < 10; i++)
126 {
127 msg = NLMSG_DATA(&request.hdr);
128 msg->rtm_family = AF_INET;
129 netlink_add_attribute(&request.hdr, RTA_DST,
130 chunk_from_thing(dst), sizeof(request));
131
132 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
133 ck_assert_int_eq(out->nlmsg_type, RTM_NEWROUTE);
134 free(out);
135 }
136 return NULL;
137 }
138
139 CALLBACK(stress_dump, void*,
140 netlink_socket_t *s)
141 {
142 struct nlmsghdr *out, *current;
143 struct rtgenmsg *msg;
144 size_t len;
145 int i;
146 netlink_buf_t request = {
147 .hdr = {
148 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
149 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
150 .nlmsg_type = RTM_GETLINK,
151 },
152 };
153
154 msg = NLMSG_DATA(&request.hdr);
155 msg->rtgen_family = AF_UNSPEC;
156
157 for (i = 0; i < 10; i++)
158 {
159 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
160 current = out;
161 while (TRUE)
162 {
163 ck_assert(NLMSG_OK(current, len));
164 if (current->nlmsg_type == NLMSG_DONE)
165 {
166 break;
167 }
168 ck_assert_int_eq(current->nlmsg_type, RTM_NEWLINK);
169 current = NLMSG_NEXT(current, len);
170 }
171 free(out);
172 }
173 return NULL;
174 }
175
176 START_TEST(test_stress)
177 {
178 thread_t *threads[10];
179 netlink_socket_t *s;
180 int i;
181
182 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
183 for (i = 0; i < countof(threads); i++)
184 {
185 threads[i] = thread_create(stress, s);
186 }
187 for (i = 0; i < countof(threads); i++)
188 {
189 threads[i]->join(threads[i]);
190 }
191 s->destroy(s);
192 }
193 END_TEST
194
195 START_TEST(test_stress_dump)
196 {
197 thread_t *threads[10];
198 netlink_socket_t *s;
199 int i;
200
201 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
202 for (i = 0; i < countof(threads); i++)
203 {
204 threads[i] = thread_create(stress_dump, s);
205 }
206 for (i = 0; i < countof(threads); i++)
207 {
208 threads[i]->join(threads[i]);
209 }
210 s->destroy(s);
211 }
212 END_TEST
213
214 START_TEST(test_retransmit_success)
215 {
216 netlink_socket_t *s;
217 struct nlmsghdr *out;
218 struct rtgenmsg *msg;
219 size_t len;
220 netlink_buf_t request = {
221 .hdr = {
222 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
223 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
224 .nlmsg_type = RTM_GETLINK,
225 },
226 };
227
228 drop_interval = 2;
229
230 lib->settings->set_int(lib->settings,
231 "%s.plugins.kernel-netlink.timeout", 100, lib->ns);
232 lib->settings->set_int(lib->settings,
233 "%s.plugins.kernel-netlink.retries", 1, lib->ns);
234
235 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
236 msg = NLMSG_DATA(&request.hdr);
237 msg->rtgen_family = AF_UNSPEC;
238
239 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
240 free(out);
241 s->destroy(s);
242
243 drop_interval = 0;
244 }
245 END_TEST
246
247 START_TEST(test_retransmit_fail)
248 {
249 netlink_socket_t *s;
250 struct nlmsghdr *out;
251 struct rtgenmsg *msg;
252 size_t len;
253 netlink_buf_t request = {
254 .hdr = {
255 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
256 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
257 .nlmsg_type = RTM_GETLINK,
258 },
259 };
260
261 drop_interval = 1;
262
263 lib->settings->set_int(lib->settings,
264 "%s.plugins.kernel-netlink.timeout", 50, lib->ns);
265 lib->settings->set_int(lib->settings,
266 "%s.plugins.kernel-netlink.retries", 3, lib->ns);
267
268 s = netlink_socket_create(NETLINK_ROUTE, NULL, _i != 0);
269 msg = NLMSG_DATA(&request.hdr);
270 msg->rtgen_family = AF_UNSPEC;
271
272 ck_assert(s->send(s, &request.hdr, &out, &len) == OUT_OF_RES);
273 s->destroy(s);
274
275 drop_interval = 0;
276 }
277 END_TEST
278
279 Suite *socket_suite_create()
280 {
281 Suite *s;
282 TCase *tc;
283
284 s = suite_create("netlink socket");
285
286 tc = tcase_create("echo");
287 tcase_add_loop_test(tc, test_echo, 0, 2);
288 tcase_add_loop_test(tc, test_echo_dump, 0, 2);
289 suite_add_tcase(s, tc);
290
291 tc = tcase_create("stress");
292 tcase_add_loop_test(tc, test_stress, 0, 2);
293 tcase_add_loop_test(tc, test_stress_dump, 0, 2);
294 suite_add_tcase(s, tc);
295
296 tc = tcase_create("retransmit");
297 tcase_add_loop_test(tc, test_retransmit_success, 0, 2);
298 tcase_add_loop_test(tc, test_retransmit_fail, 0, 2);
299 suite_add_tcase(s, tc);
300
301 return s;
302 }