]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
dnssec: implemented parallel signing of zone
authorLibor Peltan <libor.peltan@nic.cz>
Fri, 30 Nov 2018 13:28:13 +0000 (14:28 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Wed, 9 Jan 2019 16:19:41 +0000 (17:19 +0100)
doc/man/knot.conf.5in
doc/reference.rst
src/knot/conf/schema.c
src/knot/conf/schema.h
src/knot/dnssec/context.c
src/knot/dnssec/kasp/policy.h
src/knot/dnssec/zone-sign.c
tests-extra/data/knot.supp

index 2f21e09d47facc247f446c5e2ed20ba6d5375b29..53dae38d94d55427f1fe0d5e936d92663cc98e5b 100644 (file)
@@ -673,6 +673,7 @@ policy:
     nsec3\-opt\-out: BOOL
     nsec3\-salt\-length: INT
     nsec3\-salt\-lifetime: TIME
+    signing\-threads: INT
     ksk\-submission: submission_id
     cds\-cdnskey\-publish: none | delete\-dnssec | rollover | always
     offline\-ksk: BOOL
@@ -867,6 +868,20 @@ A reference to \fI\%submission\fP section holding parameters of
 KSK submittion checks.
 .sp
 \fIDefault:\fP not set
+.SS signing\-threads
+.sp
+When signing zone or update, use this number of threads for parallel signing.
+.sp
+Those are extra threads independent of \fI\%Background workers\fP\&.
+.sp
+\fBNOTE:\fP
+.INDENT 0.0
+.INDENT 3.5
+Some steps of the DNSSEC signing operation are not parallelized.
+.UNINDENT
+.UNINDENT
+.sp
+\fIDefault:\fP 1 (no extra threads)
 .SS cds\-cdnskey\-publish
 .sp
 Controls if and how shall the CDS and CDNSKEY be published in the zone.
index 26ead741ec928b29f0b4dca6c36485ca56b023da..5723d75f31713714b39b7fda2abcecbf204f9725 100644 (file)
@@ -745,6 +745,7 @@ DNSSEC policy configuration.
      nsec3-opt-out: BOOL
      nsec3-salt-length: INT
      nsec3-salt-lifetime: TIME
+     signing-threads: INT
      ksk-submission: submission_id
      cds-cdnskey-publish: none | delete-dnssec | rollover | always
      offline-ksk: BOOL
@@ -984,6 +985,20 @@ KSK submittion checks.
 
 *Default:* not set
 
+.. _policy_signing-threads:
+
+signing-threads
+---------------
+
+When signing zone or update, use this number of threads for parallel signing.
+
+Those are extra threads independent of :ref:`Background workers<server_background-workers>`.
+
+.. NOTE::
+   Some steps of the DNSSEC signing operation are not parallelized.
+
+*Default:* 1 (no extra threads)
+
 .. _policy_cds-cdnskey-publish:
 
 cds-cdnskey-publish
index f6f7dd8c3c0f8c5a65145ec39509d7c0de0dc849..e93740e6daf5e6da5dd224a6814bf9957e1b74c3 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -288,6 +288,7 @@ static const yp_item_t desc_policy[] = {
                                           CONF_IO_FRLD_ZONES },
        { C_KSK_SBM,             YP_TREF,  YP_VREF = { C_SBM }, CONF_IO_FRLD_ZONES,
                                           { check_ref } },
+       { C_SIGNING_THREADS,     YP_TINT,  YP_VINT = { 1, UINT16_MAX, 1 } },
        { C_CHILD_RECORDS,       YP_TOPT,  YP_VOPT = { child_record, CHILD_RECORDS_ALWAYS } },
        { C_OFFLINE_KSK,         YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
        { C_COMMENT,             YP_TSTR,  YP_VNONE },
index 39ab31c89353a3b2b3732800e0cb8c51ce3c0561..2fe1ce416b53fa5a7736de4458290b4039cfac05 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -96,6 +96,7 @@
 #define C_SEM_CHECKS           "\x0F""semantic-checks"
 #define C_SERIAL_POLICY                "\x0D""serial-policy"
 #define C_SERVER               "\x06""server"
+#define C_SIGNING_THREADS      "\x0F""signing-threads"
 #define C_SINGLE_TYPE_SIGNING  "\x13""single-type-signing"
 #define C_SRV                  "\x06""server"
 #define C_STATS                        "\x0A""statistics"
index 549e95f4cb997fb33c6694c7367f363e195ad3b1..660677b4c7144c71a2ffe24609df3f36f2b8a787 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -118,6 +118,9 @@ static void policy_load(knot_kasp_policy_t *policy, conf_val_t *id)
                }
        }
 
+       val = conf_id_get(conf(), C_POLICY, C_SIGNING_THREADS, id);
+       policy->signing_threads = conf_int(&val);
+
        val = conf_id_get(conf(), C_POLICY, C_OFFLINE_KSK, id);
        policy->offline_ksk = conf_bool(&val);
 }
index 86539a8ab6d985ae4d3ec80643b1fc5f662ac20d..b5c05593a7f34464860c35414d0bfef7877c9560 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -116,6 +116,7 @@ typedef struct {
        uint32_t ksk_sbm_check_interval;
        unsigned child_records_publish;
        parent_dynarray_t parents;
+       uint16_t signing_threads;
        bool offline_ksk;
 } knot_kasp_policy_t;
 // TODO make the time parameters knot_timediff_t ??
index f29fec93a22fdcaf0842ee60c04e30d11e4be12e..c704b0be780a1c0c8b655cfe81fbd557033eaeb7 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <assert.h>
+#include <pthread.h>
 #include <sys/types.h>
 
 #include "libdnssec/error.h"
@@ -508,10 +509,17 @@ static int sign_node_rrsets(const zone_node_t *node,
 /*!
  * \brief Struct to carry data for 'sign_data' callback function.
  */
-typedef struct node_sign_args {
+typedef struct {
+       zone_tree_t *tree;
        zone_sign_ctx_t *sign_ctx;
-       changeset_t *changeset;
+       changeset_t changeset;
        knot_time_t expires_at;
+       size_t num_threads;
+       size_t thread_index;
+       size_t rrset_index;
+       int errcode;
+       int thread_init_errcode;
+       pthread_t thread;
 } node_sign_args_t;
 
 /*!
@@ -535,44 +543,112 @@ static int sign_node(zone_node_t **node, void *data)
                return KNOT_EOK;
        }
 
+       if (args->rrset_index++ % args->num_threads != args->thread_index) {
+               return KNOT_EOK;
+       }
+
        int result = sign_node_rrsets(*node, args->sign_ctx,
-                                     args->changeset, &args->expires_at);
+                                     &args->changeset, &args->expires_at);
 
        return result;
 }
 
+static void *tree_sign_thread(void *_arg)
+{
+       node_sign_args_t *arg = _arg;
+       arg->errcode = zone_tree_apply(arg->tree, sign_node, _arg);
+       return NULL;
+}
+
 /*!
  * \brief Update RRSIGs in a given zone tree by updating changeset.
  *
  * \param tree        Zone tree to be signed.
+ * \param num_threads Number of threads to use for parallel signing.
  * \param zone_keys   Zone keys.
  * \param policy      DNSSEC policy.
- * \param changeset   Changeset to be updated.
+ * \param update      Zone update structure to be updated.
  * \param expires_at  Expiration time of the oldest signature in zone.
  *
  * \return Error code, KNOT_EOK if successful.
  */
 static int zone_tree_sign(zone_tree_t *tree,
+                          size_t num_threads,
                           zone_keyset_t *zone_keys,
                           const kdnssec_ctx_t *dnssec_ctx,
-                          changeset_t *changeset,
+                          zone_update_t *update,
                           knot_time_t *expires_at)
 {
        assert(zone_keys);
        assert(dnssec_ctx);
-       assert(changeset);
+       assert(update);
 
-       node_sign_args_t args = {
-               .sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx),
-               .changeset = changeset,
-               .expires_at = knot_time_add(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime),
-       };
+       int ret = KNOT_EOK;
+       node_sign_args_t args[num_threads];
+       memset(args, 0, sizeof(args));
+       *expires_at = knot_time_add(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime);
+
+       // init context structures
+       for (size_t i = 0; i < num_threads; i++) {
+               args[i].tree = tree;
+               args[i].sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
+               if (args[i].sign_ctx == NULL) {
+                       ret = KNOT_ENOMEM;
+                       break;
+               }
+               ret = changeset_init(&args[i].changeset, update->zone->name);
+               if (ret != KNOT_EOK) {
+                       break;
+               }
+               args[i].expires_at = 0;
+               args[i].num_threads = num_threads;
+               args[i].thread_index = i;
+               args[i].rrset_index = 0;
+               args[i].errcode = KNOT_EOK;
+               args[i].thread_init_errcode = -1;
+       }
+       if (ret != KNOT_EOK) {
+               for (size_t i = 0; i < num_threads; i++) {
+                       changeset_clear(&args[i].changeset);
+                       zone_sign_ctx_free(args[i].sign_ctx);
+               }
+               return ret;
+       }
 
-       int result = zone_tree_apply(tree, sign_node, &args);
-       *expires_at = args.expires_at;
+       if (num_threads == 1) {
+               args[0].thread_init_errcode = 0;
+               tree_sign_thread(&args[0]);
+       } else {
+               // start working threads
+               for (size_t i = 0; i < num_threads; i++) {
+                       args[i].thread_init_errcode =
+                               pthread_create(&args[i].thread, NULL, tree_sign_thread, &args[i]);
+               }
 
-       zone_sign_ctx_free(args.sign_ctx);
-       return result;
+               // join those threads that have been really started
+               for (size_t i = 0; i < num_threads; i++) {
+                       if (args[i].thread_init_errcode == 0) {
+                               args[i].thread_init_errcode = pthread_join(args[i].thread, NULL);
+                       }
+               }
+       }
+
+       // collect return code and results
+       for (size_t i = 0; i < num_threads && ret == KNOT_EOK; i++) {
+               if (args[i].thread_init_errcode != 0) {
+                       ret = knot_map_errno_code(args[i].thread_init_errcode);
+               } else {
+                       ret = args[i].errcode;
+                       if (ret == KNOT_EOK) {
+                               ret = zone_update_apply_changeset(update, &args[i].changeset); // _fix not needed
+                               *expires_at = knot_time_min(*expires_at, args[i].expires_at);
+                       }
+               }
+               changeset_clear(&args[i].changeset);
+               zone_sign_ctx_free(args[i].sign_ctx);
+       }
+
+       return ret;
 }
 
 /*- private API - signing of NSEC(3) in changeset ----------------------------*/
@@ -824,38 +900,29 @@ int knot_zone_sign(zone_update_t *update,
                    const kdnssec_ctx_t *dnssec_ctx,
                    knot_time_t *expire_at)
 {
-       if (!update || !zone_keys || !dnssec_ctx || !expire_at) {
+       if (!update || !zone_keys || !dnssec_ctx || !expire_at ||
+           dnssec_ctx->policy->signing_threads < 1) {
                return KNOT_EINVAL;
        }
 
        int result;
 
-       changeset_t ch;
-       result = changeset_init(&ch, update->new_cont->apex->owner);
-       if (result != KNOT_EOK) {
-               return result;
-       }
-
        knot_time_t normal_expire = 0;
-       result = zone_tree_sign(update->new_cont->nodes, zone_keys, dnssec_ctx, &ch, &normal_expire);
+       result = zone_tree_sign(update->new_cont->nodes, dnssec_ctx->policy->signing_threads,
+                               zone_keys, dnssec_ctx, update, &normal_expire);
        if (result != KNOT_EOK) {
-               changeset_clear(&ch);
                return result;
        }
 
        knot_time_t nsec3_expire = 0;
-       result = zone_tree_sign(update->new_cont->nsec3_nodes, zone_keys, dnssec_ctx,
-                               &ch, &nsec3_expire);
+       result = zone_tree_sign(update->new_cont->nsec3_nodes, dnssec_ctx->policy->signing_threads,
+                               zone_keys, dnssec_ctx, update, &nsec3_expire);
        if (result != KNOT_EOK) {
-               changeset_clear(&ch);
                return result;
        }
 
        *expire_at = knot_time_min(normal_expire, nsec3_expire);
 
-       result = zone_update_apply_changeset(update, &ch); // _fix not needed
-       changeset_clear(&ch);
-
        return result;
 }
 
index 236cf61d1ce3914f9d6ad140a6e7acae618495c6..8704f209e88fb387290f2edc5cb76f5f6e94056f 100644 (file)
    ...
    fun:call_rcu_memb
 }
+
+{
+   pthread/shared_stack
+   Memcheck:Leak
+   match-leak-kinds: possible,reachable
+   fun:calloc
+   ...
+   fun:allocate_stack
+}