Hi!

Thank you very much for quick answer! Tried it on 5.1 stable in the spirit on applying bind patch i.e. saying

# cd /usr/src
# patch -p0 < /usr/src/nsd.patch
# cd usr.sbin/nsd
# make -f Makefile.bsd-wrapper obj
# make -f Makefile.bsd-wrapper depend
# make -f Makefile.bsd-wrapper
# make -f Makefile.bsd-wrapper install

And restarting nsd.

I specifically copied zone before and after several times and got respectivele load and no load. Also checked that zone content is all right after copying. At the same time i realize that my testing is not thorough.

Do you think it is safe for me to start using this patch in production or your people do some more testing and eventually publish this patch as 002_nsd.patch for OpenBSD v. 5.1?


Best regards,

Imre


On 05/28/12 23:12, Stuart Henderson wrote:
On 2012-05-28, Imre Oolberg<[email protected]>  wrote:
Hi!

I am having trouble on OpenBSD v. 5.1 using NSD nameserver.

When slave NSD name server receives zone update and reloads it into its
database high and sustained user load (about 1-2) is generated on cpu
depending on hardware from 3 minutes to 10 minutes. Also this kind on
load is observed when doing nsdc patch. It seems to happen only when
zone has many RRs, say 100k NS lines; using NSD with OpenBSD v. 4.8 from
packages does not have this issue, also not 5.1-current, but 5.1 does; i
have tried and got similar results on amd64 and i386, happens on
both; Normally this kind of reload and patch takes several seconds only.

I would be very thankful if somebody could have a look at it and confirm
this behaviour. And if really nsd on 5.1 is to blame may i add that
patch would be very much welcomed! :)

This is due to a bug introduced with NSD 3.2.9 and fixed shortly afterwards.
The _untested_ diff against -stable below may fix it.

Index: difffile.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/difffile.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 difffile.c
--- difffile.c  29 Jan 2012 11:15:31 -0000      1.1.1.5
+++ difffile.c  28 May 2012 20:10:31 -0000
@@ -261,14 +261,43 @@ has_data_below(domain_type* top)
        /* in the canonical ordering subdomains are after this name */
        d = domain_next(d);
        while(d != NULL&&  dname_is_subdomain(domain_dname(d), 
domain_dname(top))) {
-               if(d->is_existing)
+               if(d->is_existing) {
                        return 1;
+               }
                d = domain_next(d);
        }
        return 0;
  }

-static void
+
+/* this routine makes empty terminals non-existent.
+ * @domain the lowest empty terminal
+ * @ce the closest encloser
+ */
+static domain_type*
+rrset_delete_empty_terminals(domain_type* domain, domain_type* ce)
+{
+       assert(domain);
+       if (domain->rrsets == 0) {
+               /* if there is no data below it, it becomes non existing.
+                  also empty nonterminals above it become nonexisting */
+               /* check for data below this node. */
+               if(!has_data_below(domain)) {
+                       /* nonexist this domain and all parent empty 
nonterminals */
+                       domain_type* p = domain;
+                       while(p != NULL&&  p->rrsets == 0) {
+                               if(p == ce || has_data_below(p))
+                                       return p;
+                               p->is_existing = 0;
+                               p = p->parent;
+                       }
+               }
+       }
+       return NULL;
+}
+
+
+static domain_type*
  rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
  {
        int i;
@@ -279,7 +308,7 @@ rrset_delete(namedb_type* db, domain_typ
        }
        if(!*pp) {
                /* rrset does not exist for domain */
-               return;
+               return NULL;
        }
        *pp = rrset->next;

@@ -320,23 +349,13 @@ rrset_delete(namedb_type* db, domain_typ
                sizeof(rr_type) * rrset->rr_count);
        region_recycle(db->region, rrset, sizeof(rrset_type));

+       rrset->rr_count = 0;
+
        /* is the node now an empty node (completely deleted) */
-       if(domain->rrsets == 0) {
-               /* if there is no data below it, it becomes non existing.
-                  also empty nonterminals above it become nonexisting */
-               /* check for data below this node. */
-               if(!has_data_below(domain)) {
-                       /* nonexist this domain and all parent empty 
nonterminals */
-                       domain_type* p = domain;
-                       while(p != NULL&&  p->rrsets == 0) {
-                               if(has_data_below(p))
-                                       break;
-                               p->is_existing = 0;
-                               p = p->parent;
-                       }
-               }
+       if (domain->rrsets == 0) {
+               return domain;
        }
-       rrset->rr_count = 0;
+       return NULL;
  }

  static int
@@ -384,6 +403,7 @@ find_rr_num(rrset_type* rrset,
  static int
  delete_RR(namedb_type* db, const dname_type* dname,
        uint16_t type, uint16_t klass,
+       domain_type* prevdomain,
        buffer_type* packet, size_t rdatalen, zone_type *zone,
        region_type* temp_region, int is_axfr)
  {
@@ -442,7 +462,11 @@ delete_RR(namedb_type* db, const dname_t

                if(rrset->rr_count == 1) {
                        /* delete entire rrset */
-                       rrset_delete(db, domain, rrset);
+                       domain = rrset_delete(db, domain, rrset);
+                       if (domain&&  !domain->nextdiff) {
+                               /* this domain is not yet in the diff chain */
+                               prevdomain->nextdiff = domain;
+                       }
                } else {
                        /* swap out the bad RR and decrease the count */
                        rr_type* rrs_orig = rrset->rrs;
@@ -683,6 +707,8 @@ delete_zone_rrs(namedb_type* db, zone_ty
  {
        rrset_type *rrset;
        domain_type *domain = zone->apex;
+       domain_type *ce = NULL;
+       domain_type *next = NULL;
        zone->updated = 1;
  #ifdef NSEC3
  #ifndef FULL_PREHASH
@@ -698,10 +724,13 @@ delete_zone_rrs(namedb_type* db, zone_ty
                        dname_to_string(domain_dname(domain),0)));
                /* delete all rrsets of the zone */
                while((rrset = domain_find_any_rrset(domain, zone))) {
-                       rrset_delete(db, domain, rrset);
+                       (void)rrset_delete(db, domain, rrset);
                }
-               domain = domain_next(domain);
+               next = domain_next(domain);
+               domain->nextdiff = next;
+               domain = next;
        }
+
  #ifdef NSEC3
  #ifndef FULL_PREHASH
        if (0 != zone_nsec3_domains_create(db, zone)) {
@@ -743,6 +772,7 @@ apply_ixfr(namedb_type* db, FILE *in, co
        uint16_t rrlen;
        const dname_type *dname_zone, *dname;
        zone_type* zone_db;
+       domain_type* domain, *ce = NULL, *next = NULL;
        char file_zone_name[3072];
        uint32_t file_serial, file_seq_nr;
        uint16_t file_id;
@@ -893,6 +923,7 @@ apply_ixfr(namedb_type* db, FILE *in, co
        }
        else  counter = 0;

+       domain = zone_db->apex;
        for(; counter<  ancount; ++counter,++(*rr_count))
        {
                uint16_t type, klass;
@@ -985,11 +1016,14 @@ apply_ixfr(namedb_type* db, FILE *in, co
                                &&  seq_nr == seq_total-1) {
                                continue; /* do not delete final SOA RR for 
IXFR */
                        }
-                       if(!delete_RR(db, dname, type, klass, packet,
+                       if(!delete_RR(db, dname, type, klass, domain, packet,
                                rrlen, zone_db, region, *is_axfr)) {
                                region_destroy(region);
                                return 0;
                        }
+                       if (!*is_axfr&&  domain->nextdiff) {
+                               domain = domain->nextdiff;
+                       }
                }
                else
                {
@@ -1001,6 +1035,17 @@ apply_ixfr(namedb_type* db, FILE *in, co
                        }
                }
        }
+       /* fix empty terminals */
+       domain = zone_db->apex;
+       while(domain&&  dname_is_subdomain(
+               domain_dname(domain), domain_dname(zone_db->apex)))
+       {
+               ce = rrset_delete_empty_terminals(domain, ce);
+               next = domain->nextdiff;
+               domain->nextdiff = NULL;
+               domain = next;
+       }
+
        region_destroy(region);
        return 1;
  }
Index: namedb.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/namedb.c,v
retrieving revision 1.1.1.3
diff -u -p -r1.1.1.3 namedb.c
--- namedb.c    29 Jan 2012 11:15:37 -0000      1.1.1.3
+++ namedb.c    28 May 2012 20:10:31 -0000
@@ -37,6 +37,7 @@ allocate_domain_info(domain_table_type *
        result->node.key = dname_partial_copy(
                table->region, dname, domain_dname(parent)->label_count + 1);
        result->parent = parent;
+       result->nextdiff = NULL;
        result->wildcard_child_closest_match = result;
        result->rrsets = NULL;
        result->number = 0;
@@ -71,6 +72,7 @@ domain_table_create(region_type *region)
        root = (domain_type *) region_alloc(region, sizeof(domain_type));
        root->node.key = origin;
        root->parent = NULL;
+       root->nextdiff = NULL;
        root->wildcard_child_closest_match = root;
        root->rrsets = NULL;
        root->number = 1; /* 0 is used for after header */
Index: namedb.h
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/namedb.h,v
retrieving revision 1.1.1.4
diff -u -p -r1.1.1.4 namedb.h
--- namedb.h    29 Jan 2012 11:15:40 -0000      1.1.1.4
+++ namedb.h    28 May 2012 20:10:31 -0000
@@ -43,6 +43,7 @@ struct domain
  {
        rbnode_t     node;
        domain_type *parent;
+       domain_type *nextdiff;
        domain_type *wildcard_child_closest_match;
        rrset_type  *rrsets;
  #ifdef NSEC3

Reply via email to