/*-
* Copyright (c) 2005 Andrey Simonenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#ifndef lint
static const char rcsid[] ATTR_UNUSED =
"@(#)$Id: ipastat_st.c,v 1.1.4.2 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include "ipa_mod.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "parser.h"
#include "ipastat_log.h"
#include "ipastat_rules.h"
#include "ipastat_st.h"
#include "ipastat_main.h"
const struct st_list *global_st_list; /* global { st_list } */
int debug_st_null; /* debug_st_null parameter. */
/* Internal "null" statistics system. */
struct st_list st_list_null = STAILQ_HEAD_INITIALIZER(st_list_null);
/*
* st_sets is the list of all used "st_list" parameters.
*/
struct st_sets st_sets = SLIST_HEAD_INITIALIZER(st_sets);
/*
* List of all statistics modules.
*/
struct st_mod_list st_mod_list;
struct opt_st *cur_opt_st = NULL; /* Current optional statistics name. */
/*
* List of all opt_st structures.
*/
struct opt_st_list opt_st_list = STAILQ_HEAD_INITIALIZER(opt_st_list);
/*
* Find a statistics module by configuration prefix.
*/
struct st_mod *
st_mod_by_prefix(const char *prefix)
{
struct st_mod *st_mod;
SLIST_FOREACH(st_mod, &st_mod_list, link)
if (strcmp(st_mod->ipa_st_mod->conf_prefix, prefix) == 0)
break;
return st_mod;
}
/*
* Find a statistics module by a name.
*/
struct st_mod *
st_mod_by_name(const char *name)
{
struct st_mod *st_mod;
SLIST_FOREACH(st_mod, &st_mod_list, link)
if (strcmp(st_mod->ipa_st_mod->st_name, name) == 0)
return st_mod;
return NULL;
}
/*
* Release memory held by st_set, including struct st_set{}.
*/
static void
free_st_set(struct st_set *set)
{
struct st_elem *st, *st_next;
for (st = STAILQ_FIRST(&set->list); st != NULL; st = st_next) {
st_next = STAILQ_NEXT(st, link);
mem_free(st, m_anon);
}
mem_free(set, m_anon);
}
/*
* Release memory held by all st_set.
*/
void
free_st_lists(void)
{
struct st_set *set;
while ( (set = SLIST_FIRST(&st_sets)) != NULL) {
SLIST_REMOVE_HEAD(&st_sets, link);
free_st_set(set);
}
}
/*
* Pre-init all st_mods.
*/
int
pre_init_st_mods(void)
{
const struct st_mod *st_mod;
SLIST_FOREACH(st_mod, &st_mod_list, link)
if (st_mod->ipa_st_mod->st_pre_init() < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_pre_init failed", st_mod->mod_file);
return -1;
}
return 0;
}
/*
* Init all st_mods.
*/
int
init_st_mods(void)
{
const struct st_mod *st_mod;
SLIST_FOREACH(st_mod, &st_mod_list, link)
if (st_mod->ipa_st_mod->st_init() < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_init failed", st_mod->mod_file);
return -1;
}
return 0;
}
/*
* Deinit all st_mods.
*/
int
deinit_st_mods(void)
{
int error = 0;
const struct st_mod *st_mod;
SLIST_FOREACH(st_mod, &st_mod_list, link)
if (st_mod->ipa_st_mod->st_deinit() < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_deinit failed", st_mod->mod_file);
error = -1;
}
return error;
}
/*
* Init one rule in statistics systems.
*/
int
st_init_rule(const struct rule *rule)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(rule->st_list)) {
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_init_rule(rule->ruleno, rule->rule_name) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_init_rule(%s) failed",
st->mod_file, rule->rule_name);
return -1;
}
} else {
if (debug_st_null)
logmsgx(IPA_LOG_INFO, "rule %s: this rule uses builtin \"null\" statistics system",
rule->rule_name);
}
return 0;
}
/*
* Deinit one rule in statistics systems, which it uses.
*/
int
st_deinit_rule(const struct rule *rule)
{
int error = 0;
const struct st_elem *st;
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_deinit_rule(rule->ruleno) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_deinit_rule(%s) failed",
st->mod_file, rule->rule_name);
error = -1;
}
return error;
}
int
st_get_rules_list(const struct st_list *st_list, u_int *n,
struct ipa_entity_desc **bufp)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(st_list)) {
STAILQ_FOREACH(st, st_list, link)
if (st->ipa_st_mod->st_get_rules_list != NULL) {
if (st->ipa_st_mod->st_get_rules_list(
x_pat, x_reg_ptr, m_result, n, bufp) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_rules_list failed",
st->mod_file);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "st_get_rules_list: no statistics system is able to return rules list");
return -1;
}
/* "null" statistics system --> no records and always successful. */
*n = 0;
*bufp = NULL;
return 0;
}
int
st_get_rule_stat(const struct rule *rule, const ipa_tm *tm1, const ipa_tm *tm2,
int exact, u_int *n, struct ipa_rule_stat **bufp)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(rule->st_list)) {
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_get_rule_stat != NULL) {
if (st->ipa_st_mod->st_get_rule_stat(rule->ruleno,
tm1, tm2, exact, m_result, n, bufp) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_rule_stat(%s) failed",
st->mod_file, rule->rule_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s: st_get_rule_stat: no statistics system is able to return statistics for rule",
rule->rule_name);
return -1;
}
/* "null" statistics system --> no records and always successful. */
*n = 0;
*bufp = NULL;
return 0;
}
int
st_get_rule_info(const struct rule *rule, char **infop)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(rule->st_list)) {
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_get_rule_info != NULL) {
if (st->ipa_st_mod->st_get_rule_info(
rule->ruleno, m_result, infop) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_rule_info(%s) failed",
st->mod_file, rule->rule_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s: st_get_rule_info: no statistics system is able to return info for rule",
rule->rule_name);
return -1;
}
/* "null" statistics system --> no info. */
*infop = NULL;
return 0;
}
#ifdef WITH_LIMITS
/*
* Init one limit in statistics systems.
*/
int
st_init_limit(const struct rule *rule, const struct limit *limit)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(limit->st_list)) {
STAILQ_FOREACH(st, limit->st_list, link)
if (st->ipa_st_mod->st_init_limit(rule->ruleno, rule->rule_name,
limit->limitno, limit->limit_name) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_init_limit(%s, %s) failed",
st->mod_file, rule->rule_name, limit->limit_name);
return -1;
}
} else {
if (debug_st_null)
logmsgx(IPA_LOG_INFO, "rule %s, limit %s: this limit uses builtin \"null\" statistics system",
rule->rule_name, limit->limit_name);
}
return 0;
}
/*
* Deinit one limit in statistics systems, which it uses.
*/
int
st_deinit_limit(const struct rule *rule, const struct limit *limit)
{
int error = 0;
const struct st_elem *st;
STAILQ_FOREACH(st, limit->st_list, link)
if (st->ipa_st_mod->st_deinit_limit(rule->ruleno, limit->limitno) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_deinit_limit(%s, %s) failed",
st->mod_file, rule->rule_name, limit->limit_name);
error = -1;
}
return error;
}
int
st_get_limits_list(const struct rule *rule, u_int *n,
struct ipa_entity_desc **bufp)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(rule->st_list)) {
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_get_limits_list != NULL) {
if (st->ipa_st_mod->st_get_limits_list(
rule->ruleno, x_pat, x_reg_ptr, m_result,
n, bufp) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_limits_list(%s) failed",
st->mod_file, rule->rule_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s: st_get_limits_list: no statistics system is able to return list of limits",
rule->rule_name);
return -1;
}
/* "null" statistics system --> no records and always successful. */
*n = 0;
*bufp = NULL;
return 0;
}
int
st_get_limit_stat(const struct rule *rule, const struct limit *limit,
const ipa_tm *tm1, const ipa_tm *tm2, u_int *n,
struct ipa_limit_state **bufp)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(limit->st_list)) {
STAILQ_FOREACH(st, limit->st_list, link)
if (st->ipa_st_mod->st_get_limit_stat != NULL) {
if (st->ipa_st_mod->st_get_limit_stat(rule->ruleno,
limit->limitno, tm1, tm2, m_result,
n, bufp) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_limit_stat(%s, %s) failed",
st->mod_file, rule->rule_name, limit->limit_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s, limit %s: st_get_limit_stat: no statistics system is able to return statistics for limit",
rule->rule_name, limit->limit_name);
return -1;
}
/* "null" statistics system --> no records and always successful. */
*n = 0;
*bufp = NULL;
return 0;
}
int
st_get_limit_info(const struct rule *rule, const struct limit *limit,
char **infop)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(limit->st_list)) {
STAILQ_FOREACH(st, limit->st_list, link)
if (st->ipa_st_mod->st_get_limit_info != NULL) {
if (st->ipa_st_mod->st_get_limit_info(
rule->ruleno, limit->limitno, m_result,
infop) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_limit_info(%s, %s) failed",
st->mod_file, rule->rule_name, limit->limit_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s, limit %s: st_get_limit_info: no statistics system is able to return info for limit",
rule->rule_name, limit->limit_name);
return -1;
}
/* "null" statistics system --> no info. */
*infop = NULL;
return 0;
}
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
/*
* Init one threshold in statistics systems.
*/
int
st_init_threshold(const struct rule *rule, const struct threshold *threshold)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(threshold->st_list)) {
STAILQ_FOREACH(st, threshold->st_list, link)
if (st->ipa_st_mod->st_init_threshold(rule->ruleno, rule->rule_name,
threshold->thresholdno, threshold->threshold_name) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_init_threshold(%s, %s) failed",
st->mod_file, rule->rule_name, threshold->threshold_name);
return -1;
}
} else {
if (debug_st_null)
logmsgx(IPA_LOG_INFO, "rule %s, threshold %s: this threshold uses builtin \"null\" statistics system",
rule->rule_name, threshold->threshold_name);
}
return 0;
}
/*
* Deinit one threshold in statistics systems, which it uses.
*/
int
st_deinit_threshold(const struct rule *rule, const struct threshold *threshold)
{
int error = 0;
const struct st_elem *st;
STAILQ_FOREACH(st, threshold->st_list, link)
if (st->ipa_st_mod->st_deinit_threshold(rule->ruleno, threshold->thresholdno) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_deinit_threshold(%s, %s) failed",
st->mod_file, rule->rule_name, threshold->threshold_name);
error = -1;
}
return error;
}
int
st_get_thresholds_list(const struct rule *rule, u_int *n,
struct ipa_entity_desc **bufp)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(rule->st_list)) {
STAILQ_FOREACH(st, rule->st_list, link)
if (st->ipa_st_mod->st_get_thresholds_list != NULL) {
if (st->ipa_st_mod->st_get_thresholds_list(
rule->ruleno, x_pat, x_reg_ptr, m_result,
n, bufp) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_thresholds_list(%s) failed",
st->mod_file, rule->rule_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s: st_get_thresholds_list: no statistics system is able to return list of thresholds",
rule->rule_name);
return -1;
}
/* "null" statistics system --> no records and always successful. */
*n = 0;
*bufp = NULL;
return 0;
}
int
st_get_threshold_stat(const struct rule *rule, const struct threshold *threshold,
struct ipa_threshold_state *buf)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(threshold->st_list)) {
STAILQ_FOREACH(st, threshold->st_list, link)
if (st->ipa_st_mod->st_get_threshold_stat != NULL) {
if (st->ipa_st_mod->st_get_threshold_stat(rule->ruleno,
threshold->thresholdno, buf) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_threshold_stat(%s, %s) failed",
st->mod_file, rule->rule_name, threshold->threshold_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: st_get_threshold_stat: no statistics system is able to return statistics for threshold",
rule->rule_name, threshold->threshold_name);
return -1;
}
/* "null" statistics system --> no statistics for threshold. */
buf->thr = UINT64_C(0);
return 0;
}
int
st_get_threshold_info(const struct rule *rule, const struct threshold *threshold,
char **infop)
{
const struct st_elem *st;
if (!STAILQ_EMPTY(threshold->st_list)) {
STAILQ_FOREACH(st, threshold->st_list, link)
if (st->ipa_st_mod->st_get_threshold_info != NULL) {
if (st->ipa_st_mod->st_get_threshold_info(
rule->ruleno, threshold->thresholdno, m_result,
infop) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: st_get_threshold_info(%s, %s) failed",
st->mod_file, rule->rule_name, threshold->threshold_name);
return -1;
}
return 0;
}
logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: st_get_threshold_info: no statistics system is able to return info for threshold",
rule->rule_name, threshold->threshold_name);
return -1;
}
/* "null" statistics system --> no info. */
*infop = NULL;
return 0;
}
#endif /* WITH_THRESHOLDS */
/*
* Add optional statistics name: -q -s <name>
*/
int
add_opt_st(char *st_names)
{
struct opt_st *opt_st;
if (*st_names == '\0') {
cur_opt_st = NULL;
return 0;
}
if ( (opt_st = mem_malloc(sizeof *opt_st, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "add_opt_st: mem_malloc failed");
return -1;
}
opt_st->st_names = st_names;
STAILQ_INSERT_TAIL(&opt_st_list, opt_st, link);
cur_opt_st = opt_st;
return 0;
}
/*
* Parse names of statistics system given in command query.
*/
int
parse_opt_st_list(void)
{
char *ptr;
const char *st_name;
struct opt_st *opt_st;
struct st_set *set;
struct st_elem *st;
struct st_list *list;
const struct st_mod *st_mod;
STAILQ_FOREACH(opt_st, &opt_st_list, link) {
set = NULL;
list = NULL;
for (ptr = opt_st->st_names; ptr != NULL;) {
st_name = ptr;
if ( (ptr = strchr(ptr, ' ')) != NULL) {
*ptr++ = '\0';
for (; *ptr == ' '; ++ptr)
;
}
/* Handle "null" statistics system. */
if (strcmp(st_name, "null") == 0) {
if (list != NULL || ptr != NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_st_list: builtin statistics system \"null\" cannot be used together with another statistics systems");
return -1;
}
list = &st_list_null;
continue;
}
if ( (st_mod = st_mod_by_name(st_name)) == NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_st_list: cannot find module with \"%s\" statistics system name",
st_name);
return -1;
}
if (set != NULL) {
/* We already have set. */
STAILQ_FOREACH(st, list, link)
if (strcmp(st_name, st->ipa_st_mod->st_name) == 0) {
logmsgx(IPA_LOG_ERR, "parse_opt_st_list: duplicated statistics system name \"%s\"",
st_name);
return -1;
}
} else {
/* Create new set for st_list parameter. */
if ( (set = mem_malloc(sizeof *set, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_st_list: mem_malloc failed");
return -1;
}
list = &set->list;
STAILQ_INIT(list);
}
/* Add new st element to st_list. */
if ( (st = mem_malloc(sizeof *st, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_st_list: mem_malloc failed");
return -1;
}
st->ipa_st_mod = st_mod->ipa_st_mod;
st->mod_file = st_mod->mod_file;
STAILQ_INSERT_TAIL(list, st, link);
}
opt_st->st_list = list;
if (set != NULL)
SLIST_INSERT_HEAD(&st_sets, set, link);
}
return 0;
}
/*
* Release memory previously allocated by add_opt_st().
*/
void
free_opt_st_list(void)
{
struct opt_st *opt_st, *opt_st_next;
for (opt_st = STAILQ_FIRST(&opt_st_list); opt_st != NULL; opt_st = opt_st_next) {
opt_st_next = STAILQ_NEXT(opt_st, link);
mem_free(opt_st, m_anon);
}
}
syntax highlighted by Code2HTML, v. 0.9.1