Changeset 970270


Ignore:
Timestamp:
2008-07-11 21:49:20 (6 years ago)
Author:
Poul-Henning Kamp <phk@…>
Branches:
2.0, 2.1, tags/varnish-2.0, tags/varnish-2.0-beta1, tags/varnish-2.0-beta1@3141, tags/varnish-2.0-beta2, tags/varnish-2.0-beta2@3221, tags/varnish-2.0-rc1, tags/varnish-2.0-rc1@3266, tags/varnish-2.0.1, tags/varnish-2.0.2, tags/varnish-2.0.3, tags/varnish-2.0.4, tags/varnish-2.0.5, tags/varnish-2.0.6, tags/varnish-2.1.0, tags/varnish-2.1.1, tags/varnish-2.1.2, tags/varnish-2.1.3, tags/varnish-2.1.4
Children:
3bc832
Parents:
ae1bc8
git-author:
Poul-Henning Kamp <phk@…> (2008-07-11 21:49:20)
git-committer:
Poul-Henning Kamp <phk@…> (2008-07-11 21:49:20)
Message:

Drop pseudo-automatic support for multihomed backends and require
clear expression of intent in VCL.

We now fail backend hostnames that resolve to multiple IPv4 or multiple
IPv6 addresses, in other words, you cannot use "cnn.com" as a backend
hostname specification without the compiler yelling at you:

% ./varnishd -d -d -b cnn.com -a :8080
Backend host "cnn.com": resolves to multiple IPv4 addresses.
Only one address is allowed.
Please specify which exact address you want to use, we found these:

64.236.16.20
64.236.16.52
64.236.24.12
64.236.29.120

[...]
VCL compilation failed

However, you _can_ use a hostname that resolves to both an IPv4 and
an IPv6 address, and the new paramter "prefer_ipv6" will determine
which one we try first in such cases.

The other part of this change is that we now do the DNS lookup at
VCL compiletime, and only then.

If your backend's DNS record (or /etc/hosts entry) changes IP#, you
must reload your VCL code to notify varnish.

Finer technical points:

We build a bytestring representation of the sockaddr's in VCC and
include them in the concept of backend identity, for an existing
backend (+ connections) to be reused for a new VCL the backend must
now be defined exactly the same way AND have the same resolved
IPv4/IPv6 addresses.

Since we never muck about with the address in the backend struct
anymore, it's static for the life of the struct backend instance,
we can simplify and eliminate the locking dance around our connection
attempts.

Also eliminate the struct vrt_backend inclusion in struct backend,
and instead make the relevat fields full-blown members of struct
backend. This eliminates a number of TRUST_ME() calls.

This is the companion commit to #2934 which prepared the VCL compiler.

git-svn-id:  http://www.varnish-cache.org/svn/trunk@2936 d4fa192b-c00b-0410-8231-f00ffab90ce4

Location:
bin/varnishd
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • bin/varnishd/cache_backend.c

    rc2d3fa r970270  
    4242 
    4343#include <sys/socket.h> 
    44 #include <netdb.h> 
    4544 
    4645#include "shmlog.h" 
    4746#include "cache.h" 
    48 #include "vrt.h" 
    4947#include "cache_backend.h" 
    5048 
     
    7169        CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); 
    7270        http_PrintfHeader(sp->wrk, sp->fd, sp->bereq->http, 
    73             "Host: %s", sp->backend->vrt->hostname); 
     71            "Host: %s", sp->backend->hosthdr); 
    7472} 
    7573 
     
    8482 
    8583static int 
    86 VBE_TryConnect(const struct sess *sp, const struct addrinfo *ai) 
    87 { 
    88         struct sockaddr_storage ss; 
    89         int fam, sockt, proto; 
    90         socklen_t alen; 
     84VBE_TryConnect(const struct sess *sp, int pf, const struct sockaddr *sa, socklen_t salen) 
     85{ 
    9186        int s, i, tmo; 
    9287        char abuf1[TCP_ADDRBUFSIZE], abuf2[TCP_ADDRBUFSIZE]; 
     
    9691        CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); 
    9792 
    98         /* 
    99          * ai is only valid with the lock held, so copy out the bits 
    100          * we need to make the connection 
    101          */ 
    102         fam = ai->ai_family; 
    103         sockt = ai->ai_socktype; 
    104         proto = ai->ai_protocol; 
    105         alen = ai->ai_addrlen; 
    106         assert(alen <= sizeof ss); 
    107         memcpy(&ss, ai->ai_addr, alen); 
    108  
    109         /* release lock during stuff that can take a long time */ 
    110         UNLOCK(&sp->backend->mtx); 
    111  
    112         s = socket(fam, sockt, proto); 
     93        s = socket(pf, SOCK_STREAM, 0); 
    11394        if (s < 0) { 
    11495                LOCK(&sp->backend->mtx); 
     
    11798 
    11899        tmo = params->connect_timeout; 
    119         if (sp->backend->vrt->connect_timeout > 10e-3) 
    120                 tmo = sp->backend->vrt->connect_timeout * 1000; 
     100        if (sp->backend->connect_timeout > 10e-3) 
     101                tmo = sp->backend->connect_timeout * 1000; 
    121102 
    122103        if (tmo > 0) 
    123                 i = TCP_connect(s, (void *)&ss, alen, tmo); 
     104                i = TCP_connect(s, sa, salen, tmo); 
    124105        else 
    125                 i = connect(s, (void *)&ss, alen); 
     106                i = connect(s, sa, salen); 
    126107 
    127108        if (i != 0) { 
    128109                AZ(close(s)); 
    129                 LOCK(&sp->backend->mtx); 
    130110                return (-1); 
    131111        } 
    132112 
    133113        TCP_myname(s, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1); 
    134         TCP_name((void*)&ss, alen, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2); 
     114        TCP_name(sa, salen, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2); 
    135115        WSL(sp->wrk, SLT_BackendOpen, s, "%s %s %s %s %s", 
    136             sp->backend->vrt->vcl_name, abuf1, pbuf1, abuf2, pbuf2); 
    137  
    138         LOCK(&sp->backend->mtx); 
     116            sp->backend->vcl_name, abuf1, pbuf1, abuf2, pbuf2); 
     117 
    139118        return (s); 
    140119} 
     
    255234} 
    256235 
    257 /*-------------------------------------------------------------------- 
    258  * Try to get a socket connected to one of the addresses on the list. 
    259  * We start from the cached "last good" address and try all items on 
    260  * the list exactly once. 
    261  * 
    262  * Called with backend mutex held, but will release/acquire it. 
    263  * 
    264  * XXX: Not ready for DNS re-lookups 
    265  */ 
    266  
    267 static int 
    268 bes_conn_try_list(const struct sess *sp, struct backend *bp) 
    269 { 
    270         struct addrinfo *ai, *from; 
    271         int s, loops; 
    272  
    273         CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC); 
    274  
    275         /* No addrinfo, no connection */ 
    276         if (bp->ai == NULL) 
    277                 return (-1); 
    278         AN(bp->last_ai); 
    279  
    280         /* Called with lock held */ 
    281         loops = 0; 
    282         ai = from = bp->last_ai; 
    283         while (loops == 0 || ai != from) { 
    284  
    285                 /* NB: releases/acquires backend lock */ 
    286                 s = VBE_TryConnect(sp, ai); 
    287  
    288                 if (s >= 0) {  
    289                         bp->last_ai = ai; 
    290                         return (s); 
    291                 } 
    292  
    293                 /* Try next one */ 
    294                 ai = ai->ai_next; 
    295                 if (ai == NULL) { 
    296                         loops++; 
    297                         ai = bp->ai; 
    298                 } 
    299         } 
    300         /* We have tried them all, fail */ 
    301         return (-1); 
    302 } 
    303  
    304  
    305236/*--------------------------------------------------------------------*/ 
    306237 
     
    312243        LOCK(&bp->mtx); 
    313244        bp->refcount++; 
    314         s = bes_conn_try_list(sp, bp);  /* releases/acquires backend lock */ 
    315         if (s < 0) 
     245        UNLOCK(&sp->backend->mtx); 
     246 
     247        s = -1; 
     248        assert(bp->ipv6 != NULL || bp->ipv4 != NULL); 
     249 
     250        /* release lock during stuff that can take a long time */ 
     251 
     252        if (params->prefer_ipv6 && bp->ipv6 != NULL) 
     253                s = VBE_TryConnect(sp, PF_INET6, bp->ipv6, bp->ipv6len); 
     254        if (s == -1 && bp->ipv4 != NULL) 
     255                s = VBE_TryConnect(sp, PF_INET, bp->ipv4, bp->ipv4len); 
     256        if (s == -1 && !params->prefer_ipv6 && bp->ipv6 != NULL) 
     257                s = VBE_TryConnect(sp, PF_INET6, bp->ipv6, bp->ipv6len); 
     258 
     259        if (s < 0) { 
     260                LOCK(&sp->backend->mtx); 
    316261                bp->refcount--;         /* Only keep ref on success */ 
    317         UNLOCK(&bp->mtx); 
     262                UNLOCK(&bp->mtx); 
     263        } 
    318264        return (s); 
    319265} 
     
    378324        b = vc->backend; 
    379325        assert(vc->fd >= 0); 
    380         WSL(w, SLT_BackendClose, vc->fd, "%s", vc->backend->vrt->vcl_name); 
     326        WSL(w, SLT_BackendClose, vc->fd, "%s", vc->backend->vcl_name); 
    381327        i = close(vc->fd); 
    382328        assert(i == 0 || errno == ECONNRESET || errno == ENOTCONN); 
     
    399345        assert(vc->fd >= 0); 
    400346        bp = vc->backend; 
    401         WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vrt->vcl_name); 
     347        WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vcl_name); 
    402348        LOCK(&vc->backend->mtx); 
    403349        VSL_stats->backend_recycle++; 
  • bin/varnishd/cache_backend.h

    rc2d3fa r970270  
    7474#define BACKEND_MAGIC           0x64c4c7c6 
    7575 
    76         struct vrt_backend      vrt[1]; 
     76        char                    *hosthdr; 
     77        char                    *ident; 
     78        char                    *vcl_name; 
     79        double                  connect_timeout; 
     80 
    7781        uint32_t                hash; 
    7882 
     
    8185        pthread_mutex_t         mtx; 
    8286 
    83         struct addrinfo         *ai; 
    84         struct addrinfo         *last_ai; 
     87        struct sockaddr         *ipv4; 
     88        socklen_t               ipv4len; 
     89        struct sockaddr         *ipv6; 
     90        socklen_t               ipv6len; 
    8591 
    8692        VTAILQ_HEAD(, vbe_conn) connlist; 
  • bin/varnishd/cache_backend_cfg.c

    rc2d3fa r970270  
    4242 
    4343#include <sys/socket.h> 
    44 #include <netdb.h> 
    4544 
    4645#include "shmlog.h" 
     
    10099                VBE_ReleaseConn(vbe); 
    101100        } 
    102         free(TRUST_ME(b->vrt->ident)); 
    103         free(TRUST_ME(b->vrt->hostname)); 
    104         free(TRUST_ME(b->vrt->portname)); 
     101        free(b->ident); 
     102        free(b->hosthdr); 
     103        free(b->ipv4); 
     104        free(b->ipv6); 
    105105        b->magic = 0; 
    106106        free(b); 
     
    118118} 
    119119 
    120 /*-------------------------------------------------------------------- 
    121  * DNS lookup of backend host/port 
    122  */ 
     120/*--------------------------------------------------------------------*/ 
    123121 
    124122static void 
    125 vbe_dns_lookup(const struct cli *cli, struct backend *bp) 
    126 { 
    127         int error; 
    128         struct addrinfo *res, hint, *old; 
    129  
    130         CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC); 
    131  
    132         memset(&hint, 0, sizeof hint); 
    133         hint.ai_family = PF_UNSPEC; 
    134         hint.ai_socktype = SOCK_STREAM; 
    135         res = NULL; 
    136         error = getaddrinfo(bp->vrt->hostname, bp->vrt->portname, 
    137             &hint, &res); 
    138         if (error) { 
    139                 if (res != NULL) 
    140                         freeaddrinfo(res); 
    141                 /* 
    142                  * We cannot point to the source code any more, it may 
    143                  * be long gone from memory.   We already checked over in 
    144                  * the VCL compiler, so this is only relevant for refreshes. 
    145                  * XXX: which we do when exactly ? 
    146                  */ 
    147                 cli_out(cli, "DNS(/hosts) lookup failed for (%s/%s): %s", 
    148                     bp->vrt->hostname, bp->vrt->portname, gai_strerror(error)); 
    149                 return; 
    150         } 
    151         LOCK(&bp->mtx); 
    152         old = bp->ai; 
    153         bp->ai = res; 
    154         bp->last_ai = res; 
    155         UNLOCK(&bp->mtx); 
    156         if (old != NULL) 
    157                 freeaddrinfo(old); 
     123copy_sockaddr(struct sockaddr **sa, socklen_t *len, const unsigned char *src) 
     124{ 
     125 
     126        assert(*src > 0); 
     127        *sa = malloc(*src); 
     128        AN(*sa); 
     129        memcpy(*sa, src + 1, *src); 
     130        *len = *src; 
    158131} 
    159132 
     
    170143        uint32_t u; 
    171144 
    172         AN(vb->hostname); 
    173         AN(vb->portname); 
    174145        AN(vb->ident); 
     146        assert(vb->ipv4_sockaddr != NULL || vb->ipv6_sockaddr != NULL); 
    175147        (void)cli; 
    176148        ASSERT_CLI(); 
    177         u = crc32_l(vb->ident, strlen(vb->ident)); 
     149 
     150        /* calculate a hash of (ident + ipv4_sockaddr + ipv6_sockaddr) */ 
     151        u = crc32(~0U, vb->ident, strlen(vb->ident)); 
     152        if (vb->ipv4_sockaddr != NULL) 
     153                u = crc32(u, vb->ipv4_sockaddr + 1, vb->ipv4_sockaddr[0]); 
     154        if (vb->ipv6_sockaddr != NULL) 
     155                u = crc32(u, vb->ipv6_sockaddr + 1, vb->ipv6_sockaddr[0]); 
     156 
     157        /* Run through the list and see if we already have this backend */ 
    178158        VTAILQ_FOREACH(b, &backends, list) { 
    179159                CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); 
    180160                if (u != b->hash) 
    181161                        continue; 
    182                 if (strcmp(b->vrt->ident, vb->ident)) 
     162                if (strcmp(b->ident, vb->ident)) 
     163                        continue; 
     164                if (vb->ipv4_sockaddr != NULL && 
     165                    b->ipv4len != vb->ipv4_sockaddr[0]) 
     166                        continue; 
     167                if (vb->ipv6_sockaddr != NULL && 
     168                    b->ipv6len != vb->ipv6_sockaddr[0]) 
     169                        continue; 
     170                if (b->ipv4len != 0 && 
     171                    memcmp(b->ipv4, vb->ipv4_sockaddr + 1, b->ipv4len)) 
     172                        continue; 
     173                if (b->ipv6len != 0 && 
     174                    memcmp(b->ipv6, vb->ipv6_sockaddr + 1, b->ipv6len)) 
    183175                        continue; 
    184176                b->refcount++; 
     
    186178        } 
    187179 
     180        /* Create new backend */ 
    188181        ALLOC_OBJ(b, BACKEND_MAGIC); 
    189182        XXXAN(b); 
    190         b->magic = BACKEND_MAGIC; 
     183        MTX_INIT(&b->mtx); 
     184        b->refcount = 1; 
    191185 
    192186        VTAILQ_INIT(&b->connlist); 
     
    197191         * so we cannot simply reference the VCL's copy of things. 
    198192         */ 
    199         REPLACE(b->vrt->ident, vb->ident); 
    200         REPLACE(b->vrt->hostname, vb->hostname); 
    201         REPLACE(b->vrt->portname, vb->portname); 
    202         REPLACE(b->vrt->vcl_name, vb->vcl_name); 
    203  
    204         b->vrt->connect_timeout = vb->connect_timeout; 
    205  
    206         MTX_INIT(&b->mtx); 
    207         b->refcount = 1; 
    208  
    209         vbe_dns_lookup(cli, b); 
     193        REPLACE(b->ident, vb->ident); 
     194        REPLACE(b->vcl_name, vb->vcl_name); 
     195        REPLACE(b->hosthdr, vb->hostname); 
     196 
     197        b->connect_timeout = vb->connect_timeout; 
     198 
     199        /* 
     200         * Copy over the sockaddrs 
     201         */ 
     202        if (vb->ipv4_sockaddr != NULL)  
     203                copy_sockaddr(&b->ipv4, &b->ipv4len, vb->ipv4_sockaddr); 
     204        if (vb->ipv6_sockaddr != NULL)  
     205                copy_sockaddr(&b->ipv6, &b->ipv6len, vb->ipv6_sockaddr); 
     206 
     207        assert(b->ipv4 != NULL || b->ipv6 != NULL); 
    210208 
    211209        VTAILQ_INSERT_TAIL(&backends, b, list); 
     
    239237        VTAILQ_FOREACH(b, &backends, list) { 
    240238                CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); 
    241                 cli_out(cli, "%p %s/%s/%s %d\n", 
     239                cli_out(cli, "%p %s %d\n", 
    242240                    b, 
    243                     b->vrt->vcl_name, 
    244                     b->vrt->hostname, 
    245                     b->vrt->portname, 
     241                    b->vcl_name, 
    246242                    b->refcount); 
    247243        } 
  • bin/varnishd/heritage.h

    rd00334 r970270  
    167167        /* Log local socket address to shm */ 
    168168        unsigned                log_local_addr; 
     169 
     170        /* Prefer IPv6 connections to backend*/ 
     171        unsigned                prefer_ipv6; 
    169172}; 
    170173 
  • bin/varnishd/mgt_param.c

    rb97057 r970270  
    736736                0, 
    737737                "400", "ms" }, 
     738        { "prefer_ipv6", tweak_bool, &master.prefer_ipv6, 0, 0, 
     739                "Prefer IPv6 address when connecting to backends which " 
     740                "have both IPv4 and IPv6 addresses.", 
     741                0, 
     742                "off", "bool" }, 
    738743        { "session_linger", tweak_uint, 
    739744                &master.session_linger,0, UINT_MAX, 
Note: See TracChangeset for help on using the changeset viewer.