Show zone statistics counter(s). To print also counters with value 0, use
force option.
+**zone-serial-set** *zone* [[**+**]\ *serial*]
+ Set the zone SOA serial to the specified value. If the argument is prefixed with
+ **+**, the serial is incremented by that value (the special constant **MAX**
+ can be used to increment by the maximum allowed value 2147483647).
+ If the zone transaction is open, both reading and writing of the SOA serial
+ occur within that transaction. Otherwise, a short-lived transaction
+ is created and committed solely for setting the new SOA serial.
+ If no argument is specified, the current zone SOA serial is returned.
+
**conf-init**
Initialize the configuration database. If the database doesn't exist yet,
execute this command as an intended user to ensure the server is permitted
return ret;
}
-static int zone_txn_abort(zone_t *zone, _unused_ ctl_args_t *args)
+static int zone_txn_abort_l(zone_t *zone, _unused_ ctl_args_t *args)
{
- pthread_mutex_lock(&zone->cu_lock);
if (zone->control_update == NULL) {
args->suppress = true;
- pthread_mutex_unlock(&zone->cu_lock);
return KNOT_TXN_ENOTEXISTS;
}
if (zone->control_update->flags & UPDATE_WFEV) {
knot_sem_post(&zone->control_update->external);
- pthread_mutex_unlock(&zone->cu_lock);
return KNOT_EOK;
}
zone_control_clear(zone);
+ return KNOT_EOK;
+}
+static int zone_txn_abort(zone_t *zone, ctl_args_t *args)
+{
+ pthread_mutex_lock(&zone->cu_lock);
+ int ret = zone_txn_abort_l(zone, args);
pthread_mutex_unlock(&zone->cu_lock);
- return KNOT_EOK;
+ return ret;
+}
+
+static int zone_serial_set(zone_t *zone, ctl_args_t *args)
+{
+ int ret = KNOT_EOK;
+ const char *serial_set_str = args->data[KNOT_CTL_IDX_DATA];
+ const char *serial_inc_str = args->data[KNOT_CTL_IDX_TYPE];
+ bool forced = ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS], CTL_FLAG_FORCE);
+ bool serial_set_do = (serial_set_str != NULL);
+ bool serial_inc_do = (serial_inc_str != NULL && serial_inc_str[0] == '+');
+
+ uint32_t serial_set = 0;
+ if (serial_set_do) {
+ ret = str_to_u32(serial_set_str, &serial_set);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ rcu_read_lock();
+ const zone_contents_t *c = zone->contents;
+ if (c == NULL) {
+ rcu_read_unlock();
+ return KNOT_EEMPTYZONE;
+ }
+ uint32_t return_serial = zone_contents_serial(c);
+ rcu_read_unlock();
+
+ pthread_mutex_lock(&zone->cu_lock);
+ bool cu_exists = (zone->control_update != NULL);
+
+ if (serial_set_do && !cu_exists) {
+ ret = zone_txn_begin_l(zone, args);
+ }
+
+ if (zone->control_update != NULL && ret == KNOT_EOK &&
+ !node_rrtype_exists(zone->control_update->new_cont->apex, KNOT_RRTYPE_SOA)) {
+ ret = KNOT_EEMPTYZONE;
+ }
+
+ if (zone->control_update != NULL && ret == KNOT_EOK) {
+ return_serial = zone_update_current_serial(zone->control_update);
+ if (serial_inc_do) {
+ serial_set += return_serial;
+ }
+ if (serial_set_do) {
+ ret = zone_update_set_soa(zone->control_update, serial_set, !forced);
+ }
+ }
+
+ if (serial_set_do && !cu_exists) {
+ if (ret == KNOT_EOK) {
+ ret = zone_txn_commit_l(zone, args);
+ }
+ if (ret != KNOT_EOK) {
+ zone_txn_abort_l(zone, args);
+ }
+ }
+ pthread_mutex_unlock(&zone->cu_lock);
+
+ if (!serial_set_do && ret == KNOT_EOK) {
+ send_ctx_t *ctx = &ctl_globals[args->thread_idx].send_ctx;
+ ctx->data[KNOT_CTL_IDX_DATA] = ctx->ttl;
+ (void)snprintf(ctx->ttl, sizeof(ctx->ttl), "%u", return_serial);
+ ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &ctx->data);
+ }
+
+ return ret;
}
static int init_send_ctx(send_ctx_t *ctx, const knot_dname_t *zone_name,
}
case CTL_ZONE_STATS:
return zones_apply(args, zone_stats);
+ case CTL_ZONE_SERIAL_SET:
+ return zones_apply(args, zone_serial_set);
default:
assert(0);
return KNOT_EINVAL;
[CTL_ZONE_UNSET] = { "zone-unset", ctl_zone, CTL_LOCK_SRV_R },
[CTL_ZONE_PURGE] = { "zone-purge", ctl_zone, CTL_LOCK_SRV_W },
[CTL_ZONE_STATS] = { "zone-stats", ctl_zone, CTL_LOCK_SRV_R },
+ [CTL_ZONE_SERIAL_SET] = { "zone-serial-set", ctl_zone, CTL_LOCK_SRV_R },
[CTL_CONF_LIST] = { "conf-list", ctl_conf_list, CTL_LOCK_SRV_R }, // Can either read live conf or conf txn. The latter would deserve CTL_LOCK_SRV_W, but when conf txn exists, all cmds are done by single thread anyway.
[CTL_CONF_READ] = { "conf-read", ctl_conf_read, CTL_LOCK_SRV_R },
CTL_ZONE_UNSET,
CTL_ZONE_PURGE,
CTL_ZONE_STATS,
+ CTL_ZONE_SERIAL_SET,
CTL_CONF_LIST,
CTL_CONF_READ,
return zone_update_apply_changeset(update, &reverse);
}
-int zone_update_increment_soa(zone_update_t *update, conf_t *conf)
+int zone_update_set_soa(zone_update_t *update, uint32_t new_serial, bool semcheck)
{
- if (update == NULL || conf == NULL) {
+ if (update == NULL) {
return KNOT_EINVAL;
}
return KNOT_ENOMEM;
}
- int ret = zone_update_remove(update, soa_cpy);
- if (ret != KNOT_EOK) {
+ uint32_t old_serial = knot_soa_serial(soa_cpy->rrs.rdata);
+ if (semcheck && serial_compare(old_serial, new_serial) != SERIAL_LOWER) {
knot_rrset_free(soa_cpy, NULL);
- return ret;
+ return KNOT_ESOAINVAL;
}
- uint32_t old_serial = knot_soa_serial(soa_cpy->rrs.rdata);
+ int ret = zone_update_remove(update, soa_cpy);
+ if (ret == KNOT_EOK) {
+ knot_soa_serial_set(soa_cpy->rrs.rdata, new_serial);
+ ret = zone_update_add(update, soa_cpy);
+ }
+ knot_rrset_free(soa_cpy, NULL);
+
+ return ret;
+}
+
+int zone_update_increment_soa(zone_update_t *update, conf_t *conf)
+{
+ if (update == NULL || conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t old_serial = zone_update_current_serial(update);
uint32_t new_serial = serial_next(old_serial, conf, update->zone->name,
SERIAL_POLICY_AUTO, 1);
- if (serial_compare(old_serial, new_serial) != SERIAL_LOWER) {
+
+ int ret = zone_update_set_soa(update, new_serial, true);
+ if (ret == KNOT_ESOAINVAL) {
log_zone_warning(update->zone->name, "updated SOA serial is lower "
"than current, serial %u -> %u",
old_serial, new_serial);
- ret = KNOT_ESOAINVAL;
- } else {
- knot_soa_serial_set(soa_cpy->rrs.rdata, new_serial);
-
- ret = zone_update_add(update, soa_cpy);
}
- knot_rrset_free(soa_cpy, NULL);
return ret;
}
*/
int zone_update_apply_changeset_reverse(zone_update_t *update, const changeset_t *changes);
+/*!
+ * \brief Set SOA serial in the update.
+ *
+ * \param update Update to be modified.
+ * \param new_serial SOA serial to be set.
+ * \param semcheck Enable serial decrement check.
+ *
+ * \retval KNOT_ESOAINVAL if updated serial is lower than current and semcheck enabled.
+ * \return KNOT_E*
+ */
+int zone_update_set_soa(zone_update_t *update, uint32_t new_serial, bool semcheck);
+
/*!
* \brief Increment SOA serial (according to configured policy) in the update.
*
* \param update Update to be modified.
* \param conf Configuration.
*
+ * \retval KNOT_ESOAINVAL if updated serial is lower than current.
* \return KNOT_E*
*/
int zone_update_increment_soa(zone_update_t *update, conf_t *conf);
(value != NULL ? value : ""));
*empty = false;
break;
+ case CTL_ZONE_SERIAL_SET:
+ if (error != NULL) {
+ printf("error: (%s)", error);
+ *empty = false;
+ } else if (value != NULL) {
+ printf("%s", value);
+ *empty = false;
+ }
+ break;
default:
assert(0);
}
case CTL_ZONE_SET:
case CTL_ZONE_UNSET:
case CTL_ZONE_PURGE:
- printf("%s\n", failed ? "" : "OK");
+ case CTL_ZONE_SERIAL_SET:
+ printf("%s\n", (failed || !empty) ? "" : "OK");
break;
case CTL_STATUS:
case CTL_ZONE_STATUS:
return ctl_receive(args);
}
+static int cmd_zone_serial_ctl(cmd_args_t *args)
+{
+ int ret = check_args(args, 1, 2);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = *args->flags ? args->flags : NULL,
+ [KNOT_CTL_IDX_ZONE] = args->argv[0],
+ };
+
+ if (args->argc > 1) {
+ bool incr = args->argv[1][0] == '+';
+ const char *value = incr ? args->argv[1] + 1 : args->argv[1];
+ if (incr && strcmp("MAX", value) == 0) {
+ value = "2147483647";
+ }
+ data[KNOT_CTL_IDX_TYPE] = incr ? "+" : "=";
+ data[KNOT_CTL_IDX_DATA] = value;
+ }
+
+ CTL_SEND_DATA
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
const filter_desc_t conf_import_filters[] = {
{ "+nopurge" },
{ NULL },
{ CMD_ZONE_UNSET, cmd_zone_node_ctl, CTL_ZONE_UNSET, CMD_FREQ_ZONE },
{ CMD_ZONE_PURGE, cmd_zone_ctl, CTL_ZONE_PURGE, CMD_FREQ_ZONE | CMD_FOPT_ZONE | CMD_FOPT_FILTER },
{ CMD_ZONE_STATS, cmd_stats_ctl, CTL_ZONE_STATS, CMD_FREQ_ZONE },
+ { CMD_ZONE_SERIAL_SET, cmd_zone_serial_ctl, CTL_ZONE_SERIAL_SET, CMD_FREQ_ZONE },
{ CMD_CONF_INIT, cmd_conf_init, CTL_NONE, CMD_FWRITE },
{ CMD_CONF_CHECK, cmd_conf_check, CTL_NONE, CMD_FREAD | CMD_FREQ_MOD | CMD_FLOG_MORE },
{ CMD_ZONE_UNSET, "<zone> <owner> [<type> [<rdata>]]", "Remove zone data within the transaction." },
{ CMD_ZONE_PURGE, "<zone>... [<filter>...]", "Purge zone data, zone file, journal, timers, and KASP data. (#)" },
{ CMD_ZONE_STATS, "<zone> [<module>[.<counter>]]", "Show zone statistics counter(s)."},
+ { CMD_ZONE_SERIAL_SET, "<zone> [[+]<number>]", "Get/set/increment SOA serial of given zone. (#)" },
{ "", "", "" },
{ CMD_CONF_INIT, "", "Initialize the confdb. (*)" },
{ CMD_CONF_CHECK, "", "Check the server configuration. (*)" },
#define CMD_ZONE_UNSET "zone-unset"
#define CMD_ZONE_PURGE "zone-purge"
#define CMD_ZONE_STATS "zone-stats"
+#define CMD_ZONE_SERIAL_SET "zone-serial-set"
#define CMD_CONF_INIT "conf-init"
#define CMD_CONF_CHECK "conf-check"
"zone-sign", "zone-keys-load", "zone-ksk-submitted", "zone-freeze",
"zone-thaw", "zone-xfr-freeze", "zone-xfr-thaw", "zone-read", "zone-get",
"zone-stats", "conf-init", "conf-list", "conf-read", "conf-diff",
- "conf-get"])
+ "conf-get", "zone-serial-set"])
if cmd[0:5] == "zone-" and random.choice([False, True, True]):
cmd += " " + zone_name
+ if cmd == "zone-serial-set" and random.choice([False, True, True]):
+ cmd += " " + random.choice(["+", "="]) + str(random.randint(0, 4000000000))
if random.choice([False, True]):
cmd = "-b " + cmd
try:
def ctl_update(server, zone_name):
ctl_txn_generic(server, "-b zone-begin " + zone_name,
- "zone-set " + zone_name + " abc 3600 A 1.2.3." + str(random.randint(1, 254)),
+ random.choice(["zone-set " + zone_name + " abc 3600 A 1.2.3." + str(random.randint(1, 254)),
+ "zone-serial-set " + zone_name + " " + random.choice(["+", "="]) + str(random.randint(0, 4000000000))]),
"zone-commit " + zone_name, "zone-abort " + zone_name, True)
def conf_update(server, zone_name):