2 * Copyright (C) 2017 Tobias Brunner
3 * Copyright (C) 2012 Martin Willi
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "counters_listener.h"
19 #include "counters_query.h"
21 #include <threading/spinlock.h>
22 #include <collections/hashtable.h>
23 #include <collections/array.h>
25 typedef struct private_counters_listener_t private_counters_listener_t
;
26 typedef struct private_counters_query_t private_counters_query_t
;
31 struct private_counters_query_t
{
36 counters_query_t
public;
41 private_counters_listener_t
*this;
47 struct private_counters_listener_t
{
52 counters_listener_t
public;
57 private_counters_query_t query
;
60 * Global counter values
62 uint64_t counters
[COUNTER_MAX
];
65 * Counters for specific connection names, char* => entry_t
70 * Lock for counter values
76 * Counters for a specific connection name
79 /** connection name */
81 /** counter values for connection */
82 uint64_t counters
[COUNTER_MAX
];
88 static void destroy_entry(entry_t
*this)
95 * Hashtable hash function
97 static u_int
hash(char *name
)
99 return chunk_hash(chunk_from_str(name
));
103 * Hashtable equals function
105 static bool equals(char *a
, char *b
)
111 * Get the name of an IKE_SA, but return NULL if it is not known yet
113 static char *get_ike_sa_name(ike_sa_t
*ike_sa
)
115 peer_cfg_t
*peer_cfg
;
119 peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
122 return peer_cfg
->get_name(peer_cfg
);
129 * Increase a counter for a named entry
131 static void count_named(private_counters_listener_t
*this,
132 ike_sa_t
*ike_sa
, counter_type_t type
)
137 name
= get_ike_sa_name(ike_sa
);
140 entry
= this->conns
->get(this->conns
, name
);
144 .name
= strdup(name
),
146 this->conns
->put(this->conns
, entry
->name
, entry
);
148 entry
->counters
[type
]++;
152 METHOD(listener_t
, alert
, bool,
153 private_counters_listener_t
*this, ike_sa_t
*ike_sa
,
154 alert_t alert
, va_list args
)
160 case ALERT_INVALID_IKE_SPI
:
161 type
= COUNTER_IN_INVALID_IKE_SPI
;
163 case ALERT_PARSE_ERROR_HEADER
:
164 case ALERT_PARSE_ERROR_BODY
:
165 type
= COUNTER_IN_INVALID
;
171 this->lock
->lock(this->lock
);
172 this->counters
[type
]++;
173 count_named(this, ike_sa
, type
);
174 this->lock
->unlock(this->lock
);
179 METHOD(listener_t
, ike_rekey
, bool,
180 private_counters_listener_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
185 id
= new->get_id(new);
186 if (id
->is_initiator(id
))
188 type
= COUNTER_INIT_IKE_SA_REKEY
;
192 type
= COUNTER_RESP_IKE_SA_REKEY
;
195 this->lock
->lock(this->lock
);
196 this->counters
[type
]++;
197 count_named(this, old
, type
);
198 this->lock
->unlock(this->lock
);
203 METHOD(listener_t
, child_rekey
, bool,
204 private_counters_listener_t
*this, ike_sa_t
*ike_sa
,
205 child_sa_t
*old
, child_sa_t
*new)
207 this->lock
->lock(this->lock
);
208 this->counters
[COUNTER_CHILD_SA_REKEY
]++;
209 count_named(this, ike_sa
, COUNTER_CHILD_SA_REKEY
);
210 this->lock
->unlock(this->lock
);
215 METHOD(listener_t
, message_hook
, bool,
216 private_counters_listener_t
*this, ike_sa_t
*ike_sa
, message_t
*message
,
217 bool incoming
, bool plain
)
222 if ((incoming
&& !plain
) || (!incoming
&& !plain
))
223 { /* handle each message only once */
227 request
= message
->get_request(message
);
228 switch (message
->get_exchange_type(message
))
233 type
= request
? COUNTER_IN_IKE_SA_INIT_REQ
234 : COUNTER_IN_IKE_SA_INIT_RSP
;
238 type
= request
? COUNTER_OUT_IKE_SA_INIT_REQ
239 : COUNTER_OUT_IKE_SA_INIT_RES
;
245 type
= request
? COUNTER_IN_IKE_AUTH_REQ
246 : COUNTER_IN_IKE_AUTH_RSP
;
250 type
= request
? COUNTER_OUT_IKE_AUTH_REQ
251 : COUNTER_OUT_IKE_AUTH_RSP
;
254 case CREATE_CHILD_SA
:
257 type
= request
? COUNTER_IN_CREATE_CHILD_SA_REQ
258 : COUNTER_IN_CREATE_CHILD_SA_RSP
;
262 type
= request
? COUNTER_OUT_CREATE_CHILD_SA_REQ
263 : COUNTER_OUT_CREATE_CHILD_SA_RSP
;
269 type
= request
? COUNTER_IN_INFORMATIONAL_REQ
270 : COUNTER_IN_INFORMATIONAL_RSP
;
274 type
= request
? COUNTER_OUT_INFORMATIONAL_REQ
275 : COUNTER_OUT_INFORMATIONAL_RSP
;
282 this->lock
->lock(this->lock
);
283 this->counters
[type
]++;
284 count_named(this, ike_sa
, type
);
285 this->lock
->unlock(this->lock
);
290 CALLBACK(free_names
, void,
293 array_destroy_function(names
, (void*)free
, NULL
);
296 METHOD(counters_query_t
, get_names
, enumerator_t
*,
297 private_counters_query_t
*query
)
299 private_counters_listener_t
*this = query
->this;
300 enumerator_t
*enumerator
;
304 this->lock
->lock(this->lock
);
305 names
= array_create(0, this->conns
->get_count(this->conns
));
306 enumerator
= this->conns
->create_enumerator(this->conns
);
307 while (enumerator
->enumerate(enumerator
, &name
, NULL
))
309 array_insert(names
, ARRAY_TAIL
, strdup(name
));
311 enumerator
->destroy(enumerator
);
312 this->lock
->unlock(this->lock
);
314 array_sort(names
, (void*)strcmp
, NULL
);
316 return enumerator_create_cleaner(array_create_enumerator(names
),
320 METHOD(counters_query_t
, get
, bool,
321 private_counters_query_t
*query
, counter_type_t type
, char *name
,
324 private_counters_listener_t
*this = query
->this;
325 uint64_t *counters
= this->counters
;
327 this->lock
->lock(this->lock
);
332 entry
= this->conns
->get(this->conns
, name
);
335 this->lock
->unlock(this->lock
);
338 counters
= entry
->counters
;
342 *value
= counters
[type
];
344 this->lock
->unlock(this->lock
);
348 METHOD(counters_query_t
, get_all
, uint64_t*,
349 private_counters_query_t
*query
, char *name
)
351 private_counters_listener_t
*this = query
->this;
353 uint64_t *result
, *counters
= this->counters
;
356 result
= calloc(COUNTER_MAX
, sizeof(uint64_t));
358 this->lock
->lock(this->lock
);
361 entry
= this->conns
->get(this->conns
, name
);
364 this->lock
->unlock(this->lock
);
368 counters
= &entry
->counters
[0];
370 for (i
= 0; i
< countof(this->counters
); i
++)
372 result
[i
] = counters
[i
];
374 this->lock
->unlock(this->lock
);
378 METHOD(counters_query_t
, reset
, void,
379 private_counters_query_t
*query
, char *name
)
381 private_counters_listener_t
*this = query
->this;
382 entry_t
*entry
= NULL
;
384 this->lock
->lock(this->lock
);
387 entry
= this->conns
->remove(this->conns
, name
);
391 memset(&this->counters
, 0, sizeof(this->counters
));
393 this->lock
->unlock(this->lock
);
397 destroy_entry(entry
);
401 METHOD(counters_query_t
, reset_all
, void,
402 private_counters_query_t
*query
)
404 private_counters_listener_t
*this = query
->this;
405 hashtable_t
*new_conns
, *conns
;
407 new_conns
= hashtable_create((hashtable_hash_t
)hash
,
408 (hashtable_equals_t
)equals
, 4);
410 this->lock
->lock(this->lock
);
412 this->conns
= new_conns
;
413 this->lock
->unlock(this->lock
);
415 conns
->destroy_function(conns
, (void*)destroy_entry
);
418 METHOD(counters_listener_t
, destroy
, void,
419 private_counters_listener_t
*this)
421 lib
->set(lib
, "counters", NULL
);
423 this->conns
->destroy_function(this->conns
, (void*)destroy_entry
);
424 this->lock
->destroy(this->lock
);
429 * Described in header
431 counters_listener_t
*counters_listener_create()
433 private_counters_listener_t
*this;
439 .ike_rekey
= _ike_rekey
,
440 .child_rekey
= _child_rekey
,
441 .message
= _message_hook
,
447 .get_names
= _get_names
,
451 .reset_all
= _reset_all
,
454 .conns
= hashtable_create((hashtable_hash_t
)hash
,
455 (hashtable_equals_t
)equals
, 4),
456 .lock
= spinlock_create(),
458 this->query
.this = this;
460 lib
->set(lib
, "counters", &this->query
);
462 return &this->public;