# This file is part of varnish-mib -*- c -*-
# Copyright (C) 2014-2015 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 .
# This macro inserts a comment instructing Emacs and vi that
# this file is read-only. It must be called at the end of the file.
@define ROCOM@
/* Local variables:
buffer-read-only: t
End:
vi: set ro:
*/
@enddefine@
@startperl@
$vars{'varnish_translate'} = sub {
my $name = shift;
my %trans = (
uptime => [ 'MAIN', 'uptime' ],
clientAcceptedConnections => [ 'MAIN', 'sess_conn' ],
clientRequestsReceived => [ 'MAIN', 'client_req' ],
clientCacheHits => [ 'MAIN', 'cache_hit' ],
clientCacheHitsPass => [ 'MAIN', 'cache_hitpass' ],
clientCacheMisses => [ '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' ],
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' ],
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' ],
sessAccepted => [ 'MAIN', 'sess_conn'],
sessQueued => [ 'MAIN', 'sess_queued'],
sessDropped => [ 'MAIN', 'sess_dropped'],
sessClosed => [ 'MAIN', 'sess_closed'],
sessPipeline => [ 'MAIN', 'sess_pipeline'],
sessReadAhead => [ 'MAIN', 'sess_readahead'],
sessHerd => [ 'MAIN', 'sess_herd'],
sessDrop => [ 'MAIN', 'sess_drop'],
sessFail => [ 'MAIN', 'sess_fail'],
sessPipeOverflow => [ 'MAIN', 'sess_pipe_overflow'],
threadsPools => [ 'MAIN', 'pools'],
threadsTotal => [ 'MAIN', 'threads'],
threadsLimitHits => [ 'MAIN', 'threads_limited'],
threadsCreated => [ 'MAIN', 'threads_created'],
threadsDestroyed => [ 'MAIN', 'threads_destroyed'],
threadsFailed => [ 'MAIN', 'threads_failed'],
threadsQueueLength => [ 'MAIN', 'thread_queue_len'],
bansTotal => [ 'MAIN', 'bans' ],
bansCompleted => [ 'MAIN', 'bans_completed' ],
bansObj => [ 'MAIN', 'bans_obj' ],
bansReq => [ 'MAIN', 'bans_req' ],
bansAdded => [ 'MAIN', 'bans_added' ],
bansDeleted => [ 'MAIN', 'bans_deleted' ],
bansTested => [ 'MAIN', 'bans_tested' ],
bansObjectsKilled => [ 'MAIN', 'bans_obj_killed' ],
bansLurkerTested => [ 'MAIN', 'bans_lurker_tested' ],
bansTestTested => [ 'MAIN', 'bans_tests_tested' ],
bansLurkerTestTested => [ 'MAIN', 'bans_lurker_tests_tested' ],
bansLurkerObjKilled => [ 'MAIN', 'bans_lurker_obj_killed' ],
bansDups => [ 'MAIN', 'bans_dups' ],
bansLurkerContention => [ 'MAIN', 'bans_lurker_contention' ],
bansPersistedBytes => [ 'MAIN', 'bans_persisted_bytes' ],
bansPersistedFragmentation => [ 'MAIN', 'bans_persisted_fragmentation' ],
);
my $r = $trans{$name};
if (!defined($r)) {
print STDERR "no translation for $name!\n";
exit(1);
}
$vars{'varnish_type'} = $r->[0];
$vars{'varnish_member'} = $r->[1];
if ($#{$r} == 2) {
@vars{keys %{$r->[2]}} = values %{$r->[2]};
} else {
delete $vars{$setkw};
}
return 0;
};
%field_dim_tab = (
vbeIPv4 => 4,
vbeIPv6 => 16
);
$vars{'set_field_dim'} = sub {
my $v = shift;
$vars{field_dim} = $field_dim_tab{$v};
return 0;
};
$vars{'modulename'} = $vars{'name'};
$vars{'modulename'} =~ s#.*/##;
$vars{'modulename'} =~ s/\.c$//;
#print "$vars{'modulename'}\n";
0;
@endperl@
@open ${modulename}.h@
/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct vcli_conn {
int fd;
char *secret;
int resp;
char *base;
size_t bufmax;
size_t bufsize;
} vcli_conn_t;
int vcli_write(vcli_conn_t *conn);
int vcli_read_response(vcli_conn_t *conn);
int vcli_vasprintf(vcli_conn_t *conn, const char *fmt, va_list ap);
int vcli_asprintf(vcli_conn_t *conn, const char *fmt, ...);
void vcli_disconnect(vcli_conn_t *conn);
int vcli_connect(struct VSM_data *vd, vcli_conn_t *conn);
struct VSM_data *varnish_get_vsm_data(void);
int varnish_auth_response(const char *file, const char *challenge,
char response[CLI_AUTH_RESPONSE_LEN + 1]);
int varnish_ban(netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests,
struct VSM_data *vd);
int varnish_mib_timeout_parser(const char *token, char *line,
unsigned *retval);
void varnish_ban_table_timeout_parser(const char *token, char *line);
void varnish_vcli_timeout_parser(const char *token, char *line);
void varnish_backend_table_timeout_parser(const char *token, char *line);
@open ${name}@
/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */
#include "varnish_mib.h"
static struct VSM_data *vd;
void
varnish_snmp_init(void)
{
vd = VSM_New();
}
void
varnish_snmp_deinit(void)
{
VSM_Close(vd);
}
struct VSM_data *
varnish_get_vsm_data()
{
if (VSM_Abandoned(vd)) {
DEBUGMSGTL(("$modulename", "reopening vd\n"));
VSM_Close(vd);
VSM_Open(vd);
}
return vd;
}
/* Variable handlers.
An instance handler only hands us one request at a time, unwrapping
any eventual GETNEXT requests.
*/
@foreach $i scalar@
static int
handle_$i(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
@if $i.settable@
int ret;
@end@
@startperl@
&{$vars{'varnish_translate'}}($vars{'i'});
@endperl@
if (!varnish_get_vsm_data())
return SNMP_ERR_NOSUCHNAME;
switch(reqinfo->mode) {
case MODE_GET:
@if $varnish_type eq 'MAIN'@
{
struct VSC_C_main const *st = VSC_Main(vd, NULL);
@if $i.type eq 'ASN_COUNTER64'@
struct counter64 ctr;
if (!st)
return SNMP_ERR_NOSUCHNAME;
ctr.high = st->$varnish_member >> 32;
ctr.low = st->$varnish_member & 0xffffffff;
snmp_set_var_typed_value(requests->requestvb, $i.type,
&ctr,
sizeof(ctr));
@else@
if (!st)
return SNMP_ERR_NOSUCHNAME;
snmp_set_var_typed_value(requests->requestvb, $i.type,
&st->$varnish_member,
sizeof(st->$varnish_member));
@end@
}
@elsif $varnish_type eq 'STRING'@
{
const char *s = "$varnish_member";
snmp_set_var_typed_value(requests->requestvb, $i.type,
s, strlen(s));
}
@elsif $varnish_type eq 'PROG'@
{
void *valptr;
size_t valsize;
if ($varnish_member(&valptr, &valsize))
return SNMP_ERR_NOSUCHNAME;
snmp_set_var_typed_value(requests->requestvb, $i.type,
valptr, valsize);
@if $varnish_get_free@
free(valptr);
@end@
@elsif $varnish_type eq 'VAR'@
@if $i.type eq 'ASN_OCTET_STR'@
snmp_set_var_typed_value(requests->requestvb, $i.type,
$varnish_member, strlen($varnish_member));
@else@
snmp_set_var_typed_value(requests->requestvb, $i.type,
&$varnish_member, sizeof($varnish_member));
@end@
@else@
@printf "unrecognized type %s for %s" $varnish_type $i@
@end@
break;
@if $i.settable@
/*
* SET REQUEST
*
* multiple states in the transaction. See:
* http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
*/
case MODE_SET_RESERVE1:
/* or you could use netsnmp_check_vb_type_and_size instead */
ret = netsnmp_check_vb_type(requests->requestvb, $i.type);
if (ret != SNMP_ERR_NOERROR)
netsnmp_set_request_error(reqinfo, requests, ret);
break;
case MODE_SET_RESERVE2:
@if $varnish_set_reserve2 ne ''@
if ($varnish_set_reserve2 (reqinfo, requests, vd)) {
netsnmp_set_request_error(reqinfo, requests,
SNMP_ERR_RESOURCEUNAVAILABLE);
}
@end@
break;
case MODE_SET_FREE:
@if $varnish_set_free ne ''@
# Free resources allocated in RESERVE1 and/or
# RESERVE2. Something failed somewhere, and the states
# below won't be called.
$varnish_set_free(reqinfo, requests, vd);
@end@
break;
case MODE_SET_ACTION:
@if $varnish_set_action ne ''@
ret = $varnish_set_action(reqinfo, requests, vd);
if (ret != SNMP_ERR_NOERROR)
netsnmp_set_request_error(reqinfo, requests, ret);
@end@
break;
case MODE_SET_COMMIT:
@if $varnish_set_commit ne ''@
# delete temporary storage
if ($varnish_set_commit(reqinfo, requests, vd))
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED);
@end@
break;
case MODE_SET_UNDO:
@if $varnish_set_undo ne ''@
# UNDO and return to previous value for the object
if ($varnish_set_undo(reqinfo, requests, vd))
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED);
@end@
break;
@end@
default:
/* we should never get here, so this is a really bad error */
snmp_log(LOG_ERR, "unknown mode (%d) in handle_${i}\n", reqinfo->mode );
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
@end@
@foreach $i table@
## Determine the first/last column names
@eval $first_column = "-"@
@eval $last_column = "-"@
@foreach $c column@
@if $c.readable@
@if "$first_column" eq "-"@
@eval $first_column = $c@
@end@
@eval $last_column = $c@
@end@
@end@
@push@
@append ${modulename}.h@
/* column number definitions for table $i */
@foreach $c column@
#define COLUMN_$c.uc $c.subid
@end@
struct ${i}_entry {
/* Index values */
@foreach $idx index@
@if $idx.needlength@
@startperl@
&{$vars{'set_field_dim'}}($vars{'idx'});
@endperl@
@if $field_dim > 0@
$idx.decl $idx[$field_dim];
@else@
$idx.decl *$idx;
@end@
size_t ${idx}_len;
@else@
$idx.decl $idx;
@end@
@end@
/* Column values */
@foreach $c nonindex@
@if $c.readable@
@if $c.needlength@
@startperl@
&{$vars{'set_field_dim'}}($vars{'c'});
@endperl@
@if $field_dim > 0@
$c.decl ${c}[$field_dim];
@else@
$c.decl *$c;
@end@
size_t ${c}_len;
@else@
$c.decl $c;
@end@
@end@
@end@
};
extern unsigned ${i}_timeout;
int ${i}_load(netsnmp_cache *cache, void *vmagic);
void ${i}_free(netsnmp_cache *cache, void *vmagic);
@pop@
/** handles requests for the $i table */
static int
handle_table_${i}(
netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct ${i}_entry *table_entry;
switch (reqinfo->mode) {
case MODE_GET:
for (request = requests; request; request = request->next) {
table_entry = (struct ${i}_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
@foreach $c column@
@if $c.readable@
case COLUMN_$c.uc:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
@if $c.needlength@
snmp_set_var_typed_value(request->requestvb, $c.type,
table_entry->$c,
table_entry->${c}_len);
@elsif $c.type eq 'ASN_COUNTER64'@@
snmp_set_var_typed_value(requests->requestvb, $c.type,
&table_entry->$c,
sizeof(table_entry->$c));
@else@
snmp_set_var_typed_integer(request->requestvb, $c.type,
table_entry->$c);
@end@
break;
@end@
@end@
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
}
}
break;
default:
/* we should never get here, so this is a really bad error */
snmp_log(LOG_ERR, "unknown mode (%d) in handle_table_${i}\n",
reqinfo->mode);
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/** Initialize the $i table by defining its contents and how it's structured */
static void
initialize_table_$i(void)
{
const oid ${i}_oid[] = {$i.commaoid};
const size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
netsnmp_handler_registration *reg;
netsnmp_tdata *table_data;
netsnmp_table_registration_info *table_info;
netsnmp_cache *cache;
DEBUGMSGTL(("${modulename}", "initializing table $i\n"));
reg = netsnmp_create_handler_registration("$i", handle_table_${i},
${i}_oid, ${i}_oid_len,
HANDLER_CAN_RONLY);
table_data = netsnmp_tdata_create_table("$i", 0);
if (!table_data) {
snmp_log(LOG_ERR,"error creating tdata table for $i\n");
return;
}
cache = netsnmp_cache_create(${i}_timeout,
${i}_load, ${i}_free,
${i}_oid, ${i}_oid_len);
if (!cache) {
snmp_log(LOG_ERR,"error creating cache for $i\n");
} else
cache->magic = (void *)table_data;
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
if (!table_info) {
snmp_log(LOG_ERR,"error creating table info for $i\n");
return;
}
netsnmp_table_helper_add_indexes(table_info,
@foreach $idx index@
$idx.type, /* index: $idx */
@end@
0);
table_info->min_column = COLUMN_$first_column.uc;
table_info->max_column = COLUMN_$last_column.uc;
netsnmp_tdata_register(reg, table_data, table_info);
if (cache)
netsnmp_inject_handler(reg, netsnmp_cache_handler_get(cache));
/*
netsnmp_inject_handler_before(reg, netsnmp_cache_handler_get(cache),
TABLE_TDATA_NAME);
*/
}
@end@
/** Initializes the $name module */
void
init_$modulename(void)
{
@foreach $i scalar@
const oid ${i}_oid[] = { $i.commaoid };
@end@
DEBUGMSGTL(("$modulename", "Initializing\n"));
if (!register_config_handler("snmpd", "varnishBanTableTimeout",
varnish_ban_table_timeout_parser,
NULL,
"varnishBanTableTimeout SECONDS"))
snmp_log(LOG_ERR,"can't register config handler\n");
if (!register_config_handler("snmpd", "varnishBackendTableTimeout",
varnish_backend_table_timeout_parser,
NULL,
"varnishBackendTableTimeout SECONDS"))
snmp_log(LOG_ERR,"can't register config handler\n");
if (!register_config_handler("snmpd", "varnishCLIPortTimeout",
varnish_vcli_timeout_parser,
NULL,
"varnishCLIPortTimeout SECONDS"))
snmp_log(LOG_ERR,"can't register config handler\n");
@foreach $i scalar@
netsnmp_register_scalar(
netsnmp_create_handler_registration("$i", handle_$i,
${i}_oid, OID_LENGTH(${i}_oid),
@if !$i.settable@
HANDLER_CAN_RONLY
@end@
@if $i.settable@
HANDLER_CAN_RWRITE
@end@
));
@end@
@foreach $i table@
initialize_table_$i();
@end@
varnish_snmp_init();
}
void
deinit_$modulename(void)
{
varnish_snmp_deinit();
}
@calldefine ROCOM@