[prev in list] [next in list] [prev in thread] [next in thread]
List: varnish-dev
Subject: Re: Test suite for dynamic backends
From: Dridi Boukelmoune <dridi () varni ! sh>
Date: 2015-07-14 7:34:15
Message-ID: CABoVN9AaUWoNcL4E1Jw=0NvS-P0-=Ds61d52ZXomYuZ+Xrv5eA () mail ! gmail ! com
[Download RAW message or body]
On Sun, Jul 12, 2015 at 12:09 PM, Poul-Henning Kamp <phk@phk.freebsd.dk> wrote:
>>If you look at the DNS director patch, you'll see extra care in not
>>removing backends needlessly.
>
> I havn't looked at that patch yet.
Forgot to update my DNS director draft. I also realized thanks to
telnet that my ISP doesn't seem to support IPv6 (Network is
unreachable), but loopback tests went well.
Cheers,
Dridi
["0001-Resurrect-VSA_Len.patch" (text/x-patch)]
From 32f7ad806267ea3ecb65c8c2cc95bc9bbd102cd6 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
Date: Tue, 7 Jul 2015 22:31:50 +0200
Subject: [PATCH 1/2] Resurrect VSA_Len
Partial revert of 0848a1fe471c40a49e77df941c8e2cc133170ff7.
---
include/vsa.h | 1 +
lib/libvarnish/vsa.c | 15 +++++++++++++++
2 files changed, 16 insertions(+)
diff --git a/include/vsa.h b/include/vsa.h
index 185be03..996afde 100644
--- a/include/vsa.h
+++ b/include/vsa.h
@@ -34,6 +34,7 @@ struct suckaddr;
extern const int vsa_suckaddr_len;
int VSA_Sane(const struct suckaddr *);
+socklen_t VSA_Len(const struct suckaddr *);
unsigned VSA_Port(const struct suckaddr *);
int VSA_Compare(const struct suckaddr *, const struct suckaddr *);
struct suckaddr *VSA_Clone(const struct suckaddr *sua);
diff --git a/lib/libvarnish/vsa.c b/lib/libvarnish/vsa.c
index 43d9a86..fc25cdd 100644
--- a/lib/libvarnish/vsa.c
+++ b/lib/libvarnish/vsa.c
@@ -306,6 +306,21 @@ VSA_Sane(const struct suckaddr *sua)
}
}
+socklen_t
+VSA_Len(const struct suckaddr *sua)
+{
+ CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
+
+ switch(sua->sa.sa_family) {
+ case PF_INET:
+ return (sizeof(sua->sa4));
+ case PF_INET6:
+ return (sizeof(sua->sa6));
+ default:
+ return (0);
+ }
+}
+
int
VSA_Compare(const struct suckaddr *sua1, const struct suckaddr *sua2)
{
--
2.1.0
["0002-Resurrect-the-DNS-director.patch" (text/x-patch)]
From c489a4903e8f1ec5b7f020a7ff94d1e971812c76 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
Date: Wed, 8 Jul 2015 19:49:14 +0200
Subject: [PATCH 2/2] Resurrect the DNS director
---
lib/libvmod_directors/Makefile.am | 3 +-
lib/libvmod_directors/dns.c | 393 ++++++++++++++++++++++++++++++++++++++
lib/libvmod_directors/vmod.vcc | 43 +++++
3 files changed, 438 insertions(+), 1 deletion(-)
create mode 100644 lib/libvmod_directors/dns.c
diff --git a/lib/libvmod_directors/Makefile.am b/lib/libvmod_directors/Makefile.am
index 64b72a8..bc0261f 100644
--- a/lib/libvmod_directors/Makefile.am
+++ b/lib/libvmod_directors/Makefile.am
@@ -17,6 +17,7 @@ libvmod_directors_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-vers
libvmod_directors_la_SOURCES = \
vdir.c \
vdir.h \
+ dns.c \
fall_back.c \
hash.c \
random.c \
@@ -27,7 +28,7 @@ nodist_libvmod_directors_la_SOURCES = \
vcc_if.h
# BUILT_SOURCES is only a hack and dependency tracking does not help for the first build
-vdir.lo fall_back.lo hash.lo random.lo round_robin.lo: vcc_if.h
+vdir.lo dns.lo fall_back.lo hash.lo random.lo round_robin.lo: vcc_if.h
vcc_if.c vcc_if.h vmod_directors.rst vmod_directors.man.rst: $(vmodtool) $(vmod_srcdir)/vmod.vcc
@PYTHON@ $(vmodtool) $(vmodtoolargs) $(vmod_srcdir)/vmod.vcc
diff --git a/lib/libvmod_directors/dns.c b/lib/libvmod_directors/dns.c
new file mode 100644
index 0000000..df0cf98
--- /dev/null
+++ b/lib/libvmod_directors/dns.c
@@ -0,0 +1,393 @@
+/*-
+ * Copyright (c) 2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Dridi Boukelmoune <dridi@varnish-software.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <arpa/inet.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vrt.h"
+#include "vcl.h"
+
+#include "cache/cache.h"
+#include "cache/cache_director.h"
+#include "cache/cache_backend.h"
+
+#include "vsa.h"
+#include "vtim.h"
+#include "vcc_if.h"
+
+struct vmod_directors_dns;
+
+struct dns_director {
+ struct vmod_directors_dns *dns;
+ struct director *simple_dir;
+ VTAILQ_ENTRY(dns_director) list;
+ struct suckaddr *ip_suckaddr;
+ char *ip_addr;
+ char *vcl_name;
+ unsigned mark;
+};
+
+struct vmod_directors_dns {
+ unsigned magic;
+#define VMOD_DIRECTORS_DNS_MAGIC 0x8a3e7fd1
+ pthread_t thread;
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+ char *vcl_name;
+ char *addr;
+ char *port;
+ double ttl;
+ VTAILQ_HEAD(,dns_director) director_list;
+ struct dns_director *next;
+ struct director dir;
+ struct vcl *vcl;
+ int active;
+ unsigned mark;
+};
+
+static void
+vmod_dns_rotate(struct vmod_directors_dns *dns)
+{
+ if (dns->next != NULL)
+ dns->next = dns->next->list.vtqe_next;
+
+ if (dns->next == NULL)
+ dns->next = dns->director_list.vtqh_first;
+}
+
+static int
+vmod_dns_notfound(struct vmod_directors_dns *dns, struct suckaddr *sa)
+{
+ struct dns_director *d;
+
+ AN(sa);
+
+ VTAILQ_FOREACH(d, &dns->director_list, list) {
+ if (d->mark == dns->mark)
+ continue;
+
+ if (VSA_Compare(d->ip_suckaddr, sa))
+ continue;
+
+ d->mark = dns->mark;
+ return (0);
+ }
+
+ return (1);
+}
+
+static unsigned __match_proto__(vdi_healthy_f)
+vmod_dns_healthy(const struct director *d, const struct busyobj *bo,
+ double *changed)
+{
+ struct vmod_directors_dns *dns;
+ unsigned healthy;
+
+ CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+ CAST_OBJ_NOTNULL(dns, d->priv, VMOD_DIRECTORS_DNS_MAGIC);
+
+ AZ(pthread_mutex_lock(&dns->mtx));
+ (void)changed;
+ healthy = (dns->next != NULL);
+ AZ(pthread_mutex_unlock(&dns->mtx));
+
+ // XXX we can do better than that
+ return (healthy);
+}
+
+static const struct director * __match_proto__(vdi_resolve_f)
+vmod_dns_resolve(const struct director *d, struct worker *wrk,
+ struct busyobj *bo)
+{
+ struct vmod_directors_dns *dns;
+ struct director *dir = NULL;
+
+ CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+ CAST_OBJ_NOTNULL(dns, d->priv, VMOD_DIRECTORS_DNS_MAGIC);
+
+ pthread_mutex_lock(&dns->mtx);
+ if (dns->next != NULL) {
+ dir = dns->next->simple_dir;
+ vmod_dns_rotate(dns);
+ }
+ AZ(pthread_mutex_unlock(&dns->mtx));
+
+ return (dir);
+}
+
+static void
+vmod_dns_del(VRT_CTX, struct dns_director *dir)
+{
+ struct dns_director *next;
+ struct vmod_directors_dns *dns;
+
+ AN(dir);
+ AN(dir->dns);
+
+ dns = dir->dns;
+ next = dns->next;
+ AN(next);
+
+ if (dir == next) {
+ vmod_dns_rotate(dns);
+ if (next == dns->next)
+ dns->next = NULL;
+ }
+
+ VTAILQ_REMOVE(&dir->dns->director_list, dir, list);
+ if (ctx) {
+ AN(ctx->vcl);
+ VRT_delete_backend(ctx, &dir->simple_dir);
+ }
+ free(dir->vcl_name);
+ free(dir->ip_addr);
+ free(dir->ip_suckaddr);
+ free(dir);
+}
+
+static void
+vmod_dns_add(VRT_CTX, struct vmod_directors_dns *dns,
+ struct suckaddr *sa)
+{
+ struct vrt_backend vrt;
+ struct dns_director *dir;
+ const unsigned char *ptr = NULL;
+ char buf[128];
+ int af;
+ socklen_t len;
+
+ dir = malloc(sizeof *dir);
+ AN(dir);
+ dir->dns = dns;
+ dir->mark = dns->mark;
+ dir->ip_suckaddr = sa;
+
+ af = VRT_VSA_GetPtr(sa, &ptr);
+ AN(ptr);
+ len = VSA_Len(sa);
+ AN(inet_ntop(af, ptr, buf, len));
+ dir->ip_addr = strdup(buf);
+ AN(dir->ip_addr);
+
+ snprintf(buf, sizeof buf, "%s(%s)", dns->vcl_name, dir->ip_addr);
+ dir->vcl_name = strdup(buf);
+ AN(dir->vcl_name);
+
+ INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
+ vrt.port = dns->port;
+ vrt.hosthdr = dns->addr;
+ vrt.vcl_name = dir->vcl_name;
+
+ switch (af) {
+ case AF_INET:
+ vrt.ipv4_suckaddr = sa;
+ vrt.ipv4_addr = dir->ip_addr;
+ break;
+ case AF_INET6:
+ vrt.ipv6_suckaddr = sa;
+ vrt.ipv6_addr = dir->ip_addr;
+ break;
+ default:
+ WRONG("unexpected family");
+ }
+
+
+ dir->simple_dir = VRT_new_backend(ctx, &vrt);
+ AN(dir->simple_dir);
+
+ VTAILQ_INSERT_TAIL(&dns->director_list, dir, list);
+}
+
+static void
+vmod_dns_update(struct vmod_directors_dns *dns, struct addrinfo *addr)
+{
+ struct suckaddr *sa;
+ struct dns_director *d, *d2;
+ struct vrt_ctx ctx;
+
+ AN(addr);
+
+ INIT_OBJ(&ctx, VRT_CTX_MAGIC);
+ ctx.vcl = dns->vcl;
+
+ dns->mark++;
+ while (addr) {
+ switch (addr->ai_family) {
+ case AF_INET:
+ case AF_INET6:
+ sa = malloc(vsa_suckaddr_len);
+ AN(sa);
+ AN(VSA_Build(sa, addr->ai_addr, addr->ai_addrlen));
+ if (vmod_dns_notfound(dns, sa))
+ vmod_dns_add(&ctx, dns, sa);
+ }
+ addr = addr->ai_next;
+ }
+
+ VTAILQ_FOREACH_SAFE(d, &dns->director_list, list, d2)
+ if (d->mark != dns->mark)
+ vmod_dns_del(&ctx, d);
+
+ vmod_dns_rotate(dns);
+}
+
+static void*
+vmod_dns_lookup_thread(void *obj)
+{
+ struct vmod_directors_dns *dns;
+ struct timespec ts;
+ struct addrinfo hints, *res;
+ double deadline;
+ int ret;
+
+ CAST_OBJ_NOTNULL(dns, obj, VMOD_DIRECTORS_DNS_MAGIC);
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = AF_UNSPEC;
+
+ while (dns->active) {
+ ret = getaddrinfo(dns->addr, dns->port, &hints, &res);
+
+ AZ(pthread_mutex_lock(&dns->mtx));
+
+ if (ret == 0) {
+ vmod_dns_update(dns, res);
+ freeaddrinfo(res);
+ }
+ else
+ VSL(SLT_Error, 0, "DNS lookup failed: %d (%s)",
+ ret, gai_strerror(ret));
+
+ deadline = VTIM_real() + dns->ttl;
+ ts = VTIM_timespec(deadline);
+ ret = pthread_cond_timedwait(&dns->cond, &dns->mtx, &ts);
+ assert(ret == 0 || ret == ETIMEDOUT);
+
+ AZ(pthread_mutex_unlock(&dns->mtx));
+ }
+
+ return (NULL);
+}
+
+VCL_VOID __match_proto__()
+vmod_dns__init(VRT_CTX, struct vmod_directors_dns **dnsp, const char *vcl_name,
+ VCL_STRING addr, VCL_STRING port)
+{
+ struct vmod_directors_dns *dns;
+
+ ASSERT_CLI();
+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+ AN(dnsp);
+ AZ(*dnsp);
+ AN(vcl_name);
+ AN(addr);
+ AN(port);
+
+ ALLOC_OBJ(dns, VMOD_DIRECTORS_DNS_MAGIC);
+ AN(dns);
+ VTAILQ_INIT(&dns->director_list);
+ REPLACE(dns->vcl_name, vcl_name);
+ REPLACE(dns->addr, addr);
+ REPLACE(dns->port, port);
+ dns->vcl = ctx->vcl;
+ dns->ttl = 3600;
+ dns->active = 1;
+
+ INIT_OBJ(&dns->dir, DIRECTOR_MAGIC);
+ dns->dir.name = "dns";
+ dns->dir.vcl_name = dns->vcl_name;
+ dns->dir.healthy = vmod_dns_healthy;
+ dns->dir.resolve = vmod_dns_resolve;
+ dns->dir.priv = dns;
+
+ AZ(pthread_mutex_init(&dns->mtx, NULL));
+ AZ(pthread_cond_init(&dns->cond, NULL));
+ AZ(pthread_create(&dns->thread, NULL, &vmod_dns_lookup_thread, dns));
+
+ *dnsp = dns;
+}
+
+VCL_VOID __match_proto__()
+vmod_dns__fini(struct vmod_directors_dns **dnsp)
+{
+ struct vmod_directors_dns *dns;
+
+ AN(dnsp);
+ dns = *dnsp;
+ *dnsp = NULL;
+
+ CHECK_OBJ_NOTNULL(dns, VMOD_DIRECTORS_DNS_MAGIC);
+
+ AZ(pthread_mutex_lock(&dns->mtx));
+ dns->active = 0;
+ AZ(pthread_mutex_unlock(&dns->mtx));
+
+ AZ(pthread_cond_signal(&dns->cond));
+ AZ(pthread_join(dns->thread, NULL));
+
+ /* backends will be deleted by the VCL, pass a NULL struct ctx */
+ while (dns->director_list.vtqh_first != NULL)
+ vmod_dns_del(NULL, dns->director_list.vtqh_first);
+
+ AZ(pthread_cond_destroy(&dns->cond));
+ AZ(pthread_mutex_destroy(&dns->mtx));
+ free(dns->vcl_name);
+ free(dns->addr);
+ free(dns->port);
+ FREE_OBJ(dns);
+}
+
+VCL_VOID __match_proto__()
+vmod_dns_set_ttl(VRT_CTX, struct vmod_directors_dns *dns, VCL_DURATION ttl)
+{
+
+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+ CHECK_OBJ_NOTNULL(dns, VMOD_DIRECTORS_DNS_MAGIC);
+ assert(ttl > 0);
+ dns->ttl = ttl;
+}
+
+VCL_BACKEND __match_proto__()
+vmod_dns_backend(VRT_CTX, struct vmod_directors_dns *dns)
+{
+
+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+ CHECK_OBJ_NOTNULL(dns, VMOD_DIRECTORS_DNS_MAGIC);
+ return (&dns->dir);
+}
diff --git a/lib/libvmod_directors/vmod.vcc b/lib/libvmod_directors/vmod.vcc
index cfcf2e3..9291d4d 100644
--- a/lib/libvmod_directors/vmod.vcc
+++ b/lib/libvmod_directors/vmod.vcc
@@ -180,3 +180,46 @@ Description
Example
# pick a backend based on the cookie header from the client
set req.backend_hint = vdir.backend(req.http.cookie);
+
+$Object dns(STRING, STRING)
+
+Description
+ Create a DNS director.
+
+ The director creates backends with DNS lookups and chooses them in a
+ round robin fashion. An ACL (Access Control List) can be used as a
+ white-list to restrict the use of resolved addresses.
+
+Example
+ ::
+
+ acl www_backends {
+ "192.168.15.0"/24;
+ !"192.168.15.1";
+ }
+
+ sub vcl_init {
+ new www_dir = directors.dns("www.example.com", "80");
+ www_dir.restrict_to(www_backends);
+ www_dir.set_ttl(5m);
+ }
+
+ sub vcl_recv {
+ set req.backend_hint = www_dir.backend();
+ }
+
+# TODO $Method VOID .restrict_to(ACL)
+#
+#Description
+# Restrict usage of resolved IP addresses to a named ACL.
+
+$Method VOID .set_ttl(DURATION)
+
+Description
+ Set the DNS lookup TTL (defaults to one hour).
+
+$Method BACKEND .backend()
+
+Description
+ Pick a backend from the director.
+
--
2.1.0
_______________________________________________
varnish-dev mailing list
varnish-dev@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic