1 /*-
2  * Copyright (c) 2005 Andrey Simonenko
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 
29 #ifndef lint
30 static const char rcsid[] ATTR_UNUSED =
31   "@(#)$Id: ipastat_thresholds.c,v 1.2.2.1 2011/11/15 18:12:29 simon Exp $";
32 #endif /* !lint */
33 
34 #include <sys/types.h>
35 
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "ipa_mod.h"
41 
42 #include "queue.h"
43 
44 #include "dlapi.h"
45 #include "confcommon.h"
46 #include "memfunc.h"
47 
48 #include "ipastat_log.h"
49 #include "ipastat_main.h"
50 #include "ipastat_rules.h"
51 #include "ipastat_st.h"
52 
53 char		has_opt_thresholds = 0;	/* Set if -q ... -t ... */
54 
55 #ifdef WITH_THRESHOLDS
56 
57 signed char	dynamic_thresholds;	/* dynamic_thresholds parameter. */
58 
59 ipa_mzone	*threshold_mzone;	/* Mzone for struct threshold{}. */
60 
61 struct threshold *
alloc_threshold(void)62 alloc_threshold(void)
63 {
64 	struct threshold *threshold;
65 
66 	threshold = mzone_alloc(threshold_mzone);
67 	if (threshold == NULL) {
68 		xlogmsgx(IPA_LOG_ERR, "alloc_threshold: mzone_alloc failed");
69 		return (NULL);
70 	}
71 	threshold->info = NULL;
72 	threshold->st_list = NULL;
73 	threshold->inited = 0;
74 	return (threshold);
75 }
76 
77 /*
78  * Return pointer to threshold with the give name.
79  */
80 struct threshold *
threshold_by_name(const struct rule * rule,const char * name)81 threshold_by_name(const struct rule *rule, const char *name)
82 {
83 	struct threshold *threshold;
84 
85 	STAILQ_FOREACH(threshold, &rule->thresholds, link)
86 		if (strcmp(name, threshold->name) == 0)
87 			break;
88 	return (threshold);
89 }
90 
91 static void
get_min_max_no(const struct opt_thresholds * opt_thresholds,unsigned int * minno,unsigned int * maxno)92 get_min_max_no(	const struct opt_thresholds *opt_thresholds,
93     unsigned int *minno, unsigned int *maxno)
94 {
95 	const struct threshold *threshold;
96 	const struct opt_threshold *opt_threshold;
97 
98 	*minno = UINT_MAX;
99 	*maxno = 0;
100 	STAILQ_FOREACH(opt_threshold, opt_thresholds, link) {
101 		threshold = opt_threshold->threshold;
102 		if (*minno > threshold->no)
103 			*minno = threshold->no;
104 		if (*maxno < threshold->no)
105 			*maxno = threshold->no;
106 	}
107 }
108 
109 /*
110  * Initialize all thresholds from one rule in modules.
111  */
112 int
init_thresholds(const struct opt_rule * opt_rule)113 init_thresholds(const struct opt_rule *opt_rule)
114 {
115 	const struct rule *rule;
116 	const struct opt_threshold *opt_threshold;
117 	const struct opt_thresholds *opt_thresholds;
118 	struct threshold *threshold;
119 	unsigned int minno, maxno, no;
120 
121 	rule = opt_rule->rule;
122 	opt_thresholds = &opt_rule->opt_thresholds;
123 
124 	get_min_max_no(opt_thresholds, &minno, &maxno);
125 
126 	for (no = minno; no <= maxno; ++no)
127 		STAILQ_FOREACH(opt_threshold, opt_thresholds, link) {
128 			threshold = opt_threshold->threshold;
129 			if (threshold->no == no) {
130 				if (!threshold->inited) {
131 					threshold->inited = 1;
132 					if (st_init_threshold(rule,
133 					    threshold) < 0) {
134 						logbt("init_thresholds");
135 						return (-1);
136 					}
137 				}
138 				break;
139 			}
140 		}
141 
142 	return (0);
143 }
144 
145 int
deinit_thresholds(const struct opt_rule * opt_rule)146 deinit_thresholds(const struct opt_rule *opt_rule)
147 {
148 	const struct rule *rule;
149 	const struct opt_threshold *opt_threshold;
150 	const struct opt_thresholds *opt_thresholds;
151 	struct threshold *threshold;
152 	unsigned int minno, maxno, no;
153 	int rv;
154 
155 	rule = opt_rule->rule;
156 	opt_thresholds = &opt_rule->opt_thresholds;
157 
158 	get_min_max_no(opt_thresholds, &minno, &maxno);
159 
160 	rv = 0;
161 	for (no = minno; no <= maxno; ++no)
162 		STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link) {
163 			threshold = opt_threshold->threshold;
164 			if (threshold->no == no) {
165 				if (threshold->inited) {
166 					threshold->inited = 0;
167 					if (st_deinit_threshold(rule,
168 					    threshold) < 0) {
169 						logbt("deinit_thresholds");
170 						rv = -1;
171 					}
172 				}
173 				break;
174 			}
175 		}
176 
177 	return (rv);
178 }
179 
180 /*
181  * Copy all thresholds from list_src to rule.
182  */
183 int
copy_thresholds(struct rule * rule,const struct thresholds_list * list)184 copy_thresholds(struct rule *rule, const struct thresholds_list *list)
185 {
186 	const struct threshold *tsrc;
187 	struct threshold *tdst;
188 
189 	STAILQ_FOREACH(tsrc, list, link) {
190 		tdst = mzone_alloc(threshold_mzone);
191 		if (tdst == NULL) {
192 			xlogmsgx(IPA_LOG_ERR, "copy_thresholds: "
193 			    "mzone_alloc failed");
194 			return (-1);
195 		}
196 
197 		/* Copy settings from source threshold. */
198 		*tdst = *tsrc;
199 
200 		tdst->free_mask = 0;
201 
202 		/* Link just allocated threshold to rule. */
203 		STAILQ_INSERT_TAIL(&rule->thresholds, tdst, link);
204 	}
205 	return (0);
206 }
207 
208 /*
209  * Release memory used by a list of thresholds.
210  */
211 void
free_thresholds(struct thresholds_list * thresholds)212 free_thresholds(struct thresholds_list *thresholds)
213 {
214 	struct threshold *threshold, *threshold_next;
215 
216 	STAILQ_FOREACH_SAFE(threshold, thresholds, link, threshold_next) {
217 		if (threshold->free_mask & THRESHOLD_FREE_NAME)
218 			mem_free(threshold->name, m_anon);
219 		mem_free(threshold->info, m_result);
220 		mzone_free(threshold_mzone, threshold);
221 	}
222 }
223 
224 /*
225  * Add one optional threshold given in the -q -r option.
226  */
227 int
opt_threshold_add(const char * name)228 opt_threshold_add(const char *name)
229 {
230 	struct opt_threshold *opt_threshold;
231 
232 	opt_threshold = mem_malloc(sizeof(*opt_threshold), m_anon);
233 	if (opt_threshold == NULL) {
234 		logmsgx(IPA_LOG_ERR, "opt_threshold_add: mem_malloc failed");
235 		return (-1);
236 	}
237 
238 	opt_threshold->name = name;
239 	opt_threshold->opt_st = cur_opt_st;
240 
241 	cur_opt_rule->type = OPT_RULE_THRESHOLD;
242 
243 	STAILQ_INSERT_TAIL(&cur_opt_rule->opt_thresholds, opt_threshold, link);
244 
245 	has_opt_thresholds = 1;
246 	return (0);
247 }
248 
249 int
opt_thresholds_parse(const struct opt_rule * opt_rule)250 opt_thresholds_parse(const struct opt_rule *opt_rule)
251 {
252 	struct rule *rule;
253 	struct threshold *threshold;
254 	struct opt_threshold *opt_threshold;
255 	unsigned int thresholdno;
256 
257 	if (STAILQ_EMPTY(&opt_rule->opt_thresholds))
258 		return (0);
259 
260 	rule = opt_rule->rule;
261 	if (STAILQ_EMPTY(&rule->thresholds))
262 		thresholdno = 0;
263 	else {
264 		threshold = STAILQ_LAST(&rule->thresholds, threshold, link);
265 		thresholdno = threshold->no + 1;
266 	}
267 
268 	STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link) {
269 		threshold = threshold_by_name(rule, opt_threshold->name);
270 		if (threshold == NULL) {
271 			/*
272 			 * This threshold is not given in the configuration
273 			 * file.
274 			 */
275 			if (!dynamic_thresholds) {
276 				logmsgx(IPA_LOG_ERR, "opt_thresholds_parse: "
277 				    "unknown rule %s, threshold %s",
278 				    rule->name, opt_threshold->name);
279 				return (-1);
280 			}
281 			threshold = alloc_threshold();
282 			if (threshold == NULL) {
283 				logbt("opt_thresholds_parse");
284 				return (-1);
285 			}
286 			STAILQ_INSERT_TAIL(&rule->thresholds, threshold, link);
287 			threshold->no = thresholdno++;
288 			threshold->name = (char *)opt_threshold->name;
289 			threshold->free_mask = 0;
290 		}
291 		opt_threshold->threshold = threshold;
292 		if (opt_threshold->opt_st != NULL)
293 			threshold->st_list = opt_threshold->opt_st->st_list;
294 		if (threshold->st_list == NULL)
295 			threshold->st_list = rule->st_list;
296 	}
297 
298 	return (0);
299 }
300 
301 void
opt_thresholds_free(const struct opt_thresholds * opt_thresholds)302 opt_thresholds_free(const struct opt_thresholds *opt_thresholds)
303 {
304 	struct opt_threshold *opt_threshold, *opt_threshold_next;
305 
306 	STAILQ_FOREACH_SAFE(opt_threshold, opt_thresholds, link,
307 	    opt_threshold_next)
308 		mem_free(opt_threshold, m_anon);
309 }
310 #endif /* WITH_THRESHOLDS */
311