aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@nxc.no>2018-02-01 15:16:07 +0100
committerSergey Poznyakoff <gray@nxc.no>2018-02-01 17:10:10 +0100
commit85f908426e444a596b979a9569bf83fadfa5ace1 (patch)
tree7513334ef43be06b45f39f13ef9b6a3bf37931d8
parent94973146c58df26b20e17e2e5b1274216ca88969 (diff)
downloadvarnish-mib-85f908426e444a596b979a9569bf83fadfa5ace1.tar.gz
varnish-mib-85f908426e444a596b979a9569bf83fadfa5ace1.tar.bz2
Rewrite for Varnish 5.x
* configure.ac (AC_CHECK_VSC_C_MAIN_MEMBERS): Remove. * src/.gitignore: Update. * src/Makefile.am (varnish_mib_la_SOURCES): Add new sources. * src/backend.h: New file. * src/belex.l: New file. * src/statdict.c: New file. * src/ban.c: Rewrite. * src/betab.c: Rewrite. * src/varnish_mib.mib2c: Rewrite. * src/vcli.c: Rewrite.
-rw-r--r--configure.ac5
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am3
-rw-r--r--src/backend.h16
-rw-r--r--src/ban.c15
-rw-r--r--src/belex.l178
-rw-r--r--src/betab.c482
-rw-r--r--src/statdict.c172
-rw-r--r--src/varnish_mib.mib2c227
-rw-r--r--src/vcli.c69
10 files changed, 830 insertions, 338 deletions
diff --git a/configure.ac b/configure.ac
index cf0bf05..c334724 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
# This file is part of Varnish-mib -*- autoconf -*-
-# Copyright (C) 2014-2016 Sergey Poznyakoff
+# Copyright (C) 2014-2018 Sergey Poznyakoff
#
# Varnish-mib is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@ if test "x$ac_cv_prog_cc_c99" = xno; then
AC_MSG_ERROR([could not find a C99 compatible compiler])
fi
AC_PROG_CPP
+AM_PROG_LEX
AC_PROG_INSTALL
AC_PROG_LIBTOOL
@@ -57,8 +58,6 @@ if test -n "$v"; then
IFS=$save_IFS
fi
-AC_CHECK_VSC_C_MAIN_MEMBERS
-
# Check for Net-SNMP
AC_PATH_PROG([NET_SNMP_CONFIG], net-snmp-config, none, $PATH)
if test "$NET_SNMP_CONFIG" = "none"; then
diff --git a/src/.gitignore b/src/.gitignore
index 61958b7..f40282a 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,2 +1,3 @@
varnish_mib.c
varnish_mib.h
+belex.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 48c786b..3a7f12a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,9 +20,12 @@ dlmod_LTLIBRARIES = varnish-mib.la
varnish_mib_la_SOURCES = \
auth.c\
ban.c\
+ backend.h\
+ belex.l\
betab.c\
sha256.c\
sha256.h\
+ statdict.c\
varnish_mib.c\
varnish_mib.h\
vcli.c
diff --git a/src/backend.h b/src/backend.h
new file mode 100644
index 0000000..0c15e60
--- /dev/null
+++ b/src/backend.h
@@ -0,0 +1,16 @@
+typedef struct be_string {
+ char const *start;
+ size_t len;
+} be_string_t;
+
+typedef void (*regfun_t)(be_string_t *, be_string_t *, be_string_t *, void *);
+
+void read_defs(const char *str, size_t len, regfun_t regfun, void *d);
+void varnish_backend_table_timeout_parser(const char *token, char *line);
+struct VSC_point;
+void backend_register(char const *name, size_t len, char const *param,
+ const struct VSC_point *vpt);
+void backend_clear(void);
+int backend_collect_addr(void);
+void backend_parser(const char *str, size_t len, regfun_t regfun, void *d);
+
diff --git a/src/ban.c b/src/ban.c
index 26dc5f4..0c354e9 100644
--- a/src/ban.c
+++ b/src/ban.c
@@ -38,7 +38,7 @@ send_ban_cmd(vcli_conn_t *conn, const char *expr)
int
varnish_ban(netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests,
- struct VSM_data *vd)
+ struct vsm *vsm)
{
int rc;
struct vcli_conn conn;
@@ -52,7 +52,7 @@ varnish_ban(netsnmp_agent_request_info *reqinfo,
memcpy(expr, requests->requestvb->val.string, len);
expr[len] = 0;
DEBUGMSGTL(("varnish_ban", "setting ban %s\n", expr));
- rc = vcli_connect(vd, &conn);
+ rc = vcli_connect(vsm, &conn);
if (rc == SNMP_ERR_NOERROR) {
rc = send_ban_cmd(&conn, expr);
vcli_disconnect(&conn);
@@ -151,13 +151,14 @@ banTable_load(netsnmp_cache *cache, void *vmagic)
int rc;
struct vcli_conn conn;
char *p;
- struct VSM_data *vd;
+
+ struct vsm *vsm = varnish_get_vsm_data();
+ if (!vsm)
+ return SNMP_ERR_GENERR;
DEBUGMSGTL(("varnish_ban", "reloading ban table\n"));
- vd = varnish_get_vsm_data();
- if (!vd)
- return SNMP_ERR_NOSUCHNAME;
- rc = vcli_connect(vd, &conn);
+ rc = vcli_connect(vsm, &conn);
+
if (rc != SNMP_ERR_NOERROR)
return rc;
diff --git a/src/belex.l b/src/belex.l
new file mode 100644
index 0000000..f35f114
--- /dev/null
+++ b/src/belex.l
@@ -0,0 +1,178 @@
+%option nounput
+%option noinput
+
+%{
+#include "backend.h"
+
+enum {
+ T_BOGUS = 256,
+ T_IDENT,
+ T_NUMBER,
+ T_STRING,
+ T_BACKEND,
+ T_HOST,
+ T_PORT
+};
+
+static char const *input_string;
+static size_t input_len;
+static size_t input_pos;
+static char const *string_start;
+static size_t current_pos;
+
+#define YY_INPUT(buf,result,max_size) \
+ do { \
+ size_t n = input_len - input_pos; \
+ if (n > max_size) \
+ n = max_size; \
+ memcpy(buf, input_string, n); \
+ input_pos += n; \
+ result = n; \
+ } while (0)
+
+#define YY_USER_ACTION \
+ current_pos += yyleng;
+
+#define YY_DECL static int yylex(void)
+static int yywrap(void);
+
+static char const *
+input_point(void)
+{
+ return input_string + current_pos;
+}
+
+#define YYSTYPE be_string_t
+#define YYSTYPE_INITIALIZER { NULL, 0 }
+
+static YYSTYPE yylval;
+%}
+
+%x COMMENT STR
+
+%%
+ /* C-style comments */
+"/*" BEGIN(COMMENT);
+<COMMENT>[^*]* /* eat anything that's not a '*' */
+<COMMENT>"*"+[^*/]* /* eat up '*'s not followed by '/'s */
+<COMMENT>"*"+"/" BEGIN(INITIAL);
+
+ /* Single-line comments */
+"//".*\n ;
+#.*\n ;
+
+ /* Multi-line strings */
+"{\"" { BEGIN(STR); string_start = input_point(); }
+<STR>[^\"]* /* eat anything that's not a '"' */
+<STR>"\""+[^"}]* /* eat up '"'s not followed by '}'s */
+<STR>"\""+"}" { BEGIN(INITIAL);
+ yylval.start = string_start;
+ yylval.len = input_point() - yylval.start - 2;
+ return T_STRING;
+ }
+ /* Single-line strings */
+\".*\" {
+ yylval.start = input_point() - yyleng + 1;
+ yylval.len = yyleng - 2;
+ return T_STRING;
+ }
+backend return T_BACKEND;
+".host" return T_HOST;
+".port" return T_PORT;
+"{"|"}"|"="|";" return yytext[0];
+
+[a-zA-Z_][a-zA-Z0-9_.]+ {
+ yylval.start = input_point() - yyleng;
+ yylval.len = yyleng;
+ return T_IDENT;
+ }
+[0-9]+ return T_NUMBER;
+
+[ \t\n]+ ;
+
+. return T_BOGUS;
+
+%%
+int
+yywrap(void)
+{
+ return 1;
+}
+
+static void
+set_input(char const *str, size_t len)
+{
+ input_string = str;
+ input_len = len;
+ input_pos = 0;
+ current_pos = 0;
+}
+
+static int brace_nesting;
+
+static void
+read_backend(regfun_t regfun, void *d)
+{
+ int c;
+ int in_statement;
+ YYSTYPE label, host = YYSTYPE_INITIALIZER, port = YYSTYPE_INITIALIZER;
+
+ if ((c = yylex()) != T_IDENT && c != T_STRING)
+ return;
+ label = yylval;
+ if ((c = yylex()) != '{')
+ return;
+ brace_nesting++;
+ in_statement = 0;
+ while (brace_nesting == 1) {
+ c = yylex();
+ if (c == 0)
+ break;
+ else if (c == '{')
+ brace_nesting++;
+ else if (c == '}')
+ brace_nesting++;
+ else if (in_statement) {
+ if (c == ';')
+ in_statement = 0;
+ } else {
+ in_statement = 1;
+ if (c == T_HOST || c == T_PORT) {
+ YYSTYPE *stk = c == T_HOST ? &host : &port;
+ in_statement = 1;
+ if ((c = yylex()) == '=') {
+ c = yylex();
+ if (c == T_STRING || c == T_IDENT) {
+ *stk = yylval;
+ }
+ }
+ }
+ }
+ }
+ regfun(&label, &host, &port, d);
+}
+
+void
+backend_parser(const char *str, size_t len, regfun_t regfun, void *d)
+{
+ int c;
+
+ set_input(str, len);
+
+ brace_nesting = 0;
+ while ((c = yylex())) {
+ if (brace_nesting == 0) {
+ if (c == T_BACKEND) {
+ read_backend(regfun, d);
+ }
+ }
+ switch (c) {
+ case '{':
+ brace_nesting++;
+ break;
+ case '}':
+ brace_nesting--;
+ break;
+ }
+ }
+}
diff --git a/src/betab.c b/src/betab.c
index 49e02f7..388083b 100644
--- a/src/betab.c
+++ b/src/betab.c
@@ -1,5 +1,5 @@
/* This file is part of varnish-mib
- Copyright (C) 2014 Sergey Poznyakoff
+ Copyright (C) 2014, 2018 Sergey Poznyakoff
Varnish-mib is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,73 +15,39 @@
along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
*/
#include "varnish_mib.h"
+#include <varnish/vas.h>
+#include <varnish/vqueue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
#include <arpa/inet.h>
+#include <netinet/in.h>
-unsigned backendTable_timeout = 5;
-
-void
-varnish_backend_table_timeout_parser(const char *token, char *line)
-{
- varnish_mib_timeout_parser(token, line, &backendTable_timeout);
-}
-
-/*
- * create a new row in the table
- */
-static struct backendTable_entry *
-create_entry(netsnmp_tdata *table_data, long idx,
- struct backendTable_entry *ent)
-{
- struct backendTable_entry *entry;
- netsnmp_tdata_row *row;
-
- entry = SNMP_MALLOC_TYPEDEF(struct backendTable_entry);
- if (!entry)
- return NULL;
-
- row = netsnmp_tdata_create_row();
- if (!row) {
- SNMP_FREE(entry);
- return NULL;
- }
- row->data = entry;
- *entry = *ent;
-
- entry->vbeIndex = idx;
- netsnmp_tdata_row_add_index(row, ASN_INTEGER,
- &entry->vbeIndex,
- sizeof(entry->vbeIndex));
- if (table_data)
- netsnmp_tdata_add_row(table_data, row);
- return entry;
-}
+#include "backend.h"
-#define VSC_POINT_TYPE(p) ((p)->section->fantom->type)
-#define VSC_POINT_IDENT(p) ((p)->section->fantom->ident)
-#define VSC_POINT_NAME(p) ((p)->desc->name)
-#if VARNISHAPI_MINOR == 0
-# define VSC_POINT_FMT(p) ((p)->desc->fmt)
-#elif VARNISHAPI_MINOR == 1
-# define VSC_POINT_FMT(p) ((p)->desc->ctype)
-#else
-# error "unsupported Varnish API minor number"
-#endif
-
-struct betab_priv {
- int err;
- long idx;
- struct backendTable_entry ent;
- netsnmp_tdata *table;
+enum {
+ vbeHappyProbes,
+ vbeRequestHeaderBytes,
+ vbeRequestBodyBytes,
+ vbeResponseHeaderBytes,
+ vbeResponseBodyBytes,
+ vbePipeHeaderBytes,
+ vbePipeIn,
+ vbePipeOut,
+ VBE_MAX
};
struct betab_trans {
- const char *name;
+ char const *param;
size_t off;
};
-static struct betab_trans betab_trans[] = {
+/*
{ "vcls",
offsetof(struct backendTable_entry, vbeVcls) },
+*/
+
+static struct betab_trans betab_trans[] = {
{ "happy",
offsetof(struct backendTable_entry, vbeHappyProbes) },
{ "bereq_hdrbytes",
@@ -101,168 +67,308 @@ static struct betab_trans betab_trans[] = {
{ NULL }
};
-static int
-identcmp(struct betab_priv *bp, const char *ident)
-{
- size_t len;
- size_t i;
+struct backend_dfn {
+ long vbeIndex;
+
+ char *vbeIdent;
+ size_t vbeIdent_len;
+
+ char vbeIPv4[4];
+ size_t vbeIPv4_len;
+ char vbeIPv6[16];
+ size_t vbeIPv6_len;
+ u_long vbePort;
- if (bp->idx == -1)
- return 1;
- for (i = 0; i < bp->ent.vbeIdent_len; i++, ident++)
- if (bp->ent.vbeIdent[i] != *ident)
- return 1;
- if (*ident == '(' || *ident == 0)
- return 0;
- return 1;
-}
+ const struct VSC_point *vpt[VBE_MAX];
+
+ VTAILQ_ENTRY(backend_dfn) list;
+};
-static void
-uint32_to_bytes (unsigned char *bytes, uint32_t u)
-{
- int i;
+static VTAILQ_HEAD(, backend_dfn) backends
+ = VTAILQ_HEAD_INITIALIZER(backends);
- for (i = 0; i < 4; i++)
- {
- bytes[i] = u & 0xff;
- u >>= 8;
- }
+void
+backend_clear(void)
+{
+ while (!VTAILQ_EMPTY(&backends)) {
+ struct backend_dfn *dfn = VTAILQ_FIRST(&backends);
+ VTAILQ_REMOVE(&backends, dfn, list);
+ free(dfn->vbeIdent);
+ SNMP_FREE(dfn);
+ }
}
-static void
-scanbuf(const char *s, struct backendTable_entry *ent)
+void
+backend_register(char const *name, size_t len, char const *param,
+ const struct VSC_point *vpt)
{
- char ipv4buf[16];
- char ipv6buf[81];
- unsigned long port;
- char *p;
- union {
- struct in_addr in;
- struct in6_addr in6;
- } v;
+ int i = 0;
+ struct backend_dfn *dfn;
- if (*s != '(')
- return;
- ++s;
- p = ipv4buf;
- while (p < ipv4buf + sizeof(ipv4buf) && *s && *s != ',')
- *p++ = *s++;
- if (*s != ',')
- return;
- *p = 0;
+ VTAILQ_FOREACH(dfn, &backends, list) {
+ if (dfn->vbeIdent_len == len
+ && memcmp(dfn->vbeIdent, name, len) == 0)
+ break;
+ i++;
+ }
+ if (!dfn) {
+ dfn = SNMP_MALLOC_TYPEDEF(struct backend_dfn);
+ AN(dfn);
+ dfn->vbeIndex = i;
+ dfn->vbeIdent = malloc(len + 1);
+ AN(dfn->vbeIdent);
+ memcpy(dfn->vbeIdent, name, len);
+ dfn->vbeIdent[len] = 0;
+ dfn->vbeIdent_len = len;
+ VTAILQ_INSERT_TAIL(&backends, dfn, list);
+ }
+ for (i = 0; betab_trans[i].param; i++) {
+ if (strcmp(betab_trans[i].param, param) == 0) {
+ dfn->vpt[i] = vpt;
+ break;
+ }
+ }
+}
- ++s;
- p = ipv6buf;
- while (p < ipv6buf + sizeof(ipv6buf) && *s && *s != ',')
- *p++ = *s++;
- *p = 0;
+int
+backendTable_load(netsnmp_cache *cache, void *vmagic)
+{
+ netsnmp_tdata *table_data = (netsnmp_tdata *) vmagic;
+ struct backend_dfn *dfn;
- ++s;
- port = strtoul(s, &p, 10);
- if (*p != ')' || port > USHRT_MAX)
- return;
+ DEBUGMSGTL(("varnish_backend", "loading backend table\n"));
+
+ VTAILQ_FOREACH(dfn, &backends, list) {
+ int i;
+
+ netsnmp_tdata_row *row;
+ struct backendTable_entry *ent;
+
+ ent = SNMP_MALLOC_TYPEDEF(struct backendTable_entry);
+ ent->vbeIndex = dfn->vbeIndex;
+ ent->vbeIdent = malloc(dfn->vbeIdent_len);
+ memcpy(ent->vbeIdent, dfn->vbeIdent, dfn->vbeIdent_len);
+ ent->vbeIdent_len = dfn->vbeIdent_len;
+ memset(ent->vbeIPv4, 0, sizeof ent->vbeIPv4);
+
+ memcpy(ent->vbeIPv4, dfn->vbeIPv4, dfn->vbeIPv4_len);
+ ent->vbeIPv4_len = dfn->vbeIPv4_len;
+ memcpy(ent->vbeIPv6, dfn->vbeIPv6, ent->vbeIPv6_len);
+ ent->vbeIPv6_len = dfn->vbeIPv6_len;
+ ent->vbePort = dfn->vbePort;
+
+ for (i = 0; i < VBE_MAX; i++) {
+ U64 *u = (U64*)((char*)ent + betab_trans[i].off);
+ uint64_t n = *(const volatile uint64_t*)dfn->vpt[i]->ptr;
+ u->high = n >> 32;
+ u->low = n & 0xffffffff;
+ }
+
+ row = netsnmp_tdata_create_row();
+ if (!row)
+ break;
+ row->data = ent;
+ netsnmp_tdata_row_add_index(row, ASN_INTEGER,
+ &ent->vbeIndex,
+ sizeof(ent->vbeIndex));
+ netsnmp_tdata_add_row(table_data, row);
+ }
+ return 0;
+}
+
+void
+backendTable_free(netsnmp_cache *cache, void *vmagic)
+{
+ netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
+ netsnmp_tdata_row *row;
- if (ipv4buf[0] && inet_pton(AF_INET, ipv4buf, &v)) {
- ent->vbeIPv4_len = 4;
- uint32_to_bytes(ent->vbeIPv4, v.in.s_addr);
+ DEBUGMSGTL(("varnish_backend", "freeing backend table\n"));
+ while ((row = netsnmp_tdata_row_first(table))) {
+ struct backendTable_entry *entry = row->data;
+ free(entry->vbeIdent);
+ SNMP_FREE(entry);
+ netsnmp_tdata_remove_and_delete_row(table, row);
}
+}
+
+unsigned backendTable_timeout = 5;
+
+void
+varnish_backend_table_timeout_parser(const char *token, char *line)
+{
+ varnish_mib_timeout_parser(token, line, &backendTable_timeout);
+}
+
+static struct backend_dfn *
+dfn_lookup(be_string_t *vclname, be_string_t *label)
+{
+ size_t namelen;
+ struct backend_dfn *dfn;
- if (ipv6buf[0] && inet_pton(AF_INET6, ipv6buf, &v)) {
- ent->vbeIPv6_len = 16;
- memcpy(ent->vbeIPv6, &v, ent->vbeIPv6_len);
+ namelen = vclname->len + label->len + 1;
+ VTAILQ_FOREACH(dfn, &backends, list) {
+ if (dfn->vbeIdent_len == namelen
+ && memcmp(dfn->vbeIdent, vclname->start, vclname->len) == 0
+ && dfn->vbeIdent[vclname->len] == '.'
+ && memcmp(dfn->vbeIdent + vclname->len + 1,
+ label->start, label->len) == 0)
+ return dfn;
}
- ent->vbePort = port;
-}
-
-/* Process a single statistics point. See comment below. */
-static int
-create_entry_cb(void *priv, const struct VSC_point *const pt)
+ return NULL;
+}
+
+static u_long
+to_port(be_string_t *str)
{
- struct betab_priv *bp = priv;
- struct betab_trans *tp;
-
- if (bp->err || !pt || strcmp(VSC_POINT_TYPE(pt), "VBE") ||
- strcmp(VSC_POINT_FMT(pt), "uint64_t"))
- return 0;
- if (identcmp(bp, VSC_POINT_IDENT(pt))) {
- const char *full_id;
-
- if (bp->idx != -1
- && !create_entry(bp->table, bp->idx, &bp->ent)) {
- snmp_log(LOG_ERR, "out of memory\n");
- bp->err = SNMP_ERR_GENERR;
+ int i;
+ u_long v = 0;
+ for (i = 0; i < str->len; i++) {
+ static char dig[] = "0123456789";
+ char *p = strchr(dig, str->start[i]);
+ if (!p)
return 0;
- }
+ v = v * 10 + p - dig;
+ }
+ return v;
+}
- memset(&bp->ent, 0, sizeof(bp->ent));
- bp->ent.vbeIndex = ++bp->idx;
+static void
+uint32_to_bytes (unsigned char *bytes, uint32_t u)
+{
+ int i;
- full_id = VSC_POINT_IDENT(pt);
- bp->ent.vbeIdent_len = strcspn(full_id, "(");
- bp->ent.vbeIdent = malloc(bp->ent.vbeIdent_len);
- if (!bp->ent.vbeIdent) {
- snmp_log(LOG_ERR, "out of memory\n");
- bp->err = SNMP_ERR_GENERR;
- return 0;
- }
- memcpy(bp->ent.vbeIdent, full_id, bp->ent.vbeIdent_len);
- full_id += bp->ent.vbeIdent_len;
- scanbuf(full_id, &bp->ent);
+ for (i = 0; i < 4; i++) {
+ bytes[i] = u & 0xff;
+ u >>= 8;
}
+}
- for (tp = betab_trans; tp->name; tp++) {
- if (strcmp(VSC_POINT_NAME(pt), tp->name) == 0) {
- U64 *u = (U64*)((char*)&bp->ent + tp->off);
- uint64_t n = *(const volatile uint64_t*)pt->ptr;
- u->high = n >> 32;
- u->low = n & 0xffffffff;
- break;
+static void
+update_dfn(be_string_t *label, be_string_t *host, be_string_t *port,
+ void *data)
+{
+ struct backend_dfn *dfn;
+
+ dfn = dfn_lookup(data, label);
+ if (!dfn)
+ return;
+ dfn->vbePort = to_port(port);
+ if (host->len) {
+ struct addrinfo *res, *ap;
+ int rc;
+ char *node;
+
+ node = malloc(host->len+1);
+ AN(node);
+ memcpy(node, host->start, host->len);
+ node[host->len] = 0;
+ rc = getaddrinfo(node, NULL, NULL, &res);
+ free(node);
+ if (rc)
+ return;
+ for (ap = res; ap; ap = ap->ai_next) {
+ if (ap->ai_addr->sa_family == AF_INET) {
+ if (dfn->vbeIPv4_len == 0) {
+ struct sockaddr_in *s =
+ (struct sockaddr_in *)ap->ai_addr;
+ uint32_to_bytes((unsigned char*)dfn->vbeIPv4,
+ s->sin_addr.s_addr);
+ dfn->vbeIPv4_len = 4;
+ }
+ } else if (ap->ai_addr->sa_family == AF_INET6) {
+ if (dfn->vbeIPv4_len == 0) {
+ struct sockaddr_in6 *s =
+ (struct sockaddr_in6 *)ap->ai_addr;
+ dfn->vbeIPv6_len = 16;
+ memcpy(dfn->vbeIPv6, &s->sin6_addr,
+ dfn->vbeIPv6_len);
+ }
+ }
}
+ freeaddrinfo(res);
}
- return 0;
}
-/* Varnish API does not provide access to struct VSC_C_vbe, so the only
- way to backend statistics is to iterate over all statistics data, selecting
- the entries marked as VBE. That's what this function does.
- */
-int
-backendTable_load(netsnmp_cache *cache, void *vmagic)
+static int
+backend_parse(struct vcli_conn *conn, be_string_t *name)
{
- struct betab_priv bp;
- struct VSM_data *vd = varnish_get_vsm_data();
+ if (vcli_asprintf(conn, "vcl.show %*.*s\n",
+ (int)name->len, (int)name->len,
+ name->start)
+ || vcli_write(conn))
+ return SNMP_ERR_GENERR;
- if (!vd)
- return SNMP_ERR_NOSUCHNAME;
+ if (vcli_read_response(conn))
+ return SNMP_ERR_GENERR;
- bp.idx = -1;
- bp.err = 0;
- bp.table = (netsnmp_tdata *) vmagic;
- memset(&bp.ent, 0, sizeof(bp.ent));
-
- DEBUGMSGTL(("varnish_ban", "loading backend table\n"));
- VSC_Iter(vd, NULL, create_entry_cb, &bp);
- /* FIXME: perhaps handle bp.err separately */
- if (bp.idx != -1) {
- DEBUGMSGTL(("varnish_ban", "loaded %lu backend entries\n",
- bp.idx + 1));
- if (!create_entry(bp.table, bp.idx, &bp.ent))
- snmp_log(LOG_ERR, "out of memory\n");
+ if (conn->resp != CLIS_OK) {
+ snmp_log(LOG_ERR, "vcl.show command rejected: %u %s\n",
+ conn->resp, conn->base);
+ return SNMP_ERR_GENERR;
}
+ backend_parser(conn->base, conn->bufsize, update_dfn, name);
return 0;
}
+
+struct backend_name {
+ be_string_t str;
+ VTAILQ_ENTRY(backend_name) list;
+};
+VTAILQ_HEAD(backend_name_list, backend_name);
-void
-backendTable_free(netsnmp_cache *cache, void *vmagic)
+static void
+backend_name_add(struct backend_name_list *namelist,
+ char const *str, size_t len)
{
- netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
- netsnmp_tdata_row *row;
+ struct backend_name *name;
+ VTAILQ_FOREACH(name, namelist, list) {
+ if (name->str.len == len
+ && memcmp(name->str.start, str, len) == 0)
+ return;
+ }
+ name = SNMP_MALLOC_TYPEDEF(struct backend_name);
+ AN(name);
+ name->str.start = str;
+ name->str.len = len;
+ VTAILQ_INSERT_TAIL(namelist, name, list);
+}
- DEBUGMSGTL(("varnish_ban", "freeing backend table\n"));
- while ((row = netsnmp_tdata_row_first(table))) {
- struct backendTable_entry *entry = row->data;
- free(entry->vbeIdent);
- SNMP_FREE(entry);
- netsnmp_tdata_remove_and_delete_row(table, row);
+int
+backend_collect_addr(void)
+{
+ struct backend_dfn *dfn;
+ struct vcli_conn conn;
+ struct vsm *vsm;
+ int rc;
+ struct backend_name_list namelist
+ = VTAILQ_HEAD_INITIALIZER(namelist);
+
+ vsm = varnish_get_vsm_data();
+ if (!vsm)
+ return SNMP_ERR_GENERR;
+ DEBUGMSGTL(("varnish_backend", "getting backend info\n"));
+
+ rc = vcli_connect(vsm, &conn);
+ if (rc != SNMP_ERR_NOERROR)
+ return rc;
+
+ /* Select backend names */
+ VTAILQ_FOREACH(dfn, &backends, list) {
+ int i;
+ for (i = 0; i < dfn->vbeIdent_len; i++)
+ if (dfn->vbeIdent[i] == '.')
+ break;
+ if (i == dfn->vbeIdent_len)
+ continue;
+ backend_name_add(&namelist, dfn->vbeIdent, i);
}
+
+ while (!VTAILQ_EMPTY(&namelist)) {
+ struct backend_name *name = VTAILQ_FIRST(&namelist);
+ VTAILQ_REMOVE(&namelist, name, list);
+ backend_parse(&conn, &name->str);
+ }
+
+ vcli_disconnect(&conn);
+ return 0;
}
diff --git a/src/statdict.c b/src/statdict.c
new file mode 100644
index 0000000..e87123b
--- /dev/null
+++ b/src/statdict.c
@@ -0,0 +1,172 @@
+/* This file is part of varnish-mib
+ Copyright (C) 2018 Sergey Poznyakoff
+
+ Varnish-mib is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Varnish-mib is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <vapi/vsc.h>
+#include <vapi/vsm.h>
+#include <vas.h>
+#include <vcli.h>
+#include "backend.h"
+
+static size_t hash_size[] = {
+ 7, 17, 37, 101, 229, 487, 1009, 2039, 4091, 8191, 16411
+};
+static size_t hash_num = 0;
+static struct VSC_point **dict;
+
+#define SIZE_T_MAX ((size_t)-1)
+
+static inline size_t
+rotl(size_t x, int n)
+{
+ return ((x << n) | (x >> ((CHAR_BIT * sizeof x) - n))) & SIZE_T_MAX;
+}
+
+static size_t
+hash(const char *str)
+{
+ size_t value = 0;
+ unsigned char ch;
+
+ while ((ch = *str++))
+ value = ch + rotl(value, 7);
+ return value % hash_size[hash_num];
+}
+
+struct VSC_point **lookup(const char *name, int install);
+
+static void
+rehash(void)
+{
+ struct VSC_point **old_dict = dict;
+ size_t old_size = hash_size[hash_num];
+ size_t i;
+
+ ++hash_num;
+ AN(hash_num < sizeof(hash_size) / sizeof(hash_size[0]));
+ dict = calloc(hash_size[hash_num], sizeof(dict[0]));
+ AN(dict);
+
+ for (i = 0; i < old_size; i++) {
+ if (old_dict[i])
+ *lookup(old_dict[i]->name, 1) = old_dict[i];
+ }
+ free(old_dict);
+}
+
+struct VSC_point **
+lookup(const char *name, int install)
+{
+ size_t i, pos;
+
+ if (!dict) {
+ if (install) {
+ dict = calloc(hash_size[hash_num], sizeof(dict[0]));
+ AN(dict);
+ } else
+ return NULL;
+ }
+
+ pos = hash(name);
+
+ for (i = pos; dict[i];) {
+ if (strcmp(dict[i]->name, name) == 0) {
+ return &dict[i];
+ }
+
+ if (++i >= hash_size[hash_num])
+ i = 0;
+ if (i == pos)
+ break;
+ }
+
+ if (!install)
+ return NULL;
+
+ if (!dict[i])
+ return &dict[i];
+
+ rehash();
+ return lookup(name, install);
+}
+
+int
+dict_lookup(char const *key, uint64_t *val)
+{
+ struct VSC_point **ent;
+
+ ent = lookup(key, 0);
+ if (!ent) {
+ fprintf(stderr, "%s NOT FOUND\n", key);
+ }
+ if (!ent)
+ return -1;
+ *val = *(uint64_t*)(*ent)->ptr;
+ return 0;
+}
+
+void
+dict_clear(void)
+{
+ if (dict) {
+ size_t i;
+ for (i = 0; i < hash_size[hash_num]; i++)
+ if (dict[i])
+ VSC_Destroy_Point(&dict[i]);
+ }
+}
+
+struct VSC_point const *
+dict_install(struct VSC_point const *pt)
+{
+ struct VSC_point **ent;
+
+ ent = lookup(pt->name, 1);
+ AN(ent);
+ if (*ent)
+ VSC_Destroy_Point(ent);
+ *ent = VSC_Clone_Point(pt);
+ return *ent;
+}
+
+static int
+load_cb(void *priv, const struct VSC_point *vpt)
+{
+ AZ(strcmp(vpt->ctype, "uint64_t"));
+ vpt = dict_install(vpt);
+ if (strncmp(vpt->name, "VBE.", 4) == 0) {
+ char const *name = vpt->name + 4;
+ char *p = strrchr(name, '.');
+ if (p) {
+ backend_register(name, p - name, p + 1, vpt);
+ }
+ }
+ return 0;
+}
+
+void
+dict_load(struct vsc *vsc)
+{
+ struct vsm_fantom fantom = VSM_FANTOM_NULL;
+ dict_clear();
+ backend_clear();
+ VSC_Iter(vsc, &fantom, load_cb, NULL);
+ backend_collect_addr();
+}
diff --git a/src/varnish_mib.mib2c b/src/varnish_mib.mib2c
index 9d49ce9..a458723 100644
--- a/src/varnish_mib.mib2c
+++ b/src/varnish_mib.mib2c
@@ -1,5 +1,5 @@
# This file is part of varnish-mib -*- c -*-
-# Copyright (C) 2014-2016 Sergey Poznyakoff
+# Copyright (C) 2014-2018 Sergey Poznyakoff
#
# Varnish-mib is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,80 +25,79 @@
@enddefine@
@startperl@
$vars{'varnish_translate_table'} = {
- uptime => [ 'MAIN', 'uptime' ],
- clientAcceptedConnections => [ 'MAIN', 'sess_conn' ],
- clientRequestsReceived => [ 'MAIN', 'client_req' ],
- clientCacheHits => [ 'MAIN', 'cache_hit' ],
- clientCacheHitsPass => [ 'MAIN', 'cache_hitpass' ],
- clientCacheMisses => [ 'MAIN', 'cache_miss' ],
+ uptime => [ 'DICT', 'MAIN.uptime' ],
+ clientAcceptedConnections => [ 'DICT', 'MAIN.sess_conn' ],
+ clientCacheHits => [ 'DICT', 'MAIN.cache_hit' ],
+ clientCacheHitsPass => [ 'DICT', 'MAIN.cache_hitpass' ],
+ clientCacheMisses => [ 'DICT', 'MAIN.cache_miss' ],
clientBan => [ 'STRING', '',
{ varnish_set_action => 'varnish_ban' } ],
- clientRequestsReceived => [ 'MAIN', 'client_req' ],
- clientRequests400 => [ 'MAIN', 'client_req_400' ],
- clientRequests411 => [ 'MAIN', 'client_req_411' ],
- clientRequests413 => [ 'MAIN', 'client_req_413' ],
- clientRequests417 => [ 'MAIN', 'client_req_417' ],
+ clientRequestsReceived => [ 'DICT', 'MAIN.client_req' ],
+ clientRequests400 => [ 'DICT', 'MAIN.client_req_400' ],
+ clientRequests411 => [ 'NULL', 'MAIN.client_req_411' ],
+ clientRequests413 => [ 'NULL', 'MAIN.client_req_413' ],
+ clientRequests417 => [ 'DICT', 'MAIN.client_req_417' ],
- backendConnSuccess => [ 'MAIN', 'backend_conn' ],
- backendConnNotAttempted => [ 'MAIN', 'backend_unhealthy' ],
- backendConnToMany => [ 'MAIN', 'backend_busy' ],
- backendConnFailures => [ 'MAIN', 'backend_fail' ],
- backendConnReuses => [ 'MAIN', 'backend_reuse' ],
- backendConnRecycled => [ 'MAIN', 'backend_recycle' ],
- backendConnUnused => [ 'MAIN', 'backend_toolate' ],
- backendConnRetry => [ 'MAIN', 'backend_retry' ],
- backendRequests => [ 'MAIN', 'backend_req' ],
+ backendConnSuccess => [ 'DICT', 'MAIN.backend_conn' ],
+ backendConnNotAttempted => [ 'DICT', 'MAIN.backend_unhealthy' ],
+ backendConnToMany => [ 'DICT', 'MAIN.backend_busy' ],
+ backendConnFailures => [ 'DICT', 'MAIN.backend_fail' ],
+ backendConnReuses => [ 'DICT', 'MAIN.backend_reuse' ],
+ backendConnRecycled => [ 'DICT', 'MAIN.backend_recycle' ],
+ backendConnUnused => [ 'NULL', 'MAIN.backend_toolate' ],
+ backendConnRetry => [ 'DICT', 'MAIN.backend_retry' ],
+ backendRequests => [ 'DICT', 'MAIN.backend_req' ],
- totalSessions => [ 'MAIN', 's_sess' ],
- totalRequests => [ 'MAIN', 's_req' ],
- totalPipe => [ 'MAIN', 's_pipe' ],
- totalPass => [ 'MAIN', 's_pass' ],
- totalFetch => [ 'MAIN', 's_fetch' ],
- totalRequestHeaderBytes => [ 'MAIN', 's_req_hdrbytes' ],
- totalRequestBodyBytes => [ 'MAIN', 's_req_bodybytes' ],
- totalResponseHeaderBytes => [ 'MAIN', 's_resp_hdrbytes' ],
- totalResponseBodyBytes => [ 'MAIN', 's_resp_bodybytes' ],
- totalPipeHeaderBytes => [ 'MAIN', 's_pipe_hdrbytes' ],
- totalPipeIn => [ 'MAIN', 's_pipe_in' ],
- totalPipeOut => [ 'MAIN', 's_pipe_out' ],
+ totalSessions => [ 'DICT', 'MAIN.s_sess' ],
+ totalRequests =>