27 #ifdef HAVE_COLLECTDC_H
28 #include <collectd/client.h>
29 #include <freeradius-devel/util/syserror.h>
55 static void _copy_double_to_double(
UNUSED rs_t *
conf, rs_stats_value_tmpl_t *tmpl)
60 *((
double *) tmpl->dst) = *((
double*) tmpl->src);
80 static rs_stats_tmpl_t *rs_stats_collectd_init(TALLOC_CTX *ctx,
rs_t *
conf,
81 char const *plugin_instance,
82 char const *
type,
char const *type_instance,
84 rs_stats_value_tmpl_t
const *values)
87 static char fqdn[LCC_NAME_LEN];
93 rs_stats_tmpl_t *tmpl;
94 lcc_value_list_t *
value;
98 assert(type_instance);
100 for (len = 0; values[len].src; len++) {} ;
108 struct addrinfo hints, *info = NULL;
116 memset(&hints, 0,
sizeof hints);
117 hints.ai_family = AF_UNSPEC;
118 hints.ai_socktype = SOCK_STREAM;
119 hints.ai_flags = AI_CANONNAME;
126 strlcpy(fqdn, info->ai_canonname,
sizeof(fqdn));
131 tmpl = talloc_zero(ctx, rs_stats_tmpl_t);
136 tmpl->value_tmpl = talloc_zero_array(tmpl, rs_stats_value_tmpl_t, len);
137 if (!tmpl->value_tmpl) {
143 value = talloc_zero(tmpl, lcc_value_list_t);
150 value->values_len = len;
152 value->values_types = talloc_zero_array(
value,
int, len);
153 if (!
value->values_types) {
157 value->values = talloc_zero_array(
value, value_t, len);
158 if (!
value->values) {
162 for (i = 0; i < (int) len; i++) {
163 assert(values[i].src);
164 assert(values[i].cb);
166 tmpl->value_tmpl[i] = values[i];
167 switch (tmpl->value_tmpl[i].type) {
168 case LCC_TYPE_COUNTER:
169 tmpl->value_tmpl[i].dst = &
value->values[i].counter;
173 tmpl->value_tmpl[i].dst = &
value->values[i].gauge;
176 case LCC_TYPE_DERIVE:
177 tmpl->value_tmpl[i].dst = &
value->values[i].derive;
180 case LCC_TYPE_ABSOLUTE:
181 tmpl->value_tmpl[i].dst = &
value->values[i].absolute;
187 value->values_types[i] = tmpl->value_tmpl[i].type;
200 for (p =
value->identifier.plugin; *p; ++p) {
201 if ((*p ==
'-') || (*p ==
'/'))*p =
'_';
208 plugin_instance, strlen(plugin_instance),
'\0');
209 for (p =
value->identifier.plugin_instance; *p; ++p) {
210 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
218 for (p =
value->identifier.type; *p; ++p) {
219 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
223 type_instance, strlen(type_instance),
'\0');
224 for (p =
value->identifier.type_instance; *p; ++p) {
225 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
240 rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **
out,
rs_t *
conf,
243 rs_stats_tmpl_t **tmpl =
out, *last;
245 char buffer[LCC_NAME_LEN];
250 rs_stats_value_tmpl_t
const _packet_count[] = {
251 { &
stats->interval.received, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
252 { &
stats->interval.linked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
253 { &
stats->interval.unlinked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
254 { &
stats->interval.reused, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
255 { NULL, 0, NULL, NULL }
258 rs_stats_value_tmpl_t
const _latency[] = {
259 { &
stats->latency_smoothed, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
260 { &
stats->interval.latency_average, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
261 { &
stats->interval.latency_high, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
262 { &
stats->interval.latency_low, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
263 { NULL, 0, NULL, NULL }
266 #define INIT_STATS(_ti, _v) do {\
267 strlcpy(buffer, fr_radius_packet_name[code], sizeof(buffer)); \
268 for (p = buffer; *p; ++p) *p = tolower((uint8_t) *p);\
269 last = *tmpl = rs_stats_collectd_init(ctx, conf, type, _ti, buffer, stats, _v);\
274 tmpl = &(*tmpl)->next;\
279 INIT_STATS(
"radius_count", _packet_count);
280 INIT_STATS(
"radius_latency", _latency);
283 rtx[i].src = &
stats->interval.rt[i];
284 rtx[i].type = LCC_TYPE_GAUGE;
285 rtx[i].cb = _copy_double_to_double;
290 rtx[i].type = LCC_TYPE_GAUGE;
291 rtx[i].cb = _copy_double_to_double;
294 memset(&rtx[++i], 0,
sizeof(rs_stats_value_tmpl_t));
296 INIT_STATS(
"radius_rtx", rtx);
304 void rs_stats_collectd_do_stats(
rs_t *
conf, rs_stats_tmpl_t *tmpls,
struct timeval *now)
306 rs_stats_tmpl_t *tmpl = tmpls;
307 char identifier[6 * LCC_NAME_LEN];
314 for (i = 0; i < (int) tmpl->value->values_len; i++) {
315 tmpl->value_tmpl[i].cb(
conf, &tmpl->value_tmpl[i]);
318 tmpl->value->time = now->tv_sec;
320 lcc_identifier_to_string(
conf->
stats.handle, identifier,
sizeof(identifier), &tmpl->value->identifier);
322 if (lcc_putval(
conf->
stats.handle, tmpl->value) < 0) {
325 error = lcc_strerror(
conf->
stats.handle);
326 ERROR(
"Failed PUTVAL \"%s\" interval=%i %" PRIu64
" : %s",
328 (
int) tmpl->value->interval,
329 (uint64_t) tmpl->value->time,
330 error ? error :
"unknown error");
344 int rs_stats_collectd_open(
rs_t *
conf)
351 rs_stats_collectd_close(
conf);
374 int rs_stats_collectd_close(
rs_t *
conf)
381 ret = lcc_disconnect(
conf->
stats.handle);
static int const char char buffer[256]
fr_radius_packet_code_t
RADIUS packet codes.
int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
void freeaddrinfo(struct addrinfo *ai)
char const * gai_strerror(int ecode)
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
uint64_t lost
Requests to which we received no response.
Structures and prototypes for the RADIUS sniffer.
#define RS_RETRANSMIT_MAX
Maximum number of times we expect to see a packet retransmitted.
Stats for a single interval.
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static size_t char ** out