controller: Optionally adhere to init limits also when initiating IKE_SAs
authorTobias Brunner <tobias@strongswan.org>
Thu, 16 Jul 2015 15:21:54 +0000 (17:21 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 21 Aug 2015 16:21:13 +0000 (18:21 +0200)
15 files changed:
src/charon-cmd/cmd/cmd_connection.c
src/conftest/actions.c
src/frontends/osx/charon-xpc/xpc_dispatch.c
src/libcharon/control/controller.c
src/libcharon/control/controller.h
src/libcharon/plugins/load_tester/load_tester_control.c
src/libcharon/plugins/load_tester/load_tester_plugin.c
src/libcharon/plugins/medcli/medcli_config.c
src/libcharon/plugins/smp/smp.c
src/libcharon/plugins/stroke/stroke_control.c
src/libcharon/plugins/uci/uci_control.c
src/libcharon/plugins/vici/vici_config.c
src/libcharon/plugins/vici/vici_control.c
src/libcharon/processing/jobs/initiate_mediation_job.c
src/libcharon/processing/jobs/start_action_job.c

index 2c0b7b9..0c6a504 100644 (file)
@@ -434,7 +434,7 @@ static job_requeue_t initiate(private_cmd_connection_t *this)
        child_cfg = create_child_cfg(this, peer_cfg);
 
        if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        controller_cb_empty, NULL, 0) != SUCCESS)
+                                                               controller_cb_empty, NULL, 0, FALSE) != SUCCESS)
        {
                terminate(pid);
        }
index 474672c..256b63d 100644 (file)
@@ -65,7 +65,7 @@ static job_requeue_t initiate(char *config)
        {
                DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config);
                charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        NULL, NULL, 0);
+                                                                        NULL, NULL, 0, FALSE);
        }
        else
        {
index 04aad87..4b4c67c 100644 (file)
@@ -196,7 +196,7 @@ void start_connection(private_xpc_dispatch_t *this,
                peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
 
                if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                       (controller_cb_t)initiate_cb, &ike_sa, 0) == NEED_MORE)
+                               (controller_cb_t)initiate_cb, &ike_sa, 0, FALSE) == NEED_MORE)
                {
                        this->channels->add(this->channels, channel, ike_sa);
                        success = TRUE;
index fd8349e..097f5ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2012 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
  * Copyright (C) 2007-2011 Martin Willi
  * Copyright (C) 2011 revosec AG
  * Hochschule fuer Technik Rapperswil
@@ -116,6 +116,11 @@ struct interface_listener_t {
         * spinlock to update the IKE_SA handle properly
         */
        spinlock_t *lock;
+
+       /**
+        * whether to check limits
+        */
+       bool limits;
 };
 
 
@@ -358,7 +363,6 @@ METHOD(job_t, initiate_execute, job_requeue_t,
                listener->child_cfg->destroy(listener->child_cfg);
                peer_cfg->destroy(peer_cfg);
                listener->status = FAILED;
-               /* release listener */
                listener_done(listener);
                return JOB_REQUEUE_NONE;
        }
@@ -372,6 +376,49 @@ METHOD(job_t, initiate_execute, job_requeue_t,
        }
        peer_cfg->destroy(peer_cfg);
 
+       if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
+       {       /* only check if we are not reusing an IKE_SA */
+               u_int half_open, limit_half_open, limit_job_load;
+
+               half_open = charon->ike_sa_manager->get_half_open_count(
+                                                                               charon->ike_sa_manager, NULL);
+               limit_half_open = lib->settings->get_int(lib->settings,
+                                                                               "%s.init_limit_half_open", 0, lib->ns);
+               limit_job_load = lib->settings->get_int(lib->settings,
+                                                                               "%s.init_limit_job_load", 0, lib->ns);
+               if (limit_half_open && half_open >= limit_half_open)
+               {
+                       DBG1(DBG_IKE, "abort IKE_SA initiation, half open IKE_SA count of "
+                                "%d exceeds limit of %d", half_open, limit_half_open);
+                       charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                               ike_sa);
+                       listener->child_cfg->destroy(listener->child_cfg);
+                       listener->status = INVALID_STATE;
+                       listener_done(listener);
+                       return JOB_REQUEUE_NONE;
+               }
+               if (limit_job_load)
+               {
+                       u_int jobs = 0, i;
+
+                       for (i = 0; i < JOB_PRIO_MAX; i++)
+                       {
+                               jobs += lib->processor->get_job_load(lib->processor, i);
+                       }
+                       if (jobs > limit_job_load)
+                       {
+                               DBG1(DBG_IKE, "abort IKE_SA initiation, job load of %d exceeds "
+                                        "limit of %d", jobs, limit_job_load);
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, ike_sa);
+                               listener->child_cfg->destroy(listener->child_cfg);
+                               listener->status = INVALID_STATE;
+                               listener_done(listener);
+                               return JOB_REQUEUE_NONE;
+                       }
+               }
+       }
+
        if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
        {
                if (!listener->logger.callback)
@@ -391,7 +438,7 @@ METHOD(job_t, initiate_execute, job_requeue_t,
 
 METHOD(controller_t, initiate, status_t,
        private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-       controller_cb_t callback, void *param, u_int timeout)
+       controller_cb_t callback, void *param, u_int timeout, bool limits)
 {
        interface_job_t *job;
        status_t status;
@@ -414,6 +461,7 @@ METHOD(controller_t, initiate, status_t,
                        .child_cfg = child_cfg,
                        .peer_cfg = peer_cfg,
                        .lock = spinlock_create(),
+                       .limits = limits,
                },
                .public = {
                        .execute = _initiate_execute,
index 02f4ebb..5ffeac5 100644 (file)
@@ -82,15 +82,18 @@ struct controller_t {
         * @param cb                    logging callback
         * @param param                 parameter to include in each call of cb
         * @param timeout               timeout in ms to wait for callbacks, 0 to disable
+        * @param limits                whether to check limits regarding IKE_SA initiation
         * @return
         *                                              - SUCCESS, if CHILD_SA established
         *                                              - FAILED, if setup failed
         *                                              - NEED_MORE, if callback returned FALSE
         *                                              - OUT_OF_RES if timed out
+        *                                              - INVALID_STATE if limits prevented initiation
         */
        status_t (*initiate)(controller_t *this,
                                                 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-                                                controller_cb_t callback, void *param, u_int timeout);
+                                                controller_cb_t callback, void *param, u_int timeout,
+                                                bool limits);
 
        /**
         * Terminate an IKE_SA and all of its CHILD_SAs.
index 5f089f5..24076d4 100644 (file)
@@ -239,7 +239,7 @@ static bool on_accept(private_load_tester_control_t *this, stream_t *io)
 
                switch (charon->controller->initiate(charon->controller,
                                                                                peer_cfg, child_cfg->get_ref(child_cfg),
-                                                                               (void*)initiate_cb, listener, 0))
+                                                                               (void*)initiate_cb, listener, 0, FALSE))
                {
                        case NEED_MORE:
                                /* Callback returns FALSE once it got track of this IKE_SA.
index e684f22..c7380b9 100644 (file)
@@ -152,7 +152,7 @@ static job_requeue_t do_load_test(private_load_tester_plugin_t *this)
 
                charon->controller->initiate(charon->controller,
                                        peer_cfg, child_cfg->get_ref(child_cfg),
-                                       NULL, NULL, 0);
+                                       NULL, NULL, 0, FALSE);
                if (s)
                {
                        sleep(s);
index 1fb57b9..25b1383 100644 (file)
@@ -314,7 +314,7 @@ static job_requeue_t initiate_config(peer_cfg_t *peer_cfg)
                peer_cfg->get_ref(peer_cfg);
                enumerator->destroy(enumerator);
                charon->controller->initiate(charon->controller,
-                                                                        peer_cfg, child_cfg, NULL, NULL, 0);
+                                                                        peer_cfg, child_cfg, NULL, NULL, 0, FALSE);
        }
        else
        {
index 04bf382..2aa061f 100644 (file)
@@ -488,7 +488,7 @@ static void request_control_initiate(xmlTextReaderPtr reader,
                        {
                                status = charon->controller->initiate(charon->controller,
                                                        peer, child, (controller_cb_t)xml_callback,
-                                                       writer, 0);
+                                                       writer, 0, FALSE);
                        }
                        else
                        {
index 0084fbf..0125d17 100644 (file)
@@ -109,7 +109,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
        if (msg->output_verbosity < 0)
        {
                charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        NULL, NULL, 0);
+                                                                        NULL, NULL, 0, FALSE);
        }
        else
        {
@@ -118,7 +118,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
 
                status = charon->controller->initiate(charon->controller,
                                                        peer_cfg, child_cfg, (controller_cb_t)stroke_log,
-                                                       &info, this->timeout);
+                                                       &info, this->timeout, FALSE);
                switch (status)
                {
                        case SUCCESS:
index cebc389..a7d26e6 100644 (file)
@@ -147,7 +147,7 @@ static void initiate(private_uci_control_t *this, char *name)
                if (enumerator->enumerate(enumerator, &child_cfg) &&
                        charon->controller->initiate(charon->controller, peer_cfg,
                                                                child_cfg->get_ref(child_cfg),
-                                                               controller_cb_empty, NULL, 0) == SUCCESS)
+                                                               controller_cb_empty, NULL, 0, FALSE) == SUCCESS)
                {
                        write_fifo(this, "connection '%s' established\n", name);
                }
index d442bd6..ea6d295 100644 (file)
@@ -1589,7 +1589,7 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
                        DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg));
                        charon->controller->initiate(charon->controller,
                                        peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg),
-                                       NULL, NULL, 0);
+                                       NULL, NULL, 0, FALSE);
                        break;
                case ACTION_ROUTE:
                        DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg));
index 408d299..158e3d1 100644 (file)
@@ -184,8 +184,8 @@ CALLBACK(initiate, vici_message_t*,
        {
                return send_reply(this, "CHILD_SA config '%s' not found", child);
        }
-       switch (charon->controller->initiate(charon->controller,
-                               peer_cfg, child_cfg, (controller_cb_t)log_vici, &log, timeout))
+       switch (charon->controller->initiate(charon->controller, peer_cfg,
+                                       child_cfg, (controller_cb_t)log_vici, &log, timeout, FALSE))
        {
                case SUCCESS:
                        return send_reply(this, NULL);
index 17ab830..5b5fb9d 100644 (file)
@@ -119,8 +119,8 @@ METHOD(job_t, initiate, job_requeue_t,
                /* we need an additional reference because initiate consumes one */
                mediation_cfg->get_ref(mediation_cfg);
 
-               if (charon->controller->initiate(charon->controller, mediation_cfg,
-                               NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS)
+               if (charon->controller->initiate(charon->controller, mediation_cfg, NULL,
+                               (controller_cb_t)initiate_callback, this, 0, FALSE) != SUCCESS)
                {
                        mediation_cfg->destroy(mediation_cfg);
                        mediated_cfg->destroy(mediated_cfg);
index 981473b..5e88ac2 100644 (file)
@@ -61,7 +61,7 @@ METHOD(job_t, execute, job_requeue_t,
                                        charon->controller->initiate(charon->controller,
                                                                                                 peer_cfg->get_ref(peer_cfg),
                                                                                                 child_cfg->get_ref(child_cfg),
-                                                                                                NULL, NULL, 0);
+                                                                                                NULL, NULL, 0, FALSE);
                                        break;
                                case ACTION_ROUTE:
                                        DBG1(DBG_JOB, "start action: route '%s'", name);