capabilities: Some plugins don't actually require capabilities at runtime
[strongswan.git] / src / libcharon / plugins / load_tester / load_tester_plugin.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 "load_tester_plugin.h"
17 #include "load_tester_config.h"
18 #include "load_tester_creds.h"
19 #include "load_tester_ipsec.h"
20 #include "load_tester_listener.h"
21 #include "load_tester_control.h"
22 #include "load_tester_diffie_hellman.h"
23
24 #include <unistd.h>
25
26 #include <hydra.h>
27 #include <daemon.h>
28 #include <processing/jobs/callback_job.h>
29 #include <threading/condvar.h>
30 #include <threading/mutex.h>
31
32 typedef struct private_load_tester_plugin_t private_load_tester_plugin_t;
33
34 /**
35 * private data of load_tester plugin
36 */
37 struct private_load_tester_plugin_t {
38
39 /**
40 * implements plugin interface
41 */
42 load_tester_plugin_t public;
43
44 /**
45 * load_tester configuration backend
46 */
47 load_tester_config_t *config;
48
49 /**
50 * load_tester credential set implementation
51 */
52 load_tester_creds_t *creds;
53
54 /**
55 * Unix control socket to initiate load-tests
56 */
57 load_tester_control_t *control;
58
59 /**
60 * event handler, listens on bus
61 */
62 load_tester_listener_t *listener;
63
64 /**
65 * number of iterations per thread
66 */
67 int iterations;
68
69 /**
70 * number desired initiator threads
71 */
72 int initiators;
73
74 /**
75 * currently running initiators
76 */
77 int running;
78
79 /**
80 * delay between initiations, in ms
81 */
82 int delay;
83
84 /**
85 * Throttle initiation if half-open IKE_SA count reached
86 */
87 int init_limit;
88
89 /**
90 * mutex to lock running field
91 */
92 mutex_t *mutex;
93
94 /**
95 * condvar to wait for initiators
96 */
97 condvar_t *condvar;
98 };
99
100 /**
101 * Begin the load test
102 */
103 static job_requeue_t do_load_test(private_load_tester_plugin_t *this)
104 {
105 int i, s = 0, ms = 0;
106
107 this->mutex->lock(this->mutex);
108 this->running++;
109 this->mutex->unlock(this->mutex);
110 if (this->delay)
111 {
112 s = this->delay / 1000;
113 ms = this->delay % 1000;
114 }
115
116 for (i = 0; this->iterations == 0 || i < this->iterations; i++)
117 {
118 peer_cfg_t *peer_cfg;
119 child_cfg_t *child_cfg = NULL;
120 enumerator_t *enumerator;
121
122 if (this->init_limit)
123 {
124 while ((charon->ike_sa_manager->get_count(charon->ike_sa_manager) -
125 this->listener->get_established(this->listener)) >
126 this->init_limit)
127 {
128 if (s)
129 {
130 sleep(s);
131 }
132 if (ms)
133 {
134 usleep(ms * 1000);
135 }
136 }
137 }
138
139 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
140 "load-test");
141 if (!peer_cfg)
142 {
143 break;
144 }
145 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
146 if (!enumerator->enumerate(enumerator, &child_cfg))
147 {
148 enumerator->destroy(enumerator);
149 break;
150 }
151 enumerator->destroy(enumerator);
152
153 charon->controller->initiate(charon->controller,
154 peer_cfg, child_cfg->get_ref(child_cfg),
155 NULL, NULL, 0);
156 if (s)
157 {
158 sleep(s);
159 }
160 if (ms)
161 {
162 usleep(ms * 1000);
163 }
164 }
165 this->mutex->lock(this->mutex);
166 this->running--;
167 this->condvar->signal(this->condvar);
168 this->mutex->unlock(this->mutex);
169 return JOB_REQUEUE_NONE;
170 }
171
172 METHOD(plugin_t, get_name, char*,
173 private_load_tester_plugin_t *this)
174 {
175 return "load-tester";
176 }
177
178 /**
179 * Register load_tester plugin features
180 */
181 static bool register_load_tester(private_load_tester_plugin_t *this,
182 plugin_feature_t *feature, bool reg, void *data)
183 {
184 if (reg)
185 {
186 u_int i, shutdown_on = 0;
187
188 this->config = load_tester_config_create();
189 this->creds = load_tester_creds_create();
190 this->control = load_tester_control_create();
191
192 charon->backends->add_backend(charon->backends, &this->config->backend);
193 lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set);
194
195 if (lib->settings->get_bool(lib->settings,
196 "%s.plugins.load-tester.shutdown_when_complete", 0, charon->name))
197 {
198 shutdown_on = this->iterations * this->initiators;
199 }
200 this->listener = load_tester_listener_create(shutdown_on, this->config);
201 charon->bus->add_listener(charon->bus, &this->listener->listener);
202
203 for (i = 0; i < this->initiators; i++)
204 {
205 lib->processor->queue_job(lib->processor, (job_t*)
206 callback_job_create_with_prio((callback_job_cb_t)do_load_test,
207 this, NULL, NULL, JOB_PRIO_CRITICAL));
208 }
209 }
210 else
211 {
212 this->iterations = -1;
213 this->mutex->lock(this->mutex);
214 while (this->running)
215 {
216 this->condvar->wait(this->condvar, this->mutex);
217 }
218 this->mutex->unlock(this->mutex);
219 charon->backends->remove_backend(charon->backends, &this->config->backend);
220 lib->credmgr->remove_set(lib->credmgr, &this->creds->credential_set);
221 charon->bus->remove_listener(charon->bus, &this->listener->listener);
222 this->config->destroy(this->config);
223 this->creds->destroy(this->creds);
224 this->listener->destroy(this->listener);
225 this->control->destroy(this->control);
226 }
227 return TRUE;
228 }
229
230 METHOD(plugin_t, get_features, int,
231 private_load_tester_plugin_t *this, plugin_feature_t *features[])
232 {
233 static plugin_feature_t f[] = {
234 PLUGIN_REGISTER(DH, load_tester_diffie_hellman_create),
235 PLUGIN_PROVIDE(DH, MODP_NULL),
236 PLUGIN_DEPENDS(CUSTOM, "load-tester"),
237 PLUGIN_CALLBACK((plugin_feature_callback_t)register_load_tester, NULL),
238 PLUGIN_PROVIDE(CUSTOM, "load-tester"),
239 PLUGIN_DEPENDS(CUSTOM, "kernel-net"),
240 PLUGIN_SDEPEND(PRIVKEY, KEY_RSA),
241 PLUGIN_SDEPEND(CERT_DECODE, CERT_ANY),
242 PLUGIN_SDEPEND(CERT_DECODE, CERT_X509),
243 };
244 *features = f;
245 return countof(f);
246 }
247
248 METHOD(plugin_t, destroy, void,
249 private_load_tester_plugin_t *this)
250 {
251 hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
252 (kernel_ipsec_constructor_t)load_tester_ipsec_create);
253 this->mutex->destroy(this->mutex);
254 this->condvar->destroy(this->condvar);
255 free(this);
256 }
257
258 /*
259 * see header file
260 */
261 plugin_t *load_tester_plugin_create()
262 {
263 private_load_tester_plugin_t *this;
264
265 if (!lib->settings->get_bool(lib->settings,
266 "%s.plugins.load-tester.enable", FALSE, charon->name))
267 {
268 DBG1(DBG_CFG, "disabling load-tester plugin, not configured");
269 return NULL;
270 }
271
272 if (!lib->caps->check(lib->caps, CAP_CHOWN))
273 { /* required to chown(2) control socket */
274 DBG1(DBG_CFG, "load-tester plugin requires CAP_CHOWN capability");
275 return NULL;
276 }
277
278 INIT(this,
279 .public = {
280 .plugin = {
281 .get_name = _get_name,
282 .get_features = _get_features,
283 .reload = (void*)return_false,
284 .destroy = _destroy,
285 },
286 },
287 .delay = lib->settings->get_int(lib->settings,
288 "%s.plugins.load-tester.delay", 0, charon->name),
289 .iterations = lib->settings->get_int(lib->settings,
290 "%s.plugins.load-tester.iterations", 1, charon->name),
291 .initiators = lib->settings->get_int(lib->settings,
292 "%s.plugins.load-tester.initiators", 0, charon->name),
293 .init_limit = lib->settings->get_int(lib->settings,
294 "%s.plugins.load-tester.init_limit", 0, charon->name),
295 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
296 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
297 );
298
299 if (lib->settings->get_bool(lib->settings,
300 "%s.plugins.load-tester.fake_kernel", FALSE, charon->name))
301 {
302 hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
303 (kernel_ipsec_constructor_t)load_tester_ipsec_create);
304 }
305 return &this->public.plugin;
306 }
307