varnish-cache/bin/varnishd/cache/cache_ban.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <stdlib.h>
35
#include <stdio.h>
36
37
#include "cache_varnishd.h"
38
#include "cache_ban.h"
39
#include "cache_objhead.h"
40
41
#include "vcli_serve.h"
42
#include "vend.h"
43
#include "vmb.h"
44
45
/* cache_ban_build.c */
46
void BAN_Build_Init(void);
47
void BAN_Build_Fini(void);
48
49
struct lock ban_mtx;
50
int ban_shutdown;
51
struct banhead_s ban_head = VTAILQ_HEAD_INITIALIZER(ban_head);
52
struct ban * volatile ban_start;
53
54
static pthread_t ban_thread;
55
static int ban_holds;
56
uint64_t bans_persisted_bytes;
57
uint64_t bans_persisted_fragmentation;
58
59
struct ban_test {
60
        uint8_t                 oper;
61
        uint8_t                 arg1;
62
        const char              *arg1_spec;
63
        const char              *arg2;
64
        double                  arg2_double;
65
        const void              *arg2_spec;
66
};
67
68
static const char * const arg_name[BAN_ARGARRSZ + 1] = {
69
#define PVAR(a, b, c) [BAN_ARGIDX(c)] = (a),
70
#include "tbl/ban_vars.h"
71
        [BAN_ARGARRSZ] = NULL
72
};
73
74
/*--------------------------------------------------------------------
75
 * Storage handling of bans
76
 */
77
78
static struct ban *
79 1040
ban_alloc(void)
80
{
81
        struct ban *b;
82
83 1040
        ALLOC_OBJ(b, BAN_MAGIC);
84 1040
        if (b != NULL)
85 1040
                VTAILQ_INIT(&b->objcore);
86 1040
        return (b);
87
}
88
89
void
90 2883
BAN_Free(struct ban *b)
91
{
92
93 2883
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
94 2883
        AZ(b->refcount);
95 2883
        assert(VTAILQ_EMPTY(&b->objcore));
96
97 2883
        if (b->spec != NULL)
98 2883
                free(b->spec);
99 2883
        FREE_OBJ(b);
100 2883
}
101
102
/*--------------------------------------------------------------------
103
 * Get/release holds which prevent the ban_lurker from starting.
104
 * Holds are held while stevedores load zombie objects.
105
 */
106
107
void
108 1520
BAN_Hold(void)
109
{
110
111 1520
        Lck_Lock(&ban_mtx);
112
        /* Once holds are released, we allow no more */
113 1520
        assert(ban_holds > 0);
114 1520
        ban_holds++;
115 1520
        Lck_Unlock(&ban_mtx);
116 1520
}
117
118
void
119 38584
BAN_Release(void)
120
{
121
122 38584
        Lck_Lock(&ban_mtx);
123 38584
        assert(ban_holds > 0);
124 38584
        ban_holds--;
125 38584
        Lck_Unlock(&ban_mtx);
126 38584
        if (ban_holds == 0)
127 37064
                WRK_BgThread(&ban_thread, "ban-lurker", ban_lurker, NULL);
128 38584
}
129
130
/*--------------------------------------------------------------------
131
 * Extract time and length from ban-spec
132
 */
133
134
vtim_real
135 37760
ban_time(const uint8_t *banspec)
136
{
137
        vtim_real t;
138
        uint64_t u;
139
140 37760
        assert(sizeof t == sizeof u);
141 37760
        assert(sizeof t == (BANS_LENGTH - BANS_TIMESTAMP));
142 37760
        u = vbe64dec(banspec + BANS_TIMESTAMP);
143 37760
        memcpy(&t, &u, sizeof t);
144 37760
        return (t);
145
}
146
147
unsigned
148 240259
ban_len(const uint8_t *banspec)
149
{
150
        unsigned u;
151
152 240259
        u = vbe32dec(banspec + BANS_LENGTH);
153 240259
        return (u);
154
}
155
156
int
157 11520
ban_equal(const uint8_t *bs1, const uint8_t *bs2)
158
{
159
        unsigned u;
160
161
        /*
162
         * Compare two ban-strings.
163
         */
164 11520
        u = ban_len(bs1);
165 11520
        if (u != ban_len(bs2))
166 4360
                return (0);
167 7160
        if (bs1[BANS_FLAGS] & BANS_FLAG_NODEDUP)
168 120
                return (0);
169
170 7040
        return (!memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH));
171 11520
}
172
173
void
174 39104
ban_mark_completed(struct ban *b)
175
{
176
        unsigned ln;
177
178 39104
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
179 39104
        Lck_AssertHeld(&ban_mtx);
180
181 39104
        AN(b->spec);
182 39104
        if (!(b->flags & BANS_FLAG_COMPLETED)) {
183 39104
                ln = ban_len(b->spec);
184 39104
                b->flags |= BANS_FLAG_COMPLETED;
185 39104
                b->spec[BANS_FLAGS] |= BANS_FLAG_COMPLETED;
186 39104
                VWMB();
187 39104
                vbe32enc(b->spec + BANS_LENGTH, BANS_HEAD_LEN);
188 39104
                VSC_C_main->bans_completed++;
189 39104
                bans_persisted_fragmentation += ln - ban_len(b->spec);
190 39104
                VSC_C_main->bans_persisted_fragmentation =
191 39104
                    bans_persisted_fragmentation;
192 39104
        }
193 39104
}
194
195
/*--------------------------------------------------------------------
196
 * Access a lump of bytes in a ban test spec
197
 */
198
199
static const void *
200 16520
ban_get_lump(const uint8_t **bs)
201
{
202
        const void *r;
203
        unsigned ln;
204
205 101640
        while (**bs == 0xff)
206 85120
                *bs += 1;
207 16520
        ln = vbe32dec(*bs);
208 16520
        *bs += PRNDUP(sizeof(uint32_t));
209 16520
        assert(PAOK(*bs));
210 16520
        r = (const void*)*bs;
211 16520
        *bs += ln;
212 16520
        return (r);
213
}
214
215
/*--------------------------------------------------------------------
216
 * Pick a test apart from a spec string
217
 */
218
219
static void
220 14520
ban_iter(const uint8_t **bs, struct ban_test *bt)
221
{
222
        const void *lump;
223
        uint64_t dtmp;
224
225 14520
        memset(bt, 0, sizeof *bt);
226 14520
        bt->arg2_double = nan("");
227 14520
        bt->arg1 = *(*bs)++;
228 14520
        if (BANS_HAS_ARG1_SPEC(bt->arg1)) {
229 4080
                bt->arg1_spec = (const char *)*bs;
230 4080
                (*bs) += (*bs)[0] + 2;
231 4080
        }
232 14520
        lump = ban_get_lump(bs);
233 14520
        bt->oper = *(*bs)++;
234 14520
        if (BANS_HAS_ARG2_DOUBLE(bt->arg1)) {
235 6280
                dtmp = vbe64dec(lump);
236 6280
                memcpy(&bt->arg2_double, &dtmp, sizeof dtmp);
237 6280
                return;
238
        }
239 8240
        bt->arg2 = lump;
240 8240
        if (BANS_HAS_ARG2_SPEC(bt->oper))
241 2000
                bt->arg2_spec = ban_get_lump(bs);
242 14520
}
243
244
/*--------------------------------------------------------------------
245
 * A new object is created, grab a reference to the newest ban
246
 */
247
248
void
249 56559
BAN_NewObjCore(struct objcore *oc)
250
{
251
252 56559
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
253 56559
        AZ(oc->ban);
254 56559
        AN(oc->objhead);
255 56559
        Lck_Lock(&ban_mtx);
256 56559
        oc->ban = ban_start;
257 56559
        ban_start->refcount++;
258 56559
        VTAILQ_INSERT_TAIL(&ban_start->objcore, oc, ban_list);
259 56559
        Lck_Unlock(&ban_mtx);
260 56559
}
261
262
/*--------------------------------------------------------------------
263
 * An object is destroyed, release its ban reference
264
 */
265
266
void
267 73630
BAN_DestroyObj(struct objcore *oc)
268
{
269
270 73630
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
271 73630
        if (oc->ban == NULL)
272 58942
                return;
273 14688
        Lck_Lock(&ban_mtx);
274 14688
        CHECK_OBJ_ORNULL(oc->ban, BAN_MAGIC);
275 14688
        if (oc->ban != NULL) {
276 14688
                assert(oc->ban->refcount > 0);
277 14688
                oc->ban->refcount--;
278 14688
                VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list);
279 14688
                oc->ban = NULL;
280 14688
        }
281 14688
        Lck_Unlock(&ban_mtx);
282 73630
}
283
284
/*--------------------------------------------------------------------
285
 * Find a ban based on a timestamp.
286
 * Assume we have a BAN_Hold, so list traversal is safe.
287
 */
288
289
struct ban *
290 680
BAN_FindBan(vtim_real t0)
291
{
292
        struct ban *b;
293
        vtim_real t1;
294
295 680
        assert(ban_holds > 0);
296 1840
        VTAILQ_FOREACH(b, &ban_head, list) {
297 1840
                t1 = ban_time(b->spec);
298 1840
                if (t1 == t0)
299 680
                        return (b);
300 1160
                if (t1 < t0)
301 0
                        break;
302 1160
        }
303 0
        return (NULL);
304 680
}
305
306
/*--------------------------------------------------------------------
307
 * Grab a reference to a ban and associate the objcore with that ban.
308
 * Assume we have a BAN_Hold, so list traversal is safe.
309
 */
310
311
void
312 680
BAN_RefBan(struct objcore *oc, struct ban *b)
313
{
314
315 680
        Lck_Lock(&ban_mtx);
316 680
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
317 680
        AZ(oc->ban);
318 680
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
319 680
        assert(ban_holds > 0);
320 680
        b->refcount++;
321 680
        VTAILQ_INSERT_TAIL(&b->objcore, oc, ban_list);
322 680
        oc->ban = b;
323 680
        Lck_Unlock(&ban_mtx);
324 680
}
325
326
/*--------------------------------------------------------------------
327
 * Compile a full ban list and export this area to the stevedores for
328
 * persistence.
329
 */
330
331
static void
332 73704
ban_export(void)
333
{
334
        struct ban *b;
335
        struct vsb *vsb;
336
        unsigned ln;
337
338 73704
        Lck_AssertHeld(&ban_mtx);
339 73704
        ln = bans_persisted_bytes - bans_persisted_fragmentation;
340 73704
        vsb = VSB_new_auto();
341 73704
        AN(vsb);
342 150605
        VTAILQ_FOREACH_REVERSE(b, &ban_head, banhead_s, list)
343 76901
                AZ(VSB_bcat(vsb, b->spec, ban_len(b->spec)));
344 73704
        AZ(VSB_finish(vsb));
345 73704
        assert(VSB_len(vsb) == ln);
346 73704
        STV_BanExport((const uint8_t *)VSB_data(vsb), VSB_len(vsb));
347 73704
        VSB_destroy(&vsb);
348 73704
        VSC_C_main->bans_persisted_bytes =
349 73704
            bans_persisted_bytes = ln;
350 73704
        VSC_C_main->bans_persisted_fragmentation =
351 73704
            bans_persisted_fragmentation = 0;
352 73704
}
353
354
/*
355
 * For both of these we do a full export on info failure to remove
356
 * holes in the exported list.
357
 * XXX: we should keep track of the size of holes in the last exported list
358
 * XXX: check if the ban_export should be batched in ban_cleantail
359
 */
360
void
361 41064
ban_info_new(const uint8_t *ban, unsigned len)
362
{
363
        /* XXX martin pls review if ban_mtx needs to be held */
364 41064
        Lck_AssertHeld(&ban_mtx);
365 41064
        if (STV_BanInfoNew(ban, len))
366 0
                ban_export();
367 41064
}
368
369
void
370 2883
ban_info_drop(const uint8_t *ban, unsigned len)
371
{
372
        /* XXX martin pls review if ban_mtx needs to be held */
373 2883
        Lck_AssertHeld(&ban_mtx);
374 2883
        if (STV_BanInfoDrop(ban, len))
375 0
                ban_export();
376 2883
}
377
378
/*--------------------------------------------------------------------
379
 * Put a skeleton ban in the list, unless there is an identical,
380
 * time & condition, ban already in place.
381
 *
382
 * If a newer ban has same condition, mark the inserted ban COMPLETED,
383
 * also mark any older bans, with the same condition COMPLETED.
384
 */
385
386
static void
387 1360
ban_reload(const uint8_t *ban, unsigned len)
388
{
389
        struct ban *b, *b2;
390 1360
        int duplicate = 0;
391 1360
        vtim_real t0, t1, t2 = 9e99;
392 1360
        ASSERT_CLI();
393 1360
        Lck_AssertHeld(&ban_mtx);
394
395 1360
        t0 = ban_time(ban);
396 1360
        assert(len == ban_len(ban));
397
398 2960
        VTAILQ_FOREACH(b, &ban_head, list) {
399 2320
                t1 = ban_time(b->spec);
400 2320
                assert(t1 < t2);
401 2320
                t2 = t1;
402 2320
                if (t1 == t0)
403 320
                        return;
404 2000
                if (t1 < t0)
405 400
                        break;
406 1600
                if (ban_equal(b->spec, ban))
407 960
                        duplicate = 1;
408 1600
        }
409
410 1040
        VSC_C_main->bans++;
411 1040
        VSC_C_main->bans_added++;
412
413 1040
        b2 = ban_alloc();
414 1040
        AN(b2);
415 1040
        b2->spec = malloc(len);
416 1040
        AN(b2->spec);
417 1040
        memcpy(b2->spec, ban, len);
418 1040
        if (ban[BANS_FLAGS] & BANS_FLAG_REQ) {
419 200
                VSC_C_main->bans_req++;
420 200
                b2->flags |= BANS_FLAG_REQ;
421 200
        }
422 1040
        if (duplicate)
423 720
                VSC_C_main->bans_dups++;
424 1040
        if (duplicate || (ban[BANS_FLAGS] & BANS_FLAG_COMPLETED))
425 760
                ban_mark_completed(b2);
426 1040
        if (b == NULL)
427 640
                VTAILQ_INSERT_TAIL(&ban_head, b2, list);
428
        else
429 400
                VTAILQ_INSERT_BEFORE(b, b2, list);
430 1040
        bans_persisted_bytes += len;
431 1040
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
432
433
        /* Hunt down older duplicates */
434 1640
        for (b = VTAILQ_NEXT(b2, list); b != NULL; b = VTAILQ_NEXT(b, list)) {
435 600
                if (b->flags & BANS_FLAG_COMPLETED)
436 560
                        continue;
437 40
                if (ban_equal(b->spec, ban)) {
438 0
                        ban_mark_completed(b);
439 0
                        VSC_C_main->bans_dups++;
440 0
                }
441 40
        }
442 1360
}
443
444
/*--------------------------------------------------------------------
445
 * Reload a series of persisted ban specs
446
 */
447
448
void
449 1520
BAN_Reload(const uint8_t *ptr, unsigned len)
450
{
451
        const uint8_t *pe;
452
        unsigned l;
453
454 1520
        AZ(ban_shutdown);
455 1520
        pe = ptr + len;
456 1520
        Lck_Lock(&ban_mtx);
457 2880
        while (ptr < pe) {
458
                /* XXX: This can be optimized by traversing the live
459
                 * ban list together with the reload list (combining
460
                 * the loops in BAN_Reload and ban_reload). */
461 1360
                l = ban_len(ptr);
462 1360
                assert(ptr + l <= pe);
463 1360
                ban_reload(ptr, l);
464 1360
                ptr += l;
465
        }
466 1520
        Lck_Unlock(&ban_mtx);
467 1520
}
468
469
/*--------------------------------------------------------------------
470
 * Get a bans timestamp
471
 */
472
473
vtim_real
474 2800
BAN_Time(const struct ban *b)
475
{
476
477 2800
        if (b == NULL)
478 880
                return (0.0);
479
480 1920
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
481 1920
        return (ban_time(b->spec));
482 2800
}
483
484
/*--------------------------------------------------------------------
485
 * Evaluate ban-spec
486
 */
487
488
int
489 3600
ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc,
490
    const struct http *reqhttp, unsigned *tests)
491
{
492
        struct ban_test bt;
493
        const uint8_t *bs, *be;
494
        const char *p;
495
        const char *arg1;
496
        double darg1, darg2;
497
        int rv;
498
499
        /*
500
         * for ttl, age and last_hit, fix the point in time such that banning
501
         * refers to the same point in time when the ban is evaluated
502
         *
503
         * for grace/keep, we assume that the absolute values are pola and that
504
         * users will most likely also specify a ttl criterion if they want to
505
         * fix a point in time (such as "obj.ttl > 5h && obj.keep > 3h")
506
         */
507
508 3600
        bs = bsarg;
509 3600
        be = bs + ban_len(bs);
510 3600
        bs += BANS_HEAD_LEN;
511 6000
        while (bs < be) {
512 4160
                (*tests)++;
513 4160
                ban_iter(&bs, &bt);
514 4160
                arg1 = NULL;
515 4160
                darg1 = darg2 = nan("");
516 4160
                switch (bt.arg1) {
517
                case BANS_ARG_URL:
518 1080
                        AN(reqhttp);
519 1080
                        arg1 = reqhttp->hd[HTTP_HDR_URL].b;
520 1080
                        break;
521
                case BANS_ARG_REQHTTP:
522 360
                        AN(reqhttp);
523 360
                        (void)http_GetHdr(reqhttp, bt.arg1_spec, &p);
524 360
                        arg1 = p;
525 360
                        break;
526
                case BANS_ARG_OBJHTTP:
527 1280
                        arg1 = HTTP_GetHdrPack(wrk, oc, bt.arg1_spec);
528 1280
                        break;
529
                case BANS_ARG_OBJSTATUS:
530 560
                        arg1 = HTTP_GetHdrPack(wrk, oc, H__Status);
531 560
                        break;
532
                case BANS_ARG_OBJTTL:
533 200
                        darg1 = oc->ttl + oc->t_origin;
534 200
                        darg2 = bt.arg2_double + ban_time(bsarg);
535 200
                        break;
536
                case BANS_ARG_OBJAGE:
537 200
                        darg1 = 0.0 - oc->t_origin;
538 200
                        darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double);
539 200
                        break;
540
                case BANS_ARG_OBJGRACE:
541 120
                        darg1 = oc->grace;
542 120
                        darg2 = bt.arg2_double;
543 120
                        break;
544
                case BANS_ARG_OBJKEEP:
545 280
                        darg1 = oc->keep;
546 280
                        darg2 = bt.arg2_double;
547 280
                        break;
548
                case BANS_ARG_OBJLASTHIT:
549 80
                        if (isnan(oc->last_lru))
550 0
                                return (0);
551 80
                        darg1 = 0.0 - oc->last_lru;
552 80
                        darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double);
553 80
                        break;
554
                default:
555 0
                        WRONG("Wrong BAN_ARG code");
556 0
                }
557
558 4160
                switch (bt.oper) {
559
                case BANS_OPER_EQ:
560 2240
                        if (arg1 == NULL) {
561 440
                                if (isnan(darg1) || darg1 != darg2)
562 200
                                        return (0);
563 2040
                        } else if (strcmp(arg1, bt.arg2)) {
564 840
                                return (0);
565
                        }
566 1200
                        break;
567
                case BANS_OPER_NEQ:
568 480
                        if (arg1 == NULL) {
569 280
                                if (! isnan(darg1) && darg1 == darg2)
570 160
                                        return (0);
571 320
                        } else if (!strcmp(arg1, bt.arg2)) {
572 80
                                return (0);
573
                        }
574 240
                        break;
575
                case BANS_OPER_MATCH:
576 960
                        if (arg1 == NULL)
577 40
                                return (0);
578 920
                        rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL);
579 920
                        xxxassert(rv >= -1);
580 920
                        if (rv < 0)
581 80
                                return (0);
582 840
                        break;
583
                case BANS_OPER_NMATCH:
584 0
                        if (arg1 == NULL)
585 0
                                return (0);
586 0
                        rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL);
587 0
                        xxxassert(rv >= -1);
588 0
                        if (rv >= 0)
589 0
                                return (0);
590 0
                        break;
591
                case BANS_OPER_GT:
592 320
                        AZ(arg1);
593 320
                        assert(! isnan(darg1));
594 320
                        if (!(darg1 > darg2))
595 320
                                return (0);
596 0
                        break;
597
                case BANS_OPER_GTE:
598 0
                        AZ(arg1);
599 0
                        assert(! isnan(darg1));
600 0
                        if (!(darg1 >= darg2))
601 0
                                return (0);
602 0
                        break;
603
                case BANS_OPER_LT:
604 120
                        AZ(arg1);
605 120
                        assert(! isnan(darg1));
606 120
                        if (!(darg1 < darg2))
607 40
                                return (0);
608 80
                        break;
609
                case BANS_OPER_LTE:
610 40
                        AZ(arg1);
611 40
                        assert(! isnan(darg1));
612 40
                        if (!(darg1 <= darg2))
613 0
                                return (0);
614 40
                        break;
615
                default:
616 0
                        WRONG("Wrong BAN_OPER code");
617 0
                }
618
        }
619 1840
        return (1);
620 3600
}
621
622
/*--------------------------------------------------------------------
623
 * Check an object against all applicable bans
624
 *
625
 * Return:
626
 *      -1 not all bans checked, but none of the checked matched
627
 *              Only if !has_req
628
 *      0 No bans matched, object moved to ban_start.
629
 *      1 Ban matched, object removed from ban list.
630
 */
631
632
int
633 154314
BAN_CheckObject(struct worker *wrk, struct objcore *oc, struct req *req)
634
{
635
        struct ban *b;
636
        struct vsl_log *vsl;
637
        struct ban *b0, *bn;
638
        unsigned tests;
639
640 154314
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
641 154314
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
642 154314
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
643 154314
        Lck_AssertHeld(&oc->objhead->mtx);
644 154314
        assert(oc->refcnt > 0);
645
646 154314
        vsl = req->vsl;
647
648 154314
        CHECK_OBJ_NOTNULL(oc->ban, BAN_MAGIC);
649
650
        /* First do an optimistic unlocked check */
651 154314
        b0 = ban_start;
652 154314
        CHECK_OBJ_NOTNULL(b0, BAN_MAGIC);
653
654 154314
        if (b0 == oc->ban)
655 151874
                return (0);
656
657
        /* If that fails, make a safe check */
658 2440
        Lck_Lock(&ban_mtx);
659 2440
        b0 = ban_start;
660 2440
        bn = oc->ban;
661 2440
        if (b0 != bn)
662 2440
                bn->refcount++;
663 2440
        Lck_Unlock(&ban_mtx);
664
665 2440
        AN(bn);
666
667 2440
        if (b0 == bn)
668 0
                return (0);
669
670 2440
        AN(b0);
671 2440
        AN(bn);
672
673
        /*
674
         * This loop is safe without locks, because we know we hold
675
         * a refcount on a ban somewhere in the list and we do not
676
         * inspect the list past that ban.
677
         */
678 2440
        tests = 0;
679 4160
        for (b = b0; b != bn; b = VTAILQ_NEXT(b, list)) {
680 3080
                CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
681 3080
                if (b->flags & BANS_FLAG_COMPLETED)
682 800
                        continue;
683 2280
                if (ban_evaluate(wrk, b->spec, oc, req->http, &tests))
684 1360
                        break;
685 920
        }
686
687 2440
        Lck_Lock(&ban_mtx);
688 2440
        bn->refcount--;
689 2440
        VSC_C_main->bans_tested++;
690 2440
        VSC_C_main->bans_tests_tested += tests;
691
692 2440
        if (b == bn) {
693
                /* not banned */
694 1080
                oc->ban->refcount--;
695 1080
                VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list);
696 1080
                VTAILQ_INSERT_TAIL(&b0->objcore, oc, ban_list);
697 1080
                b0->refcount++;
698 1080
                oc->ban = b0;
699 1080
                b = NULL;
700 1080
        }
701 2440
        if (b != NULL)
702 1360
                VSC_C_main->bans_obj_killed++;
703
704 2440
        if (VTAILQ_LAST(&ban_head, banhead_s)->refcount == 0)
705 880
                ban_kick_lurker();
706
707 2440
        Lck_Unlock(&ban_mtx);
708
709 2440
        if (b == NULL) {
710
                /* not banned */
711 1080
                ObjSendEvent(wrk, oc, OEV_BANCHG);
712 1080
                return (0);
713
        } else {
714 2720
                VSLb(vsl, SLT_ExpBan,
715 1360
                    "%ju banned lookup", VXID(ObjGetXID(wrk, oc)));
716 1360
                return (1);
717
        }
718 154314
}
719
720
/*--------------------------------------------------------------------
721
 * CLI functions to add bans
722
 */
723
724
static void v_matchproto_(cli_func_t)
725 3680
ccf_ban(struct cli *cli, const char * const *av, void *priv)
726
{
727
        int narg, i;
728
        struct ban_proto *bp;
729 3680
        const char *err = NULL;
730
731 3680
        (void)priv;
732
733
        /* First do some cheap checks on the arguments */
734 16520
        for (narg = 0; av[narg + 2] != NULL; narg++)
735 12840
                continue;
736 3680
        if ((narg % 4) != 3) {
737 80
                VCLI_Out(cli, "Wrong number of arguments");
738 80
                VCLI_SetResult(cli, CLIS_PARAM);
739 80
                return;
740
        }
741 3960
        for (i = 3; i < narg; i += 4) {
742 400
                if (strcmp(av[i + 2], "&&")) {
743 40
                        VCLI_Out(cli, "Found \"%s\" expected &&", av[i + 2]);
744 40
                        VCLI_SetResult(cli, CLIS_PARAM);
745 40
                        return;
746
                }
747 360
        }
748
749 3560
        bp = BAN_Build();
750 3560
        if (bp == NULL) {
751 0
                VCLI_Out(cli, "Out of Memory");
752 0
                VCLI_SetResult(cli, CLIS_CANT);
753 0
                return;
754
        }
755 7200
        for (i = 0; i < narg; i += 4) {
756 3920
                err = BAN_AddTest(bp, av[i + 2], av[i + 3], av[i + 4]);
757 3920
                if (err)
758 280
                        break;
759 3640
        }
760
761 3560
        if (err == NULL) {
762
                // XXX racy - grab wstat lock?
763 3280
                err = BAN_Commit(bp);
764 3280
        }
765
766 3560
        if (err != NULL) {
767 280
                VCLI_Out(cli, "%s", err);
768 280
                BAN_Abandon(bp);
769 280
                VCLI_SetResult(cli, CLIS_PARAM);
770 280
        }
771 3680
}
772
773
#define Ms 60
774
#define Hs (Ms * 60)
775
#define Ds (Hs * 24)
776
#define Ws (Ds * 7)
777
#define Ys (Ds * 365)
778
779
#define Xfmt(buf, var, s, unit)                                         \
780
        ((var) >= s && (var) % s == 0)                                  \
781
                bprintf((buf), "%ju" unit, (var) / s)
782
783
// XXX move to VTIM?
784
#define vdur_render(buf, dur) do {                                      \
785
        uintmax_t dec = (uintmax_t)floor(dur);                          \
786
        uintmax_t frac = (uintmax_t)floor((dur) * 1e3) % UINTMAX_C(1000); \
787
        if (dec == 0 && frac == 0)                                      \
788
                (void) strncpy(buf, "0s", sizeof(buf));                 \
789
        else if (dec == 0)                                              \
790
                bprintf((buf), "%jums", frac);                          \
791
        else if (frac != 0)                                             \
792
                bprintf((buf), "%ju.%03jus", dec, frac);                \
793
        else if Xfmt(buf, dec, Ys, "y");                                \
794
        else if Xfmt(buf, dec, Ws, "w");                                \
795
        else if Xfmt(buf, dec, Ds, "d");                                \
796
        else if Xfmt(buf, dec, Hs, "h");                                \
797
        else if Xfmt(buf, dec, Ms, "m");                                \
798
        else                                                            \
799
                bprintf((buf), "%jus", dec);                            \
800
        } while (0)
801
802
static void
803 12960
ban_render(struct cli *cli, const uint8_t *bs, int quote)
804
{
805
        struct ban_test bt;
806
        const uint8_t *be;
807
        char buf[64];
808
809 12960
        be = bs + ban_len(bs);
810 12960
        bs += BANS_HEAD_LEN;
811 23320
        while (bs < be) {
812 10360
                ban_iter(&bs, &bt);
813 10360
                ASSERT_BAN_ARG(bt.arg1);
814 10360
                ASSERT_BAN_OPER(bt.oper);
815
816 10360
                if (BANS_HAS_ARG1_SPEC(bt.arg1))
817 4880
                        VCLI_Out(cli, "%s%.*s",
818 2440
                            arg_name[BAN_ARGIDX(bt.arg1)],
819 2440
                            bt.arg1_spec[0] - 1, bt.arg1_spec + 1);
820
                else
821 7920
                        VCLI_Out(cli, "%s", arg_name[BAN_ARGIDX(bt.arg1)]);
822
823 10360
                VCLI_Out(cli, " %s ", ban_oper[BAN_OPERIDX(bt.oper)]);
824
825 10360
                if (BANS_HAS_ARG2_DOUBLE(bt.arg1)) {
826 10440
                        vdur_render(buf, bt.arg2_double);
827 5400
                        VCLI_Out(cli, "%s", buf);
828 10360
                } else if (quote) {
829 520
                        VCLI_Quote(cli, bt.arg2);
830 520
                } else {
831 4440
                        VCLI_Out(cli, "%s", bt.arg2);
832
                }
833
834 10360
                if (bs < be)
835 1000
                        VCLI_Out(cli, " && ");
836
        }
837 12960
}
838
839
static void
840 2920
ban_list(struct cli *cli, struct ban *bl)
841
{
842
        struct ban *b;
843
        int64_t o;
844
845 2920
        VCLI_Out(cli, "Present bans:\n");
846 14880
        VTAILQ_FOREACH(b, &ban_head, list) {
847 11960
                o = bl == b ? 1 : 0;
848 23920
                VCLI_Out(cli, "%10.6f %5ju %s", ban_time(b->spec),
849 11960
                    (intmax_t)(b->refcount - o),
850 11960
                    b->flags & BANS_FLAG_COMPLETED ? "C" : "-");
851 11960
                if (DO_DEBUG(DBG_LURKER)) {
852 3760
                        VCLI_Out(cli, "%s%s %p ",
853 1880
                            b->flags & BANS_FLAG_REQ ? "R" : "-",
854 1880
                            b->flags & BANS_FLAG_OBJ ? "O" : "-",
855 1880
                            b);
856 1880
                }
857 11960
                VCLI_Out(cli, "  ");
858 11960
                ban_render(cli, b->spec, 0);
859 11960
                VCLI_Out(cli, "\n");
860 11960
                if (VCLI_Overflow(cli))
861 0
                        break;
862 11960
                if (DO_DEBUG(DBG_LURKER)) {
863 1880
                        Lck_Lock(&ban_mtx);
864
                        struct objcore *oc;
865 3160
                        VTAILQ_FOREACH(oc, &b->objcore, ban_list)
866 1280
                                VCLI_Out(cli, "  oc = %p\n", oc);
867 1880
                        Lck_Unlock(&ban_mtx);
868 1880
                }
869 11960
        }
870 2920
}
871
872
static void
873 240
ban_list_json(struct cli *cli, const char * const *av, struct ban *bl)
874
{
875
        struct ban *b;
876
        int64_t o;
877 240
        int n = 0;
878
        int ocs;
879
880 240
        VCLI_JSON_begin(cli, 2, av);
881 240
        VCLI_Out(cli, ",\n");
882 1240
        VTAILQ_FOREACH(b, &ban_head, list) {
883 1000
                o = bl == b ? 1 : 0;
884 1000
                VCLI_Out(cli, "%s", n ? ",\n" : "");
885 1000
                n++;
886 1000
                VCLI_Out(cli, "{\n");
887 1000
                VSB_indent(cli->sb, 2);
888 1000
                VCLI_Out(cli, "\"time\": %.6f,\n", ban_time(b->spec));
889 1000
                VCLI_Out(cli, "\"refs\": %ju,\n", (intmax_t)(b->refcount - o));
890 2000
                VCLI_Out(cli, "\"completed\": %s,\n",
891 1000
                         b->flags & BANS_FLAG_COMPLETED ? "true" : "false");
892 1000
                VCLI_Out(cli, "\"spec\": \"");
893 1000
                ban_render(cli, b->spec, 1);
894 1000
                VCLI_Out(cli, "\"");
895
896 1000
                if (DO_DEBUG(DBG_LURKER)) {
897 240
                        VCLI_Out(cli, ",\n");
898 480
                        VCLI_Out(cli, "\"req_tests\": %s,\n",
899 240
                                 b->flags & BANS_FLAG_REQ ? "true" : "false");
900 480
                        VCLI_Out(cli, "\"obj_tests\": %s,\n",
901 240
                                 b->flags & BANS_FLAG_OBJ ? "true" : "false");
902 240
                        VCLI_Out(cli, "\"pointer\": \"%p\",\n", b);
903 240
                        if (VCLI_Overflow(cli))
904 0
                                break;
905
906 240
                        ocs = 0;
907 240
                        VCLI_Out(cli, "\"objcores\": [\n");
908 240
                        VSB_indent(cli->sb, 2);
909 240
                        Lck_Lock(&ban_mtx);
910
                        struct objcore *oc;
911 240
                        VTAILQ_FOREACH(oc, &b->objcore, ban_list) {
912 0
                                if (ocs)
913 0
                                        VCLI_Out(cli, ",\n");
914 0
                                VCLI_Out(cli, "%p", oc);
915 0
                                ocs++;
916 0
                        }
917 240
                        Lck_Unlock(&ban_mtx);
918 240
                        VSB_indent(cli->sb, -2);
919 240
                        VCLI_Out(cli, "\n]");
920 240
                }
921 1000
                VSB_indent(cli->sb, -2);
922 1000
                VCLI_Out(cli, "\n}");
923 1000
        }
924 240
        VCLI_JSON_end(cli);
925 240
}
926
927
static void v_matchproto_(cli_func_t)
928 3160
ccf_ban_list(struct cli *cli, const char * const *av, void *priv)
929
{
930
        struct ban *bl;
931
932 3160
        (void)priv;
933
934
        /* Get a reference so we are safe to traverse the list */
935 3160
        Lck_Lock(&ban_mtx);
936 3160
        bl = VTAILQ_LAST(&ban_head, banhead_s);
937 3160
        bl->refcount++;
938 3160
        Lck_Unlock(&ban_mtx);
939
940 3160
        if (av[2] != NULL && strcmp(av[2], "-j") == 0)
941 240
                ban_list_json(cli, av, bl);
942
        else
943 2920
                ban_list(cli, bl);
944
945 3160
        Lck_Lock(&ban_mtx);
946 3160
        bl->refcount--;
947 3160
        ban_kick_lurker();      // XXX: Mostly for testcase b00009.vtc
948 3160
        Lck_Unlock(&ban_mtx);
949 3160
}
950
951
static struct cli_proto ban_cmds[] = {
952
        { CLICMD_BAN,                           "", ccf_ban },
953
        { CLICMD_BAN_LIST,                      "", ccf_ban_list,
954
          ccf_ban_list },
955
        { NULL }
956
};
957
958
/*--------------------------------------------------------------------
959
 */
960
961
void
962 37064
BAN_Compile(void)
963
{
964
        struct ban *b;
965
966
        /*
967
         * All bans have been read from all persistent stevedores. Export
968
         * the compiled list
969
         */
970
971 37064
        ASSERT_CLI();
972 37064
        AZ(ban_shutdown);
973
974 37064
        Lck_Lock(&ban_mtx);
975
976
        /* Report the place-holder ban */
977 37064
        b = VTAILQ_FIRST(&ban_head);
978 37064
        ban_info_new(b->spec, ban_len(b->spec));
979
980 37064
        ban_export();
981
982 37064
        Lck_Unlock(&ban_mtx);
983
984 37064
        ban_start = VTAILQ_FIRST(&ban_head);
985 37064
        BAN_Release();
986 37064
}
987
988
void
989 37144
BAN_Init(void)
990
{
991
        struct ban_proto *bp;
992
993 37144
        BAN_Build_Init();
994 37144
        Lck_New(&ban_mtx, lck_ban);
995 37144
        CLI_AddFuncs(ban_cmds);
996
997 37144
        ban_holds = 1;
998
999
        /* Add a placeholder ban */
1000 37144
        bp = BAN_Build();
1001 37144
        AN(bp);
1002 37144
        PTOK(pthread_cond_init(&ban_lurker_cond, NULL));
1003 37144
        AZ(BAN_Commit(bp));
1004 37144
        Lck_Lock(&ban_mtx);
1005 37144
        ban_mark_completed(VTAILQ_FIRST(&ban_head));
1006 37144
        Lck_Unlock(&ban_mtx);
1007 37144
}
1008
1009
/*--------------------------------------------------------------------
1010
 * Shutdown of the ban system.
1011
 *
1012
 * When this function returns, no new bans will be accepted, and no
1013
 * bans will be dropped (ban lurker thread stopped), so that no
1014
 * STV_BanInfo calls will be executed.
1015
 */
1016
1017
void
1018 36640
BAN_Shutdown(void)
1019
{
1020
        void *status;
1021
1022 36640
        Lck_Lock(&ban_mtx);
1023 36640
        ban_shutdown = 1;
1024 36640
        ban_kick_lurker();
1025 36640
        Lck_Unlock(&ban_mtx);
1026
1027 36640
        PTOK(pthread_join(ban_thread, &status));
1028 36640
        AZ(status);
1029
1030 36640
        Lck_Lock(&ban_mtx);
1031
        /* Export the ban list to compact it */
1032 36640
        ban_export();
1033 36640
        Lck_Unlock(&ban_mtx);
1034
1035 36640
        BAN_Build_Fini();
1036 36640
}