2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "stroke_counter.h"
18 #include <threading/spinlock.h>
19 #include <collections/hashtable.h>
21 ENUM(stroke_counter_type_names
,
22 COUNTER_INIT_IKE_SA_REKEY
, COUNTER_OUT_INFORMATIONAL_RSP
,
46 typedef struct private_stroke_counter_t private_stroke_counter_t
;
49 * Private data of an stroke_counter_t object.
51 struct private_stroke_counter_t
{
54 * Public stroke_counter_t interface.
56 stroke_counter_t
public;
59 * Global counter values
61 u_int64_t counter
[COUNTER_MAX
];
64 * Counters for specific connection names, char* => entry_t
69 * Lock for counter values
75 * Counters for a specific connection name
78 /** connection name */
80 /** counter values for connection */
81 u_int64_t counter
[COUNTER_MAX
];
87 static void destroy_entry(entry_t
*this)
94 * Hashtable hash function
96 static u_int
hash(char *name
)
98 return chunk_hash(chunk_from_str(name
));
102 * Hashtable equals function
104 static bool equals(char *a
, char *b
)
110 * Get the name of an IKE_SA, but return NULL if it is not known yet
112 static char *get_ike_sa_name(ike_sa_t
*ike_sa
)
114 peer_cfg_t
*peer_cfg
;
118 peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
121 return peer_cfg
->get_name(peer_cfg
);
128 * Increase a counter for a named entry
130 static void count_named(private_stroke_counter_t
*this,
131 ike_sa_t
*ike_sa
, stroke_counter_type_t type
)
136 name
= get_ike_sa_name(ike_sa
);
139 entry
= this->conns
->get(this->conns
, name
);
143 .name
= strdup(name
),
145 this->conns
->put(this->conns
, entry
->name
, entry
);
147 entry
->counter
[type
]++;
151 METHOD(listener_t
, alert
, bool,
152 private_stroke_counter_t
*this, ike_sa_t
*ike_sa
,
153 alert_t alert
, va_list args
)
155 stroke_counter_type_t type
;
159 case ALERT_INVALID_IKE_SPI
:
160 type
= COUNTER_IN_INVALID_IKE_SPI
;
162 case ALERT_PARSE_ERROR_HEADER
:
163 case ALERT_PARSE_ERROR_BODY
:
164 type
= COUNTER_IN_INVALID
;
170 this->lock
->lock(this->lock
);
171 this->counter
[type
]++;
172 count_named(this, ike_sa
, type
);
173 this->lock
->unlock(this->lock
);
178 METHOD(listener_t
, ike_rekey
, bool,
179 private_stroke_counter_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
181 stroke_counter_type_t type
;
184 id
= new->get_id(new);
185 if (id
->is_initiator(id
))
187 type
= COUNTER_INIT_IKE_SA_REKEY
;
191 type
= COUNTER_RESP_IKE_SA_REKEY
;
194 this->lock
->lock(this->lock
);
195 this->counter
[type
]++;
196 count_named(this, old
, type
);
197 this->lock
->unlock(this->lock
);
202 METHOD(listener_t
, child_rekey
, bool,
203 private_stroke_counter_t
*this, ike_sa_t
*ike_sa
,
204 child_sa_t
*old
, child_sa_t
*new)
206 this->lock
->lock(this->lock
);
207 this->counter
[COUNTER_CHILD_SA_REKEY
]++;
208 count_named(this, ike_sa
, COUNTER_CHILD_SA_REKEY
);
209 this->lock
->unlock(this->lock
);
214 METHOD(listener_t
, message_hook
, bool,
215 private_stroke_counter_t
*this, ike_sa_t
*ike_sa
, message_t
*message
,
216 bool incoming
, bool plain
)
218 stroke_counter_type_t type
;
221 if ((incoming
&& !plain
) || (!incoming
&& !plain
))
222 { /* handle each message only once */
226 request
= message
->get_request(message
);
227 switch (message
->get_exchange_type(message
))
232 type
= request ? COUNTER_IN_IKE_SA_INIT_REQ
233 : COUNTER_IN_IKE_SA_INIT_RSP
;
237 type
= request ? COUNTER_OUT_IKE_SA_INIT_REQ
238 : COUNTER_OUT_IKE_SA_INIT_RES
;
244 type
= request ? COUNTER_IN_IKE_AUTH_REQ
245 : COUNTER_IN_IKE_AUTH_RSP
;
249 type
= request ? COUNTER_OUT_IKE_AUTH_REQ
250 : COUNTER_OUT_IKE_AUTH_RSP
;
253 case CREATE_CHILD_SA
:
256 type
= request ? COUNTER_IN_CREATE_CHILD_SA_REQ
257 : COUNTER_IN_CREATE_CHILD_SA_RSP
;
261 type
= request ? COUNTER_OUT_CREATE_CHILD_SA_REQ
262 : COUNTER_OUT_CREATE_CHILD_SA_RSP
;
268 type
= request ? COUNTER_IN_INFORMATIONAL_REQ
269 : COUNTER_IN_INFORMATIONAL_RSP
;
273 type
= request ? COUNTER_OUT_INFORMATIONAL_REQ
274 : COUNTER_OUT_INFORMATIONAL_RSP
;
281 this->lock
->lock(this->lock
);
282 this->counter
[type
]++;
283 count_named(this, ike_sa
, type
);
284 this->lock
->unlock(this->lock
);
290 * Print a single counter value to out
292 static void print_counter(FILE *out
, stroke_counter_type_t type
,
295 fprintf(out
, "%-18N %12llu\n", stroke_counter_type_names
, type
, counter
);
299 * Print IKE counters for a specific connection
301 static void print_one(private_stroke_counter_t
*this, FILE *out
, char *name
)
303 u_int64_t counter
[COUNTER_MAX
];
307 this->lock
->lock(this->lock
);
308 entry
= this->conns
->get(this->conns
, name
);
311 for (i
= 0; i
< countof(this->counter
); i
++)
313 counter
[i
] = entry
->counter
[i
];
316 this->lock
->unlock(this->lock
);
320 fprintf(out
, "\nList of IKE counters for '%s':\n\n", name
);
321 for (i
= 0; i
< countof(this->counter
); i
++)
323 print_counter(out
, i
, counter
[i
]);
328 fprintf(out
, "No IKE counters found for '%s'\n", name
);
333 * Print counters for all connections
335 static void print_all(private_stroke_counter_t
*this, FILE *out
)
337 enumerator_t
*enumerator
;
342 list
= linked_list_create();
344 this->lock
->lock(this->lock
);
345 enumerator
= this->conns
->create_enumerator(this->conns
);
346 while (enumerator
->enumerate(enumerator
, &name
, &entry
))
348 list
->insert_last(list
, strdup(name
));
350 enumerator
->destroy(enumerator
);
351 this->lock
->unlock(this->lock
);
353 enumerator
= list
->create_enumerator(list
);
354 while (enumerator
->enumerate(enumerator
, &name
))
356 print_one(this, out
, name
);
358 enumerator
->destroy(enumerator
);
360 list
->destroy_function(list
, free
);
364 * Print global counters
366 static void print_global(private_stroke_counter_t
*this, FILE *out
)
368 u_int64_t counter
[COUNTER_MAX
];
371 this->lock
->lock(this->lock
);
372 for (i
= 0; i
< countof(this->counter
); i
++)
374 counter
[i
] = this->counter
[i
];
376 this->lock
->unlock(this->lock
);
378 fprintf(out
, "\nList of IKE counters:\n\n");
380 for (i
= 0; i
< countof(this->counter
); i
++)
382 print_counter(out
, i
, counter
[i
]);
386 METHOD(stroke_counter_t
, print
, void,
387 private_stroke_counter_t
*this, FILE *out
, char *name
)
391 if (streq(name
, "all"))
393 return print_all(this, out
);
395 return print_one(this, out
, name
);
397 return print_global(this, out
);
400 METHOD(stroke_counter_t
, reset
, void,
401 private_stroke_counter_t
*this, char *name
)
403 this->lock
->lock(this->lock
);
408 entry
= this->conns
->remove(this->conns
, name
);
411 destroy_entry(entry
);
416 memset(&this->counter
, 0, sizeof(this->counter
));
418 this->lock
->unlock(this->lock
);
421 METHOD(stroke_counter_t
, destroy
, void,
422 private_stroke_counter_t
*this)
424 enumerator_t
*enumerator
;
428 enumerator
= this->conns
->create_enumerator(this->conns
);
429 while (enumerator
->enumerate(enumerator
, &name
, &entry
))
431 destroy_entry(entry
);
433 enumerator
->destroy(enumerator
);
434 this->conns
->destroy(this->conns
);
435 this->lock
->destroy(this->lock
);
442 stroke_counter_t
*stroke_counter_create()
444 private_stroke_counter_t
*this;
450 .ike_rekey
= _ike_rekey
,
451 .child_rekey
= _child_rekey
,
452 .message
= _message_hook
,
458 .conns
= hashtable_create((hashtable_hash_t
)hash
,
459 (hashtable_equals_t
)equals
, 4),
460 .lock
= spinlock_create(),
463 return &this->public;