Forwarders and RTT

LaMont Jones lamont at hp.com
Fri Apr 14 01:15:46 UTC 2000


Problem: when using multiple forwarders, the first one gets hammered,
and anything beyond the third forwarder get ignored... (Uses MAXNS
instead of NSMAX...)  A more logical thing would be to track RTT to
the forwarders and sort them into the NS list, thereby achieving the
same load balancing that NS RR's get today.  Much of the needed code
is already present, but no query-to-query state is maintained, and
forwarders always get an RTT of 0 for the sort...

This became a challenge since they want to distribute a common set of
forwarders for a large number of machines, and let them work out the
load balancing...

The attached patch (relative to 8.2.3-T2B) implements the rest of forwarder
sorting.  The method is simply to have nsfwdadd sort the list of forwarders
before returning.  (nslookup also does a sort, but since that's called
multiple places (and not called from the ns_forw path for forward-only
servers, I really didn't want to deal with figuring out if it could move or
not...)

The logic is to maintain a global list of forwarders, so that RTT info
for one zone affects all uses of that forwarder.  db_dump was modified
to dump the rtt for all of the forwarders.

I'll be the first to admit that it's probably a shade less clean than it
could and should be, but it works.   Also bundled in here is:
1. move loop detection up in add_forwarder(), which simplifies the code.
2. change MAXNS (3) to NSMAX(10) in nsfwdadd(), since that's how many
   nameservers we can handle.  (I think this fixes a bug that's been there
   for a while that only the first 3 forwarders would be used.  It probably
   makes sense to have add_forwarder enforce that limit, to avoid confusion.)

Side effects (which kind of make sense...):
1. If not forward-only, then nameservers with lower RTT than our best
   forwarder will get asked the question before the forwarders.  I think
   that this is "correct" behavior, especially from a performance perspective.
2. RTT for forwarders is tracked just like regular NS targets.

Next steps:
See if the qsort() in nslookup can be pulled out, which would let us pull
the qsort out of nsfwdadd() as well, and only do one qsort.  Then again,
there are only 10 elements in the list we're sorting, so it can't be that
big a deal...

thoughts?
lamont


-- Attached file included as plaintext by Listar --

--- db_dump.c.orig	Fri Mar 31 10:52:37 2000
+++ db_dump.c	Fri Mar 31 14:19:05 2000
@@ -148,6 +148,8 @@
 	fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec));
 	if (zones != NULL && nzones != 0)
 		zt_dump(fp);
+	if (fwddata != NULL && fwddata_count != 0)
+		fwd_dump(fp);
 	fputs(
 "; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n",
 	      fp);
@@ -204,6 +206,18 @@
 				inet_ntoa(zp->z_axfr_src));
 	}
 	fprintf(fp, ";; --zone table--\n");
+	return (0);
+}
+int
+fwd_dump(FILE *fp) {
+	int i;
+	fprintf(fp, ";; ++forwarders table++\n");
+	for (i=0;i<fwddata_count;i++) {
+		fprintf(fp,"; %s rtt=%d\n",
+			inet_ntoa(fwddata[i]->fwdaddr.sin_addr),
+			fwddata[i]->nsdata->d_nstime);
+	}
+	fprintf(fp, ";; --forwarders table--\n");
 	return (0);
 }
 
--- ns_config.c.orig	Fri Mar 31 10:52:38 2000
+++ ns_config.c	Fri Mar 31 14:21:33 2000
@@ -2246,7 +2246,79 @@
 	return (0);
 }
 
+/*
+ * find_forwarder finds the fwddata structure for an address,
+ * allocating one if we can't find one already existing.
+ */
+
+static struct fwddata *
+find_forwarder(struct in_addr address)
+{
+	struct fwddata *fdp;
+	struct databuf *ns, *nsdata;
+	register int i;
+
+	for (i=0;i<fwddata_count; i++) {
+		fdp=fwddata[i];
+		if (memcmp(&fdp->fwdaddr.sin_addr,&address,sizeof(address))==0) {
+			fdp->ref_count++;
+			return fdp;
+		}
+	}
+
+	fdp = (struct fwddata *)memget(sizeof(struct fwddata));
+	if (!fdp)
+		panic("memget failed in find_forwarder", NULL);
+	fdp->fwdaddr.sin_family = AF_INET;
+	fdp->fwdaddr.sin_addr = address;
+	fdp->fwdaddr.sin_port = ns_port;
+	ns = fdp->ns = (struct databuf *)memget(sizeof(*ns));
+	if (!ns)
+		panic("memget failed in find_forwarder", NULL);
+	memset(ns,0,sizeof(*ns));
+	nsdata = fdp->nsdata = (struct databuf *)memget(sizeof(*nsdata));
+	if (!nsdata)
+		panic("memget failed in find_forwarder", NULL);
+	memset(nsdata,0,sizeof(*nsdata));
+	ns->d_type = T_NS; 
+	ns->d_class = C_IN;
+	ns->d_rcnt=1;
+	nsdata->d_type = T_A;
+	nsdata->d_class = C_IN;
+	nsdata->d_nstime = 1 + (int)(25.0*rand()/(RAND_MAX + 1.0));
+	nsdata->d_rcnt=1;
+	fdp->ref_count=1;
+	
+	i=0;
+	if (fwddata == NULL) {
+		fwddata = memget(sizeof *fwddata);
+		if (fwddata == NULL)
+			i = 1;
+	} else {
+		register size_t size;
+		register struct fwddata **an_tmp;
+		size = fwddata_count * sizeof *fwddata;
+		an_tmp = memget(size + sizeof *fwddata);
+		if (an_tmp == NULL) {
+			i = 1;
+		} else {
+			memcpy(an_tmp, fwddata, size);
+			memput(fwddata, size);
+			fwddata = an_tmp;
+		}
+	}
 
+	if (i == 0) {
+		fwddata[fwddata_count] = fdp;
+		fwddata_count++;
+	} else {
+		ns_warning(ns_log_config,
+		     "forwarder add failed (memget) [%s]",
+			inet_ntoa(address));
+	}
+
+	return fdp;
+}
 /*
  * Forwarder glue
  *
@@ -2257,25 +2329,25 @@
 static void
 add_forwarder(struct fwdinfo **fipp, struct in_addr address) {
 	struct fwdinfo *fip = *fipp, *ftp = NULL;
+	struct fwddata *fdp;
+
+#ifdef FWD_LOOP
+	if (aIsUs(address)) {
+		ns_error(ns_log_config, "forwarder '%s' ignored, my address",
+			 inet_ntoa(address));
+		return;
+	}
+#endif /* FWD_LOOP */
 
 	/* On multiple forwarder lines, move to end of the list. */
 	while (fip != NULL && fip->next != NULL)
 		fip = fip->next;
 
+	fdp = find_forwarder(address);
 	ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo));
 	if (!ftp)
 		panic("memget failed in add_forwarder", NULL);
-	ftp->fwdaddr.sin_family = AF_INET;
-	ftp->fwdaddr.sin_addr = address;
-	ftp->fwdaddr.sin_port = ns_port;
-#ifdef FWD_LOOP
-	if (aIsUs(ftp->fwdaddr.sin_addr)) {
-		ns_error(ns_log_config, "forwarder '%s' ignored, my address",
-			 inet_ntoa(address));
-		memput(ftp, sizeof *ftp);
-		return;
-	}
-#endif /* FWD_LOOP */
+	ftp->fwddata = fdp;
 	ftp->next = NULL;
 	if (fip == NULL)
 		*fipp = ftp;		/* First time only */
@@ -2387,6 +2459,12 @@
 
 	for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
 		fnext = ftp->next;
+		if (!--ftp->fwddata->ref_count) {
+			memput(ftp->fwddata->ns, sizeof *ftp->fwddata->ns);
+			memput(ftp->fwddata->nsdata,
+					sizeof *ftp->fwddata->nsdata);
+			memput(ftp->fwddata,sizeof *ftp->fwddata);
+		}
 		memput(ftp, sizeof *ftp);
 	}
 	fwdtab = NULL;
--- ns_defs.h.orig	Fri Mar 31 10:52:38 2000
+++ ns_defs.h	Fri Mar 31 12:44:46 2000
@@ -620,10 +620,17 @@
 #define	ALLOW_HOSTS	0x0002
 #define	ALLOW_ALL	(ALLOW_NETS | ALLOW_HOSTS)
 
+struct fwddata {
+	struct sockaddr_in
+			fwdaddr;	/* address of NS */
+	struct databuf	*ns;		/* databuf for NS record */
+	struct databuf	*nsdata;	/* databuf for server address */
+	int		ref_count;	/* how many users of this */
+};
+
 struct fwdinfo {
 	struct fwdinfo	*next;
-	struct sockaddr_in
-			fwdaddr;
+	struct fwddata  *fwddata;
 };
 
 enum nameserStats {	nssRcvdR,	/* sent us an answer */
--- ns_forw.c.orig	Thu Mar 30 13:28:24 2000
+++ ns_forw.c	Fri Mar 31 14:08:09 2000
@@ -1240,15 +1240,15 @@
 	struct qserv *qs;
 
 	n = qp->q_naddr;
-	while (fwd != NULL && n < MAXNS) {
+	while (fwd != NULL && n < NSMAX) {
 		qs = qp->q_addr;
 		for (i = 0; i < (u_int)n; i++, qs++)
 			if (ina_equal(qs->ns_addr.sin_addr,
-				      fwd->fwdaddr.sin_addr))
+				      fwd->fwddata->fwdaddr.sin_addr))
 				goto nextfwd;
-		qs->ns_addr = fwd->fwdaddr;
-		qs->ns = NULL;
-		qs->nsdata = NULL;
+		qs->ns_addr = fwd->fwddata->fwdaddr;
+		qs->ns = fwd->fwddata->ns;
+		qs->nsdata = fwd->fwddata->nsdata;
 		qs->forwarder = 1;
 		qs->nretry = 0;
 		n++;
@@ -1256,4 +1256,14 @@
 		fwd = fwd->next;
 	}
 	qp->q_naddr = n;
+
+	/* Update the refcounts before the sort. */
+	for (i = 0; i < (u_int)n; i++) {
+		DRCNTINC(qp->q_addr[i].nsdata);
+		DRCNTINC(qp->q_addr[i].ns);
+	}
+	if (n > 1) {
+		qsort((char *)qp->q_addr, n, sizeof(struct qserv),
+		      (int (*)(const void *, const void *))qcomp);
+	}
 }
--- ns_glob.h.orig	Thu Mar 30 13:22:16 2000
+++ ns_glob.h	Fri Mar 31 13:27:58 2000
@@ -156,6 +156,11 @@
 DECL	u_char			**dnptrs_end
 				INIT(dnptrs + sizeof dnptrs / sizeof(u_char*));
 
+	/* data about all forwarders */
+DECL    struct fwddata          **fwddata;
+	/* how many forwarders are there in fwddata? */
+DECL	int			fwddata_count;
+
 	/* number of names in addinfo */
 DECL	int			addcount;
 
--- ns_resp.c.orig	Fri Mar 31 10:52:38 2000
+++ ns_resp.c	Fri Mar 31 13:13:29 2000
@@ -464,14 +464,14 @@
 	 * XXX - should put this in STATS somewhere.
 	 */
 	for (fwd = NS_ZFWDTAB(qp->q_fzone); fwd; fwd = fwd->next)
-		if (ina_equal(fwd->fwdaddr.sin_addr, from.sin_addr))
+		if (ina_equal(fwd->fwddata->fwdaddr.sin_addr, from.sin_addr))
 			break;
 	/*
 	/*
-	 * If we weren't using a forwarder, find the qinfo pointer and update
+	 * find the qinfo pointer and update
 	 * the rtt and fact that we have called on this server before.
 	 */
-	if (fwd == NULL) {
+	{
 		struct timeval *stp;
 
 		for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++)




More information about the bind-workers mailing list