/*- * 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 #include #include #include #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 */ 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); } }