aboutsummaryrefslogtreecommitdiff
path: root/src/betab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/betab.c')
-rw-r--r--src/betab.c482
1 files changed, 294 insertions, 188 deletions
diff --git a/src/betab.c b/src/betab.c
index 49e02f7..388083b 100644
--- a/src/betab.c
+++ b/src/betab.c
@@ -1,3 +1,3 @@
/* This file is part of varnish-mib
- Copyright (C) 2014 Sergey Poznyakoff
+ Copyright (C) 2014, 2018 Sergey Poznyakoff
@@ -17,59 +17,22 @@
#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
};
@@ -77,3 +40,3 @@ struct betab_priv {
struct betab_trans {
- const char *name;
+ char const *param;
size_t off;
@@ -81,5 +44,8 @@ struct betab_trans {
-static struct betab_trans betab_trans[] = {
+/*
{ "vcls",
offsetof(struct backendTable_entry, vbeVcls) },
+*/
+
+static struct betab_trans betab_trans[] = {
{ "happy",
@@ -103,166 +69,306 @@ static struct betab_trans betab_trans[] = {
-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;
}

Return to:

Send suggestions and report system problems to the System administrator.