[PATCH] Add softban support
Tollef Fog Heen
tfheen at varnish-software.com
Wed Oct 31 09:31:53 CET 2012
Soft bans are like normal bans, but they are subject to grace per
usual rules.
---
bin/varnishd/cache/cache.h | 1 +
bin/varnishd/cache/cache_ban.c | 58 +++++++++++++++++++++++++++++++++----
bin/varnishd/cache/cache_vrt.c | 6 ++--
bin/varnishtest/tests/s00004.vtc | 47 ++++++++++++++++++++++++++++++
bin/varnishtest/tests/s00005.vtc | 59 ++++++++++++++++++++++++++++++++++++++
include/vcli.h | 7 +++++
include/vrt.h | 4 +--
lib/libvcl/vcc_action.c | 25 ++++++++++++++--
8 files changed, 195 insertions(+), 12 deletions(-)
create mode 100644 bin/varnishtest/tests/s00004.vtc
create mode 100644 bin/varnishtest/tests/s00005.vtc
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 6d4fe86..66ee459 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -757,6 +757,7 @@ void BAN_Compile(void);
struct ban *BAN_RefBan(struct objcore *oc, double t0, const struct ban *tail);
void BAN_TailDeref(struct ban **ban);
double BAN_Time(const struct ban *ban);
+void BAN_Set_Soft(struct ban *b, int soft);
/* cache_busyobj.c */
void VBO_Init(void);
diff --git a/bin/varnishd/cache/cache_ban.c b/bin/varnishd/cache/cache_ban.c
index aa8bca9..6270a4a 100644
--- a/bin/varnishd/cache/cache_ban.c
+++ b/bin/varnishd/cache/cache_ban.c
@@ -42,6 +42,7 @@
* 8 bytes - double: timestamp XXX: Byteorder ?
* 4 bytes - be32: length
* 1 byte - flags: 0x01: BAN_F_REQ
+ * 0x02: BAN_F_SOFT
* N tests
* A test have this form:
* 1 byte - arg (see ban_vars.h col 3 "BAN_ARG_XXX")
@@ -82,6 +83,7 @@ struct ban {
unsigned flags;
#define BAN_F_GONE (1 << 0)
#define BAN_F_REQ (1 << 2)
+#define BAN_F_SOFT (1 << 3) /* soft ban, aka grace */
#define BAN_F_LURK (3 << 6) /* ban-lurker-color */
VTAILQ_HEAD(,objcore) objcore;
struct vsb *vsb;
@@ -392,7 +394,11 @@ BAN_Insert(struct ban *b)
t0 = VTIM_real();
memcpy(b->spec, &t0, sizeof t0);
- b->spec[12] = (b->flags & BAN_F_REQ) ? 1 : 0;
+ b->spec[12] = 0;
+ if (b->flags & BAN_F_REQ)
+ b->spec[12] |= 0x1;
+ if (b->flags & BAN_F_SOFT)
+ b->spec[12] |= 0x2;
memcpy(b->spec + 13, VSB_data(b->vsb), ln);
ln += 13;
vbe32enc(b->spec + 8, ln);
@@ -551,8 +557,10 @@ BAN_Reload(const uint8_t *ban, unsigned len)
AN(b2->spec);
memcpy(b2->spec, ban, len);
b2->flags |= gone;
- if (ban[12])
+ if (ban[12] & 0x01)
b2->flags |= BAN_F_REQ;
+ if (ban[12] & 0x02)
+ b2->flags |= BAN_F_SOFT;
if (b == NULL)
VTAILQ_INSERT_TAIL(&ban_head, b2, list);
else
@@ -587,6 +595,21 @@ BAN_Time(const struct ban *b)
}
/*--------------------------------------------------------------------
+ * Set/unset the soft flag on a ban
+ */
+
+void
+BAN_Set_Soft(struct ban *b, int soft)
+{
+
+ CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+ if (soft)
+ b->flags |= BAN_F_SOFT;
+ else
+ b->flags &= ~BAN_F_SOFT;
+}
+
+/*--------------------------------------------------------------------
* All silos have read their bans, ready for action
*/
@@ -687,7 +710,8 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
struct ban *b;
struct objcore *oc;
struct ban * volatile b0;
- unsigned tests, skipped;
+ unsigned tests, skipped, soft;
+ double now;
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
CHECK_OBJ_ORNULL(req_http, HTTP_MAGIC);
@@ -708,6 +732,7 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
*/
tests = 0;
skipped = 0;
+ soft = 0;
for (b = b0; b != oc->ban; b = VTAILQ_NEXT(b, list)) {
CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
if (b->flags & BAN_F_GONE)
@@ -724,15 +749,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
* be other bans that match, so we soldier on
*/
skipped++;
- } else if (ban_evaluate(b->spec, o->http, req_http, &tests))
+ } else if (ban_evaluate(b->spec, o->http, req_http, &tests)) {
+ if (b->flags & BAN_F_SOFT) {
+ soft = 1;
+ continue;
+ }
+ soft = 0; /* Found hard ban */
break;
+ }
}
Lck_Lock(&ban_mtx);
VSC_C_main->bans_tested++;
VSC_C_main->bans_tests_tested += tests;
- if (b == oc->ban && skipped > 0) {
+ if (b == oc->ban && skipped > 0 && soft == 0) {
AZ(req_http);
Lck_Unlock(&ban_mtx);
/*
@@ -751,10 +782,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
}
Lck_Unlock(&ban_mtx);
- if (b == oc->ban) { /* not banned */
+ if (soft == 0 && b == oc->ban) { /* not banned */
oc->ban = b0;
oc_updatemeta(oc);
return (0);
+ } else if (soft) {
+ now = VTIM_real();
+ /* Softban, set ttl to now */
+ if (o->exp.entered + o->exp.ttl > now)
+ o->exp.ttl = now - o->exp.entered;
+ oc->ban = b0;
+ oc_updatemeta(oc);
+ /* XXX: no req in lurker */
+ VSLb(vsl, SLT_ExpBan, "%u was softbanned", o->vxid);
+ EXP_Rearm(o);
+ return (2);
} else {
EXP_Clr(&o->exp);
oc->ban = NULL;
@@ -1026,6 +1068,9 @@ ccf_ban(struct cli *cli, const char * const *av, void *priv)
VCLI_SetResult(cli, CLIS_CANT);
return;
}
+ if (strcmp(av[1], "softban") == 0) {
+ b->flags |= BAN_F_SOFT;
+ }
for (i = 0; i < narg; i += 4)
if (BAN_AddTest(cli, b, av[i + 2], av[i + 3], av[i + 4])) {
BAN_Free(b);
@@ -1125,6 +1170,7 @@ ccf_ban_list(struct cli *cli, const char * const *av, void *priv)
static struct cli_proto ban_cmds[] = {
{ CLI_BAN_URL, "", ccf_ban_url },
{ CLI_BAN, "", ccf_ban },
+ { CLI_SOFTBAN, "", ccf_ban },
{ CLI_BAN_LIST, "", ccf_ban_list },
{ NULL }
};
diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index ed7ae59..70537fc 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -433,7 +433,7 @@ VRT_synth_page(const struct req *req, unsigned flags, const char *str, ...)
/*--------------------------------------------------------------------*/
void
-VRT_ban(const struct req *req, char *cmds, ...)
+VRT_ban(const struct req *req, int soft, char *cmds, ...)
{
char *a1, *a2, *a3;
va_list ap;
@@ -442,6 +442,7 @@ VRT_ban(const struct req *req, char *cmds, ...)
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
b = BAN_New();
+ BAN_Set_Soft(b, soft);
va_start(ap, cmds);
a1 = cmds;
good = 0;
@@ -468,7 +469,7 @@ VRT_ban(const struct req *req, char *cmds, ...)
/*--------------------------------------------------------------------*/
void
-VRT_ban_string(const struct req *req, const char *str)
+VRT_ban_string(const struct req *req, int soft, const char *str)
{
char *a1, *a2, *a3;
char **av;
@@ -484,6 +485,7 @@ VRT_ban_string(const struct req *req, const char *str)
return;
}
b = BAN_New();
+ BAN_Set_Soft(b, soft);
good = 0;
for (i = 1; ;) {
a1 = av[i++];
diff --git a/bin/varnishtest/tests/s00004.vtc b/bin/varnishtest/tests/s00004.vtc
new file mode 100644
index 0000000..781d1dc
--- /dev/null
+++ b/bin/varnishtest/tests/s00004.vtc
@@ -0,0 +1,47 @@
+varnishtest "Softbans from CLI"
+
+server s1 {
+ rxreq
+ txresp
+
+ sema r1 sync 3
+
+ rxreq
+ txresp
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_hit {
+ if (obj.ttl <= 0s) {
+ set req.http.grace = "t";
+ }
+ }
+ sub vcl_fetch {
+ set beresp.ttl = 1m;
+ set beresp.grace = 1m;
+ }
+ sub vcl_deliver {
+ set resp.http.grace = req.http.grace;
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ delay 1
+ txreq
+ sema r1 sync 3
+ rxresp
+} -start
+
+varnish v1 -cliok "softban req.url ~ ^"
+delay 1;
+
+client c2 {
+ sema r1 sync 3
+ txreq
+ rxresp
+ expect resp.http.grace == "t"
+ expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/s00005.vtc b/bin/varnishtest/tests/s00005.vtc
new file mode 100644
index 0000000..35d1a8a
--- /dev/null
+++ b/bin/varnishtest/tests/s00005.vtc
@@ -0,0 +1,59 @@
+varnishtest "Softbans from VCL"
+
+server s1 {
+ rxreq
+ txresp
+
+ sema r1 sync 3
+
+ rxreq
+ txresp
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_recv {
+ if (req.request == "SOFTBAN") {
+ softban("req.url ~ " + req.url);
+ error 410;
+ }
+ }
+
+ sub vcl_hit {
+ if (obj.ttl <= 0s) {
+ set req.http.grace = "t";
+ }
+ }
+ sub vcl_fetch {
+ set beresp.ttl = 1m;
+ set beresp.grace = 1m;
+ }
+ sub vcl_deliver {
+ set resp.http.grace = req.http.grace;
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ delay 1
+ txreq
+ sema r1 sync 3
+ rxresp
+} -start
+
+delay 1
+client c2 {
+ txreq -req SOFTBAN -url /
+ rxresp
+ expect resp.status == 410
+} -run
+
+
+client c3 {
+ sema r1 sync 3
+ txreq
+ rxresp
+ expect resp.http.grace == "t"
+ expect resp.status == 200
+} -run
diff --git a/include/vcli.h b/include/vcli.h
index 04ac11c..3d79e7b 100644
--- a/include/vcli.h
+++ b/include/vcli.h
@@ -78,6 +78,13 @@
"\tList the active bans.", \
0, 0
+#define CLI_SOFTBAN \
+ "softban", \
+ "softban <field> <operator> <arg> [&& <field> <oper> <arg>]...", \
+ "\tAll objects where the all the conditions match will be " \
+ "marked obsolete, but still eligible for grace.", \
+ 3, UINT_MAX
+
#define CLI_VCL_LOAD \
"vcl.load", \
"vcl.load <configname> <filename>", \
diff --git a/include/vrt.h b/include/vrt.h
index c98e085..bb21f93 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -177,8 +177,8 @@ int VRT_re_match(struct req *, const char *, void *re);
const char *VRT_regsub(struct req *, int all, const char *,
void *, const char *);
-void VRT_ban(const struct req *, char *, ...);
-void VRT_ban_string(const struct req *, const char *);
+void VRT_ban(const struct req *, int, char *, ...);
+void VRT_ban_string(const struct req *, int, const char *);
void VRT_purge(struct req *, double ttl, double grace);
void VRT_count(struct req *, unsigned);
diff --git a/lib/libvcl/vcc_action.c b/lib/libvcl/vcc_action.c
index eae6231..3662a39 100644
--- a/lib/libvcl/vcc_action.c
+++ b/lib/libvcl/vcc_action.c
@@ -183,7 +183,7 @@ parse_ban(struct vcc *tl)
ExpectErr(tl, '(');
vcc_NextToken(tl);
- Fb(tl, 1, "VRT_ban_string(req, ");
+ Fb(tl, 1, "VRT_ban_string(req, 0, ");
vcc_Expr(tl, STRING);
ERRCHK(tl);
Fb(tl, 0, ");\n");
@@ -202,7 +202,7 @@ parse_ban_url(struct vcc *tl)
ExpectErr(tl, '(');
vcc_NextToken(tl);
- Fb(tl, 1, "VRT_ban(req, \"req.url\", \"~\", ");
+ Fb(tl, 1, "VRT_ban(req, 0, \"req.url\", \"~\", ");
vcc_Expr(tl, STRING);
ERRCHK(tl);
ExpectErr(tl, ')');
@@ -213,6 +213,26 @@ parse_ban_url(struct vcc *tl)
/*--------------------------------------------------------------------*/
static void
+parse_softban(struct vcc *tl)
+{
+
+ vcc_NextToken(tl);
+
+ ExpectErr(tl, '(');
+ vcc_NextToken(tl);
+
+ Fb(tl, 1, "VRT_ban_string(req, 1, ");
+ vcc_Expr(tl, STRING);
+ ERRCHK(tl);
+ Fb(tl, 0, ");\n");
+
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
parse_new_syntax(struct vcc *tl)
{
@@ -325,6 +345,7 @@ static struct action_table {
{ "hash_data", parse_hash_data, VCL_MET_HASH },
{ "ban", parse_ban },
{ "ban_url", parse_ban_url },
+ { "softban", parse_softban },
{ "remove", parse_unset }, /* backward compatibility */
{ "return", parse_return },
{ "rollback", parse_rollback },
--
1.7.10.4
More information about the varnish-dev
mailing list