Commit 794ff6dc authored by Dominik Taborsky's avatar Dominik Taborsky

zone-api: changesets do not remove and add the same RRSets at the same time.

parent 6369a2ed
......@@ -307,6 +307,6 @@ $ kdig +tcp example.com \-t A @192.0.2.1 \-x 2001:DB8::1 @192.0.2.2
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -372,6 +372,6 @@ $ keymgr tsig generate operator.key algorithm hmac\-sha512
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -166,6 +166,6 @@ $ khost \-t AXFR \-v example.com
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -973,6 +973,6 @@ A module identifier.
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -67,6 +67,6 @@ Print help and usage.
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -256,6 +256,6 @@ $ knotc conf\-commit
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -58,6 +58,6 @@ Print help and usage.
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -82,6 +82,6 @@ A1RT98BS5QGC9NFI51S9HCI47ULJG6JH (salt=\-, hash=1, iterations=0)
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -209,6 +209,6 @@ $ knsupdate
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2015, CZ.NIC, z.s.p.o.
Copyright 2010–2016, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
......@@ -25,8 +25,19 @@
/* -------------------- Changeset iterator helpers -------------------------- */
/*! \brief Adds RRSet to given zone. */
static int add_rr_to_zone(zone_contents_t *z, const knot_rrset_t *rrset)
static int add_rr_to_zone(zone_contents_t *z, knot_rrset_t **soa, const knot_rrset_t *rrset)
{
if (rrset->type == KNOT_RRTYPE_SOA) {
if (*soa == NULL) {
*soa = knot_rrset_copy(rrset, NULL);
if (*soa == NULL) {
return KNOT_ENOMEM;
}
}
// Do not add SOAs into actual contents.
return KNOT_EOK;
}
zone_node_t *n = NULL;
int ret = zone_contents_add_rr(z, rrset, &n);
UNUSED(n);
......@@ -124,6 +135,57 @@ static knot_rrset_t get_next_rr(changeset_iter_t *ch_it, hattrie_iter_t *t_it) /
return node_rrset_at(ch_it->node, ch_it->node_pos++);
}
static bool intersection_exists(const knot_rrset_t *node_rr, const knot_rrset_t *inc_rr)
{
knot_rdataset_t intersection;
knot_rdataset_init(&intersection);
int ret = knot_rdataset_intersect(&node_rr->rrs, &inc_rr->rrs, &intersection, NULL);
if (ret != KNOT_EOK) {
return false;
}
const uint16_t rr_count = intersection.rr_count;
knot_rdataset_clear(&intersection, NULL);
return rr_count > 0;
}
static bool need_to_insert(zone_contents_t *counterpart, const knot_rrset_t *rr)
{
zone_node_t *node = zone_contents_find_node_for_rr(counterpart, rr);
if (node == NULL) {
return true;
}
if (!node_rrtype_exists(node, rr->type)) {
return true;
}
knot_rrset_t node_rr = node_rrset(node, rr->type);
if (!intersection_exists(&node_rr, rr)) {
return true;
}
// Subtract the data from node's RRSet.
int ret = knot_rdataset_subtract(&node->rrs->rrs, &rr->rrs, NULL);
if (ret != KNOT_EOK) {
return true;
}
if (knot_rrset_empty(&node_rr)) {
// Remove empty type.
node_remove_rdataset(node, rr->type);
}
if (node->rrset_count == 0) {
// Remove empty node.
zone_tree_t *t = zone_contents_rrset_is_nsec3rel(rr) ? counterpart->nsec3_nodes :
counterpart->nodes;
zone_contents_delete_empty_node(counterpart, t, node);
}
return false;
}
/* ------------------------------- API -------------------------------------- */
int changeset_init(changeset_t *ch, const knot_dname_t *apex)
......@@ -211,12 +273,20 @@ size_t changeset_size(const changeset_t *ch)
int changeset_add_rrset(changeset_t *ch, const knot_rrset_t *rrset)
{
return add_rr_to_zone(ch->add, rrset);
/* Check if there's any removal and remove that, then add this
* addition anyway. Required to change TTLs. */
need_to_insert(ch->remove, rrset);
return add_rr_to_zone(ch->add, &ch->soa_to, rrset);
}
int changeset_rem_rrset(changeset_t *ch, const knot_rrset_t *rrset)
{
return add_rr_to_zone(ch->remove, rrset);
if (need_to_insert(ch->add, rrset)) {
return add_rr_to_zone(ch->remove, &ch->soa_from, rrset);
} else {
return KNOT_EOK;
}
}
int changeset_merge(changeset_t *ch1, const changeset_t *ch2)
......
......@@ -632,6 +632,11 @@ static int process_rem_rr(const knot_rrset_t *rr,
const zone_node_t *node,
zone_update_t *update)
{
if (node == NULL) {
// Removing from node that does not exist
return KNOT_EOK;
}
const bool apex_ns = node_rrtype_exists(node, KNOT_RRTYPE_SOA) &&
rr->type == KNOT_RRTYPE_NS;
if (apex_ns) {
......@@ -647,13 +652,6 @@ static int process_rem_rr(const knot_rrset_t *rr,
}
}
// Remove possible previously added RR
remove_rr_from_changeset(update->change.add, rr);
if (node == NULL) {
// Removing from node that did not exists before update
return KNOT_EOK;
}
knot_rrset_t to_modify = node_rrset(node, rr->type);
if (knot_rrset_empty(&to_modify)) {
// No such RRSet
......@@ -674,7 +672,7 @@ static int process_rem_rr(const knot_rrset_t *rr,
return KNOT_EOK;
}
assert(intersection.rrs.rr_count == 1);
ret = rem_rr_to_chgset(&intersection, update);
ret = zone_update_remove(update, &intersection);
knot_rdataset_clear(&intersection.rrs, NULL);
return ret;
}
......@@ -696,7 +694,7 @@ static int process_rem_rrset(const knot_rrset_t *rrset,
}
// Remove all previously added RRs with this owner and type from chgset
remove_header_from_changeset(update->change.add, rrset);
//remove_header_from_changeset(update->change.add, rrset);
if (node == NULL) {
// no such node in zone, ignore
......@@ -710,6 +708,8 @@ static int process_rem_rrset(const knot_rrset_t *rrset,
knot_rrset_t to_remove = node_rrset(node, rrset->type);
return rem_rrset_to_chgset(&to_remove, update);
//#warning why doesn't this work?
//return zone_update_remove(update, &to_remove);
}
/*!< \brief Removes node from zone. */
......@@ -717,7 +717,7 @@ static int process_rem_node(const knot_rrset_t *rr,
const zone_node_t *node, zone_update_t *update)
{
// Remove all previously added records with given owner from changeset
remove_owner_from_changeset(update->change.add, rr->owner);
//remove_owner_from_changeset(update->change.add, rr->owner);
if (node == NULL) {
return KNOT_EOK;
......
......@@ -643,7 +643,7 @@ static int recreate_nsec3_tree(const zone_contents_t *z, zone_contents_t *out)
return KNOT_EOK;
}
static bool rrset_is_nsec3rel(const knot_rrset_t *rr)
bool zone_contents_rrset_is_nsec3rel(const knot_rrset_t *rr)
{
if (rr == NULL) {
return false;
......@@ -662,7 +662,7 @@ int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr,
return KNOT_EINVAL;
}
return insert_rr(z, rr, n, rrset_is_nsec3rel(rr));
return insert_rr(z, rr, n, zone_contents_rrset_is_nsec3rel(rr));
}
const zone_node_t *zone_contents_find_node(const zone_contents_t *zone,
......@@ -734,7 +734,7 @@ static zone_node_t *get_previous(const zone_contents_t *zone,
int exact_match = find_in_tree(zone->nodes, name, &found, &prev);
assert(exact_match >= 0);
assert(prev != NULL);
//assert(prev != NULL);
return prev;
}
......@@ -1107,7 +1107,7 @@ zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrs
return NULL;
}
const bool nsec3 = rrset_is_nsec3rel(rrset);
const bool nsec3 = zone_contents_rrset_is_nsec3rel(rrset);
zone_node_t *node = nsec3 ? get_nsec3_node(zone, rrset->owner) :
get_node(zone, rrset->owner);
if (node == NULL) {
......@@ -1130,7 +1130,72 @@ zone_node_t *zone_contents_find_node_for_rr(zone_contents_t *zone, const knot_rr
return NULL;
}
const bool nsec3 = rrset_is_nsec3rel(rrset);
const bool nsec3 = zone_contents_rrset_is_nsec3rel(rrset);
return nsec3 ? get_nsec3_node(zone, rrset->owner) :
get_node(zone, rrset->owner);
}
zone_node_t *zone_contents_greatest_child(const zone_contents_t *zone, const knot_dname_t *parent)
{
if (knot_dname_size(parent) + 2 > KNOT_DNAME_MAXLEN) {
// Not enough space for children.
return NULL;
}
knot_dname_t dn[KNOT_DNAME_MAXLEN] = { 0x01, 0xff };
knot_dname_to_wire(dn + 2, parent, KNOT_DNAME_MAXLEN);
zone_node_t *child = get_node(zone, dn);
if (child) {
return child;
}
child = get_previous(zone, dn);
if (!child) {
return NULL;
}
//assert(child);
const int parent_labels = knot_dname_labels(parent, NULL);
const int child_labels = knot_dname_labels(child->owner, NULL);
if (child_labels <= parent_labels) {
return NULL;
}
if (knot_dname_matched_labels(parent, child->owner) != parent_labels) {
return NULL;
}
return child;
}
static bool contents_has_children(const zone_contents_t *zone, const knot_dname_t *owner)
{
return zone_contents_greatest_child(zone, owner) != NULL;
}
void zone_contents_delete_empty_node(zone_contents_t *zone, zone_tree_t *tree, zone_node_t *node)
{
assert(zone);
assert(tree);
assert(node);
if (node->rrset_count == 0 && !contents_has_children(zone, node->owner)) {
const knot_dname_t *parent_dname = knot_wire_next_label(node->owner, NULL);
zone_node_t *parent_node = NULL;
if (tree == zone->nsec3_nodes) {
// Only one level in NSEC3 tree
parent_node = (node == zone->apex) ? NULL : zone->apex;
} else {
parent_node = zone_contents_find_node(zone, parent_dname);
}
if (parent_node && parent_node != zone->apex) {
// Recurse using the parent node, do not delete possibly empty parent.
zone_contents_delete_empty_node(zone, tree, parent_node);
}
// Delete node
zone_node_t *removed_node = NULL;
zone_tree_remove(tree, node->owner, &removed_node);
UNUSED(removed_node);
node_free(&node, NULL);
}
}
......@@ -50,6 +50,10 @@ typedef int (*zone_contents_apply_cb_t)(zone_node_t *node, void *data);
zone_contents_t *zone_contents_new(const knot_dname_t *apex_name);
bool zone_contents_rrset_is_nsec3rel(const knot_rrset_t *rr);
int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n);
/*!
......@@ -272,4 +276,5 @@ zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrs
zone_node_t *zone_contents_find_node_for_rr(zone_contents_t *zone, const knot_rrset_t *rrset);
void zone_contents_delete_empty_node(zone_contents_t *zone, zone_tree_t *tree, zone_node_t *node);
/*! @} */
......@@ -53,9 +53,9 @@ int main(int argc, char *argv[])
ok(changeset_size(ch) == 1, "changeset: size add");
ret = changeset_rem_rrset(ch, apex_txt_rr);
ok(ret == KNOT_EOK, "changeset: rem RRSet");
ok(changeset_size(ch) == 2, "changeset: size remove");
ok(!changeset_empty(ch), "changeset: not empty");
ok(changeset_size(ch) == 0, "changeset: size remove");
ok(changeset_empty(ch), "changeset: empty");
changeset_add_rrset(ch, apex_txt_rr);
// Add another RR to node.
knot_rrset_t *apex_spf_rr = knot_rrset_new(d, KNOT_RRTYPE_SPF, KNOT_CLASS_IN, NULL);
......@@ -92,6 +92,9 @@ int main(int argc, char *argv[])
changeset_iter_clear(&it);
ok(knot_rrset_empty(&iter), "changeset: traversal: skip non-terminals");
changeset_rem_rrset(ch, apex_txt_rr);
changeset_rem_rrset(ch, apex_txt_rr);
// Test remove traversal.
ret = changeset_iter_rem(&it, ch, false);
ok(ret == KNOT_EOK, "changeset: create iter rem");
......@@ -110,7 +113,7 @@ int main(int argc, char *argv[])
iter = changeset_iter_next(&it);
}
changeset_iter_clear(&it);
ok(size == 4, "changeset: iter all");
ok(size == 3, "changeset: iter all");
// Create new changeset.
knot_dname_free(&d, NULL);
......@@ -136,7 +139,7 @@ int main(int argc, char *argv[])
// Test merge.
ret = changeset_merge(ch, ch2);
ok(ret == KNOT_EOK && changeset_size(ch) == 6, "changeset: merge");
ok(ret == KNOT_EOK && changeset_size(ch) == 5, "changeset: merge");
// Test cleanup.
changeset_clear(ch);
......
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