]> err.no Git - varnish/commitdiff
Split the backend code into two files, the probe code will make it
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 8 Jul 2008 10:09:03 +0000 (10:09 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 8 Jul 2008 10:09:03 +0000 (10:09 +0000)
more complicated than a single file can carry.

cache_backend_cfg.c now contains the configuration and selection of
backends and directors.

cache_backend.c contains the connection and request management against
backends.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2905 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/Makefile.am
varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_backend.c
varnish-cache/bin/varnishd/cache_backend.h [new file with mode: 0644]
varnish-cache/bin/varnishd/cache_backend_cfg.c [new file with mode: 0644]

index 4de55881cb498d105daba3d88775cb3b6af00252..1e5c5053327541349ceca2c72b00c32815ba8ae3 100644 (file)
@@ -12,6 +12,7 @@ varnishd_SOURCES = \
        cache_acceptor_poll.c \
        cache_acceptor_kqueue.c \
        cache_backend.c \
+       cache_backend_cfg.c \
        cache_ban.c \
        cache_center.c \
        cache_cli.c \
index ebffdc03545e137326eb5bb37332e51156996401..7df47fe3110f88d191a2584ae844c4f292fb4cb4 100644 (file)
@@ -413,17 +413,19 @@ extern int vca_pipes[2];
 
 /* cache_backend.c */
 
-void VBE_Init(void);
-struct vbe_conn *VBE_GetFd(struct sess *sp);
+struct vbe_conn *VBE_GetFd(const struct sess *sp);
 void VBE_ClosedFd(struct worker *w, struct vbe_conn *vc);
 void VBE_RecycleFd(struct worker *w, struct vbe_conn *vc);
 struct bereq * VBE_new_bereq(void);
 void VBE_free_bereq(struct bereq *bereq);
-void VBE_DropRef(struct backend *);
-struct backend *VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb);
 void VBE_UpdateHealth(const struct sess *sp, const struct vbe_conn *, int);
-void VBE_AddHostHeader(struct sess *sp);
+void VBE_AddHostHeader(const struct sess *sp);
+
+/* cache_backend_cfg.c */
+void VBE_Init(void);
+void VBE_DropRef(struct backend *);
 void VBE_SelectBackend(struct sess *sp);
+struct backend *VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb);
 
 /* cache_ban.c */
 int BAN_Add(struct cli *cli, const char *regexp, int hash);
index 0a17b60451941406ef0306a95f8124acf792f2af..5cc1fe169d2dd2ba3d9ac36b2be0c20afb1080a7 100644 (file)
  *
  * $Id$
  *
- * This is the central switch-board for backend connections and it is
- * slightly complicated by a number of optimizations.
- *
- * The data structures:
- *
- *    A vrt_backend is a definition of a backend in a VCL program.
- *
- *    A backend is a TCP destination, possibly multi-homed and it has a
- *    number of associated properties and statistics.
- *
- *    A vbe_conn is an open TCP connection to a backend.
- *
- *    A bereq is a memory carrier for handling a HTTP transaction with
- *    a backend over a vbe_conn.
- *
- *    A director is a piece of code that selects which backend to use,
- *    by whatever method or metric it chooses.
- *
- * The relationships:
- *
- *    Backends and directors get instantiated when VCL's are loaded,
- *    and this always happen in the CLI thread.
- *
- *    When a VCL tries to instantiate a backend, any existing backend
- *    with the same identity (== definition in VCL) will be used instead
- *    so that vbe_conn's can be reused across VCL changes.
- *
- *    Directors disapper with the VCL that created them.
- *
- *    Backends disappear when their reference count drop to zero.
- *
- *    Backends have their host/port name looked up to addrinfo structures
- *    when they are instantiated, and we just cache that result and cycle
- *    through the entries (for multihomed backends) on failure only.
- *    XXX: add cli command to redo lookup.
- *
- *    bereq is sort of a step-child here, we just manage the pool of them.
+ * Handle backend connections and backend request structures.
  *
  */
 
 #include "shmlog.h"
 #include "cache.h"
 #include "vrt.h"
-#include "cli_priv.h"
-
-/* Backend indstance */
-struct backend {
-       unsigned                magic;
-#define BACKEND_MAGIC          0x64c4c7c6
-
-       struct vrt_backend      vrt[1];
-       uint32_t                hash;
-
-       VTAILQ_ENTRY(backend)   list;
-       int                     refcount;
-       pthread_mutex_t         mtx;
-
-       struct addrinfo         *ai;
-       struct addrinfo         *last_ai;
-
-       VTAILQ_HEAD(, vbe_conn) connlist;
-
-       int                     health;
-};
-
-static MTX VBE_mtx;
+#include "cache_backend.h"
 
 /*
  * List of cached vbe_conns, used if enabled in params/heritage
@@ -116,17 +58,11 @@ static VTAILQ_HEAD(,vbe_conn) vbe_conns = VTAILQ_HEAD_INITIALIZER(vbe_conns);
  */
 static VTAILQ_HEAD(,bereq) bereq_head = VTAILQ_HEAD_INITIALIZER(bereq_head);
 
-/*
- * The list of backends is not locked, it is only ever accessed from
- * the CLI thread, so there is no need.
- */
-static VTAILQ_HEAD(, backend) backends = VTAILQ_HEAD_INITIALIZER(backends);
-
 /*--------------------------------------------------------------------
  * Create default Host: header for backend request
  */
 void
-VBE_AddHostHeader(struct sess *sp)
+VBE_AddHostHeader(const struct sess *sp)
 {
 
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
@@ -299,7 +235,7 @@ VBE_NewConn(void)
        return (vc);
 }
 
-static void
+void
 VBE_ReleaseConn(struct vbe_conn *vc)
 {
 
@@ -318,52 +254,6 @@ VBE_ReleaseConn(struct vbe_conn *vc)
        }
 }
 
-/*--------------------------------------------------------------------
- * Drop a reference to a backend.
- * The last reference must come from the watcher in the CLI thread,
- * as only that thread is allowed to clean up the backend list.
- */
-
-static void
-VBE_DropRefLocked(struct backend *b)
-{
-       int i;
-       struct vbe_conn *vbe, *vbe2;
-
-       CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
-       assert(b->refcount > 0);
-
-       i = --b->refcount;
-       UNLOCK(&b->mtx);
-       if (i > 0)
-               return;
-
-       ASSERT_CLI();
-       VTAILQ_REMOVE(&backends, b, list);
-       VTAILQ_FOREACH_SAFE(vbe, &b->connlist, list, vbe2) {
-               VTAILQ_REMOVE(&b->connlist, vbe, list);
-               if (vbe->fd >= 0)
-                       AZ(close(vbe->fd));
-               VBE_ReleaseConn(vbe);
-       }
-       free(TRUST_ME(b->vrt->ident));
-       free(TRUST_ME(b->vrt->hostname));
-       free(TRUST_ME(b->vrt->portname));
-       b->magic = 0;
-       free(b);
-       VSL_stats->n_backend--;
-}
-
-void
-VBE_DropRef(struct backend *b)
-{
-
-       CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
-
-       LOCK(&b->mtx);
-       VBE_DropRefLocked(b);
-}
-
 /*--------------------------------------------------------------------
  * Try to get a socket connected to one of the addresses on the list.
  * We start from the cached "last good" address and try all items on
@@ -430,22 +320,8 @@ bes_conn_try(const struct sess *sp, struct backend *bp)
 
 /*--------------------------------------------------------------------*/
 
-void
-VBE_SelectBackend(struct sess *sp)
-{
-       struct backend *bp;
-
-       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
-       CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
-       bp = sp->director->choose(sp);
-       CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
-       sp->backend = bp;
-}
-
-/*--------------------------------------------------------------------*/
-
 struct vbe_conn *
-VBE_GetFd(struct sess *sp)
+VBE_GetFd(const struct sess *sp)
 {
        struct backend *bp;
        struct vbe_conn *vc;
@@ -560,149 +436,3 @@ VBE_UpdateHealth(const struct sess *sp, const struct vbe_conn *vc, int a)
        CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
 #endif
 }
-
-/*--------------------------------------------------------------------
- * DNS lookup of backend host/port
- */
-
-static void
-vbe_dns_lookup(struct cli *cli, struct backend *bp)
-{
-       int error;
-       struct addrinfo *res, hint, *old;
-
-       CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
-
-       memset(&hint, 0, sizeof hint);
-       hint.ai_family = PF_UNSPEC;
-       hint.ai_socktype = SOCK_STREAM;
-       res = NULL;
-       error = getaddrinfo(bp->vrt->hostname, bp->vrt->portname,
-           &hint, &res);
-       if (error) {
-               if (res != NULL)
-                       freeaddrinfo(res);
-               /*
-                * We cannot point to the source code any more, it may
-                * be long gone from memory.   We already checked over in
-                * the VCL compiler, so this is only relevant for refreshes.
-                * XXX: which we do when exactly ?
-                */
-               cli_out(cli, "DNS(/hosts) lookup failed for (%s/%s): %s",
-                   bp->vrt->hostname, bp->vrt->portname, gai_strerror(error));
-               return;
-       }
-       LOCK(&bp->mtx);
-       old = bp->ai;
-       bp->ai = res;
-       bp->last_ai = res;
-       UNLOCK(&bp->mtx);
-       if (old != NULL)
-               freeaddrinfo(old);
-}
-
-/*--------------------------------------------------------------------
- * Add a backend/director instance when loading a VCL.
- * If an existing backend is matched, grab a refcount and return.
- * Else create a new backend structure with reference initialized to one.
- */
-
-struct backend *
-VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb)
-{
-       struct backend *b;
-       uint32_t u;
-
-       AN(vb->hostname);
-       AN(vb->portname);
-       AN(vb->ident);
-       (void)cli;
-       ASSERT_CLI();
-       u = crc32_l(vb->ident, strlen(vb->ident));
-       VTAILQ_FOREACH(b, &backends, list) {
-               CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
-               if (u != b->hash)
-                       continue;
-               if (strcmp(b->vrt->ident, vb->ident))
-                       continue;
-               b->refcount++;
-               return (b);
-       }
-
-       ALLOC_OBJ(b, BACKEND_MAGIC);
-       XXXAN(b);
-       b->magic = BACKEND_MAGIC;
-
-       VTAILQ_INIT(&b->connlist);
-       b->hash = u;
-
-       /*
-        * This backend may live longer than the VCL that instantiated it
-        * so we cannot simply reference the VCL's copy of things.
-        */
-       REPLACE(b->vrt->ident, vb->ident);
-       REPLACE(b->vrt->hostname, vb->hostname);
-       REPLACE(b->vrt->portname, vb->portname);
-       REPLACE(b->vrt->vcl_name, vb->vcl_name);
-
-       b->vrt->connect_timeout = vb->connect_timeout;
-
-       MTX_INIT(&b->mtx);
-       b->refcount = 1;
-
-       vbe_dns_lookup(cli, b);
-
-       VTAILQ_INSERT_TAIL(&backends, b, list);
-       VSL_stats->n_backend++;
-       return (b);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-void
-VRT_fini_dir(struct cli *cli, struct director *b)
-{
-
-       (void)cli;
-       ASSERT_CLI();
-       CHECK_OBJ_NOTNULL(b, DIRECTOR_MAGIC);
-       b->fini(b);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-cli_debug_backend(struct cli *cli, const char * const *av, void *priv)
-{
-       struct backend *b;
-
-       (void)av;
-       (void)priv;
-       ASSERT_CLI();
-       VTAILQ_FOREACH(b, &backends, list) {
-               CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
-               cli_out(cli, "%p %s/%s/%s %d\n",
-                   b,
-                   b->vrt->vcl_name,
-                   b->vrt->hostname,
-                   b->vrt->portname,
-                   b->refcount);
-       }
-}
-
-static struct cli_proto debug_cmds[] = {
-       { "debug.backend", "debug.backend",
-           "\tExamine Backend internals\n", 0, 0, cli_debug_backend },
-       { NULL }
-};
-
-/*--------------------------------------------------------------------*/
-
-void
-VBE_Init(void)
-{
-
-       MTX_INIT(&VBE_mtx);
-       CLI_AddFuncs(DEBUG_CLI, debug_cmds);
-}
diff --git a/varnish-cache/bin/varnishd/cache_backend.h b/varnish-cache/bin/varnishd/cache_backend.h
new file mode 100644 (file)
index 0000000..588bb8a
--- /dev/null
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ * This is the central switch-board for backend connections and it is
+ * slightly complicated by a number of optimizations.
+ *
+ * The data structures:
+ *
+ *    A vrt_backend is a definition of a backend in a VCL program.
+ *
+ *    A backend is a TCP destination, possibly multi-homed and it has a
+ *    number of associated properties and statistics.
+ *
+ *    A vbe_conn is an open TCP connection to a backend.
+ *
+ *    A bereq is a memory carrier for handling a HTTP transaction with
+ *    a backend over a vbe_conn.
+ *
+ *    A director is a piece of code that selects which backend to use,
+ *    by whatever method or metric it chooses.
+ *
+ * The relationships:
+ *
+ *    Backends and directors get instantiated when VCL's are loaded,
+ *    and this always happen in the CLI thread.
+ *
+ *    When a VCL tries to instantiate a backend, any existing backend
+ *    with the same identity (== definition in VCL) will be used instead
+ *    so that vbe_conn's can be reused across VCL changes.
+ *
+ *    Directors disapper with the VCL that created them.
+ *
+ *    Backends disappear when their reference count drop to zero.
+ *
+ *    Backends have their host/port name looked up to addrinfo structures
+ *    when they are instantiated, and we just cache that result and cycle
+ *    through the entries (for multihomed backends) on failure only.
+ *    XXX: add cli command to redo lookup.
+ *
+ *    bereq is sort of a step-child here, we just manage the pool of them.
+ *
+ */
+
+/* Backend indstance */
+struct backend {
+       unsigned                magic;
+#define BACKEND_MAGIC          0x64c4c7c6
+
+       struct vrt_backend      vrt[1];
+       uint32_t                hash;
+
+       VTAILQ_ENTRY(backend)   list;
+       int                     refcount;
+       pthread_mutex_t         mtx;
+
+       struct addrinfo         *ai;
+       struct addrinfo         *last_ai;
+
+       VTAILQ_HEAD(, vbe_conn) connlist;
+
+       int                     health;
+};
+
+/* cache_backend_cfg.c */
+extern MTX VBE_mtx;
+void VBE_DropRefLocked(struct backend *b);
+
+/* cache_backend.c */
+void VBE_ReleaseConn(struct vbe_conn *vc);
diff --git a/varnish-cache/bin/varnishd/cache_backend_cfg.c b/varnish-cache/bin/varnishd/cache_backend_cfg.c
new file mode 100644 (file)
index 0000000..d4399b2
--- /dev/null
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ * Handle configuration of backends from VCL programs.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "shmlog.h"
+#include "cache.h"
+#include "vrt.h"
+#include "cache_backend.h"
+#include "cli_priv.h"
+
+MTX VBE_mtx;
+
+/*
+ * The list of backends is not locked, it is only ever accessed from
+ * the CLI thread, so there is no need.
+ */
+static VTAILQ_HEAD(, backend) backends = VTAILQ_HEAD_INITIALIZER(backends);
+
+/*--------------------------------------------------------------------*/
+
+void
+VBE_SelectBackend(struct sess *sp)
+{
+       struct backend *bp;
+
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+       CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
+       bp = sp->director->choose(sp);
+       CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+       sp->backend = bp;
+}
+
+/*--------------------------------------------------------------------
+ * Drop a reference to a backend.
+ * The last reference must come from the watcher in the CLI thread,
+ * as only that thread is allowed to clean up the backend list.
+ */
+
+void
+VBE_DropRefLocked(struct backend *b)
+{
+       int i;
+       struct vbe_conn *vbe, *vbe2;
+
+       CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+       assert(b->refcount > 0);
+
+       i = --b->refcount;
+       UNLOCK(&b->mtx);
+       if (i > 0)
+               return;
+
+       ASSERT_CLI();
+       VTAILQ_REMOVE(&backends, b, list);
+       VTAILQ_FOREACH_SAFE(vbe, &b->connlist, list, vbe2) {
+               VTAILQ_REMOVE(&b->connlist, vbe, list);
+               if (vbe->fd >= 0)
+                       AZ(close(vbe->fd));
+               VBE_ReleaseConn(vbe);
+       }
+       free(TRUST_ME(b->vrt->ident));
+       free(TRUST_ME(b->vrt->hostname));
+       free(TRUST_ME(b->vrt->portname));
+       b->magic = 0;
+       free(b);
+       VSL_stats->n_backend--;
+}
+
+void
+VBE_DropRef(struct backend *b)
+{
+
+       CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+
+       LOCK(&b->mtx);
+       VBE_DropRefLocked(b);
+}
+
+/*--------------------------------------------------------------------
+ * DNS lookup of backend host/port
+ */
+
+static void
+vbe_dns_lookup(const struct cli *cli, struct backend *bp)
+{
+       int error;
+       struct addrinfo *res, hint, *old;
+
+       CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+
+       memset(&hint, 0, sizeof hint);
+       hint.ai_family = PF_UNSPEC;
+       hint.ai_socktype = SOCK_STREAM;
+       res = NULL;
+       error = getaddrinfo(bp->vrt->hostname, bp->vrt->portname,
+           &hint, &res);
+       if (error) {
+               if (res != NULL)
+                       freeaddrinfo(res);
+               /*
+                * We cannot point to the source code any more, it may
+                * be long gone from memory.   We already checked over in
+                * the VCL compiler, so this is only relevant for refreshes.
+                * XXX: which we do when exactly ?
+                */
+               cli_out(cli, "DNS(/hosts) lookup failed for (%s/%s): %s",
+                   bp->vrt->hostname, bp->vrt->portname, gai_strerror(error));
+               return;
+       }
+       LOCK(&bp->mtx);
+       old = bp->ai;
+       bp->ai = res;
+       bp->last_ai = res;
+       UNLOCK(&bp->mtx);
+       if (old != NULL)
+               freeaddrinfo(old);
+}
+
+/*--------------------------------------------------------------------
+ * Add a backend/director instance when loading a VCL.
+ * If an existing backend is matched, grab a refcount and return.
+ * Else create a new backend structure with reference initialized to one.
+ */
+
+struct backend *
+VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb)
+{
+       struct backend *b;
+       uint32_t u;
+
+       AN(vb->hostname);
+       AN(vb->portname);
+       AN(vb->ident);
+       (void)cli;
+       ASSERT_CLI();
+       u = crc32_l(vb->ident, strlen(vb->ident));
+       VTAILQ_FOREACH(b, &backends, list) {
+               CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+               if (u != b->hash)
+                       continue;
+               if (strcmp(b->vrt->ident, vb->ident))
+                       continue;
+               b->refcount++;
+               return (b);
+       }
+
+       ALLOC_OBJ(b, BACKEND_MAGIC);
+       XXXAN(b);
+       b->magic = BACKEND_MAGIC;
+
+       VTAILQ_INIT(&b->connlist);
+       b->hash = u;
+
+       /*
+        * This backend may live longer than the VCL that instantiated it
+        * so we cannot simply reference the VCL's copy of things.
+        */
+       REPLACE(b->vrt->ident, vb->ident);
+       REPLACE(b->vrt->hostname, vb->hostname);
+       REPLACE(b->vrt->portname, vb->portname);
+       REPLACE(b->vrt->vcl_name, vb->vcl_name);
+
+       b->vrt->connect_timeout = vb->connect_timeout;
+
+       MTX_INIT(&b->mtx);
+       b->refcount = 1;
+
+       vbe_dns_lookup(cli, b);
+
+       VTAILQ_INSERT_TAIL(&backends, b, list);
+       VSL_stats->n_backend++;
+       return (b);
+}
+
+
+/*--------------------------------------------------------------------*/
+
+void
+VRT_fini_dir(struct cli *cli, struct director *b)
+{
+
+       (void)cli;
+       ASSERT_CLI();
+       CHECK_OBJ_NOTNULL(b, DIRECTOR_MAGIC);
+       b->fini(b);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+cli_debug_backend(struct cli *cli, const char * const *av, void *priv)
+{
+       struct backend *b;
+
+       (void)av;
+       (void)priv;
+       ASSERT_CLI();
+       VTAILQ_FOREACH(b, &backends, list) {
+               CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+               cli_out(cli, "%p %s/%s/%s %d\n",
+                   b,
+                   b->vrt->vcl_name,
+                   b->vrt->hostname,
+                   b->vrt->portname,
+                   b->refcount);
+       }
+}
+
+static struct cli_proto debug_cmds[] = {
+       { "debug.backend", "debug.backend",
+           "\tExamine Backend internals\n", 0, 0, cli_debug_backend },
+       { NULL }
+};
+
+/*--------------------------------------------------------------------*/
+
+void
+VBE_Init(void)
+{
+
+       MTX_INIT(&VBE_mtx);
+       CLI_AddFuncs(DEBUG_CLI, debug_cmds);
+}