ceea6535d85d533c0ef83c307055bd7f6132ce16
[strongswan.git] / src / libhydra / 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, *current;
45 struct rtgenmsg *msg;
46 size_t len;
47 netlink_buf_t request = {
48 .hdr = {
49 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
50 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
51 .nlmsg_type = RTM_GETLINK,
52 },
53 };
54
55 s = netlink_socket_create(NETLINK_ROUTE, NULL);
56 msg = NLMSG_DATA(&request.hdr);
57 msg->rtgen_family = AF_UNSPEC;
58
59 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
60 current = out;
61 while (TRUE)
62 {
63 ck_assert(NLMSG_OK(current, len));
64 if (current->nlmsg_type == NLMSG_DONE)
65 {
66 break;
67 }
68 ck_assert_int_eq(current->nlmsg_type, RTM_NEWLINK);
69 current = NLMSG_NEXT(current, len);
70 }
71 free(out);
72 s->destroy(s);
73 }
74 END_TEST
75
76 CALLBACK(stress, void*,
77 netlink_socket_t *s)
78 {
79 struct nlmsghdr *out, *current;
80 struct rtgenmsg *msg;
81 size_t len;
82 int i;
83 netlink_buf_t request = {
84 .hdr = {
85 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
86 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
87 .nlmsg_type = RTM_GETLINK,
88 },
89 };
90
91 msg = NLMSG_DATA(&request.hdr);
92 msg->rtgen_family = AF_UNSPEC;
93
94 for (i = 0; i < 10; i++)
95 {
96 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
97 current = out;
98 while (TRUE)
99 {
100 ck_assert(NLMSG_OK(current, len));
101 if (current->nlmsg_type == NLMSG_DONE)
102 {
103 break;
104 }
105 ck_assert_int_eq(current->nlmsg_type, RTM_NEWLINK);
106 current = NLMSG_NEXT(current, len);
107 }
108 free(out);
109 }
110 return NULL;
111 }
112
113 START_TEST(test_stress)
114 {
115 thread_t *threads[10];
116 netlink_socket_t *s;
117 int i;
118
119 s = netlink_socket_create(NETLINK_ROUTE, NULL);
120 for (i = 0; i < countof(threads); i++)
121 {
122 threads[i] = thread_create(stress, s);
123 }
124 for (i = 0; i < countof(threads); i++)
125 {
126 threads[i]->join(threads[i]);
127 }
128 s->destroy(s);
129 }
130 END_TEST
131
132 START_TEST(test_retransmit_success)
133 {
134 netlink_socket_t *s;
135 struct nlmsghdr *out;
136 struct rtgenmsg *msg;
137 size_t len;
138 netlink_buf_t request = {
139 .hdr = {
140 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
141 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
142 .nlmsg_type = RTM_GETLINK,
143 },
144 };
145
146 drop_interval = 2;
147
148 lib->settings->set_int(lib->settings,
149 "%s.plugins.kernel-netlink.timeout", 100, lib->ns);
150 lib->settings->set_int(lib->settings,
151 "%s.plugins.kernel-netlink.retries", 1, lib->ns);
152
153 s = netlink_socket_create(NETLINK_ROUTE, NULL);
154 msg = NLMSG_DATA(&request.hdr);
155 msg->rtgen_family = AF_UNSPEC;
156
157 ck_assert(s->send(s, &request.hdr, &out, &len) == SUCCESS);
158 free(out);
159 s->destroy(s);
160
161 drop_interval = 0;
162 }
163 END_TEST
164
165 START_TEST(test_retransmit_fail)
166 {
167 netlink_socket_t *s;
168 struct nlmsghdr *out;
169 struct rtgenmsg *msg;
170 size_t len;
171 netlink_buf_t request = {
172 .hdr = {
173 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
174 .nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT,
175 .nlmsg_type = RTM_GETLINK,
176 },
177 };
178
179 drop_interval = 1;
180
181 lib->settings->set_int(lib->settings,
182 "%s.plugins.kernel-netlink.timeout", 50, lib->ns);
183 lib->settings->set_int(lib->settings,
184 "%s.plugins.kernel-netlink.retries", 3, lib->ns);
185
186 s = netlink_socket_create(NETLINK_ROUTE, NULL);
187 msg = NLMSG_DATA(&request.hdr);
188 msg->rtgen_family = AF_UNSPEC;
189
190 ck_assert(s->send(s, &request.hdr, &out, &len) == OUT_OF_RES);
191 s->destroy(s);
192
193 drop_interval = 0;
194 }
195 END_TEST
196
197 Suite *socket_suite_create()
198 {
199 Suite *s;
200 TCase *tc;
201
202 s = suite_create("netlink socket");
203
204 tc = tcase_create("echo");
205 tcase_add_test(tc, test_echo);
206 suite_add_tcase(s, tc);
207
208 tc = tcase_create("stress");
209 tcase_add_test(tc, test_stress);
210 suite_add_tcase(s, tc);
211
212 tc = tcase_create("retransmit");
213 tcase_add_test(tc, test_retransmit_success);
214 tcase_add_test(tc, test_retransmit_fail);
215 suite_add_tcase(s, tc);
216
217 return s;
218 }