Commit b4eaafe6 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

dnssec: implemented parallel signing of zone

parent 460ef628
......@@ -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.
......
......@@ -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
......
/* 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 },
......
/* 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"
......
/* 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);
}
......
/* 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 ??
......@@ -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;
}
......
......@@ -15,3 +15,12 @@
...
fun:call_rcu_memb
}
{
pthread/shared_stack
Memcheck:Leak
match-leak-kinds: possible,reachable
fun:calloc
...
fun:allocate_stack
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment