summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/dnstap/dnstap.c1
-rw-r--r--modules/hints/meson.build2
-rw-r--r--modules/http/meson.build2
-rw-r--r--modules/stats/stats.c143
4 files changed, 110 insertions, 38 deletions
diff --git a/modules/dnstap/dnstap.c b/modules/dnstap/dnstap.c
index ab52bca3..6fcc192c 100644
--- a/modules/dnstap/dnstap.c
+++ b/modules/dnstap/dnstap.c
@@ -193,6 +193,7 @@ static int dnstap_log(kr_layer_t *ctx, enum dnstap_log_phase phase) {
m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
m.has_socket_family = true;
break;
+ default:;
}
}
diff --git a/modules/hints/meson.build b/modules/hints/meson.build
index d5046cb4..7e681f11 100644
--- a/modules/hints/meson.build
+++ b/modules/hints/meson.build
@@ -18,5 +18,5 @@ hints_mod = shared_module(
)
config_tests += [
- ['hints', files('tests/hints.test.lua'), ['skip_asan']],
+ ['hints', files('tests/hints.test.lua')],
]
diff --git a/modules/http/meson.build b/modules/http/meson.build
index 9d20c929..7d892159 100644
--- a/modules/http/meson.build
+++ b/modules/http/meson.build
@@ -21,7 +21,7 @@ lua_mod_src += [
config_tests += [
['http', files('http.test.lua')],
['http.doh', files('http_doh.test.lua')],
- ['http.tls', files('test_tls/tls.test.lua')],
+ ['http.tls', files('test_tls/tls.test.lua'), ['skip_asan']],
]
# install static files
diff --git a/modules/stats/stats.c b/modules/stats/stats.c
index a8a29de2..deed9c94 100644
--- a/modules/stats/stats.c
+++ b/modules/stats/stats.c
@@ -46,8 +46,9 @@
X(answer,aa) X(answer,tc) X(answer,rd) X(answer,ra) X(answer, ad) X(answer,cd) \
X(answer,edns0) X(answer,do) \
X(query,edns) X(query,dnssec) \
- X(request,total) X(request,udp) X(request,tcp) X(request,xdp) \
- X(request,dot) X(request,doh) X(request,internal) \
+ X(request,total) X(request,total4) X(request,total6) X(request,internal) \
+ X(request,udp4) X(request,tcp4) X(request,xdp4) X(request,dot4) X(request,doh4) \
+ X(request,udp6) X(request,tcp6) X(request,xdp6) X(request,dot6) X(request,doh6) \
X(const,end)
enum const_metric {
@@ -72,6 +73,29 @@ static struct const_metric_elm const_metrics[] = {
CONST_METRICS(X)
#undef X
};
+
+/// These metrics are read-only views, each simply summing a pair of const_metrics items.
+struct sum_metric {
+ const char *sub_key;
+ const size_t *val1, *val2;
+};
+static const struct sum_metric sum_metrics[] = {
+ // We're using this to aggregate v4 + v6 pairs.
+ #define DEF(proto) { \
+ .sub_key = #proto, \
+ .val1 = &const_metrics[metric_request_ ## proto ## 4].val, \
+ .val2 = &const_metrics[metric_request_ ## proto ## 6].val, \
+ }
+ DEF(udp),
+ DEF(tcp),
+ DEF(xdp),
+ DEF(dot),
+ DEF(doh),
+ #undef DEF
+};
+static const size_t sum_metrics_len = sizeof(sum_metrics) / sizeof(sum_metrics[0]);
+#define SUM_METRICS_SUP_KEY "request"
+
/** @endcond */
/** @internal LRU hash of most frequent names. */
@@ -125,7 +149,7 @@ static inline int collect_key(char *key, const knot_dname_t *name, uint16_t type
if (key_len < 0) {
return kr_error(key_len);
}
- return key_len + sizeof(type);
+ return key_len + (int)sizeof(type);
}
static void collect_sample(struct stat_data *data, struct kr_rplan *rplan)
@@ -193,19 +217,26 @@ static int collect_transport(kr_layer_t *ctx)
}
/**
- * Count each transport only once,
+ * Apart from the "total" stats, count each transport only once,
* i.e. DoT does not count as TCP and XDP does not count as UDP.
+ * We have two counts for each - IPv6 and IPv4 separately.
*/
+ const bool isIPv6 = req->qsource.addr->sa_family == AF_INET6;
+ #define INC_PROTO(proto) \
+ stat_const_add(data, isIPv6 ? metric_request_ ## proto ## 6 \
+ : metric_request_ ## proto ## 4, 1)
+ INC_PROTO(total);
if (req->qsource.flags.http)
- stat_const_add(data, metric_request_doh, 1);
+ INC_PROTO(doh);
else if (req->qsource.flags.tls)
- stat_const_add(data, metric_request_dot, 1);
+ INC_PROTO(dot);
else if (req->qsource.flags.tcp)
- stat_const_add(data, metric_request_tcp, 1);
+ INC_PROTO(tcp);
else if (req->qsource.flags.xdp)
- stat_const_add(data, metric_request_xdp, 1);
+ INC_PROTO(xdp);
else
- stat_const_add(data, metric_request_udp, 1);
+ INC_PROTO(udp);
+ #undef INC_PROTO
return ctx->state;
}
@@ -282,6 +313,7 @@ static int collect(kr_layer_t *ctx)
* Set nominal value of a key.
*
* Input: { key, val }
+ * Aggregate metrics can't be set.
*
*/
static char* stats_set(void *env, struct kr_module *module, const char *args)
@@ -323,26 +355,36 @@ static char* stats_get(void *env, struct kr_module *module, const char *args)
struct stat_data *data = module->data;
/* Expecting CHAR_BIT to be 8, this is a safe bet */
- char *ret = malloc(3 * sizeof(size_t) + 2);
- if (!ret) {
- return NULL;
- }
+ char *str_value = NULL;
+ int ret = 0;
/* Check if it exists in const map. */
for (unsigned i = 0; i < metric_const_end; ++i) {
if (strcmp(const_metrics[i].key, args) == 0) {
- sprintf(ret, "%zu", const_metrics[i].val);
- return ret;
+ ret = asprintf(&str_value, "%zu", const_metrics[i].val);
+ if (ret < 0)
+ return NULL;
+ return str_value;
+ }
+ }
+ /* Check if it exists in aggregate metrics. */
+ for (int i = 0; i < sum_metrics_len; ++i) {
+ const struct sum_metric *smi = &sum_metrics[i];
+ if (strcmp(smi->sub_key, args) == 0) {
+ ret = asprintf(&str_value, "%zu", *smi->val1 + *smi->val2);
+ if (ret < 0)
+ return NULL;
+ return str_value;
}
}
/* Check in variable map */
trie_val_t *val = trie_get_try(data->trie, args, strlen(args));
- if (!val) {
- free(ret);
+ if (!val)
return NULL;
- }
- sprintf(ret, "%zu", (size_t) *val);
- return ret;
+ ret = asprintf(&str_value, "%zu", (size_t) *val);
+ if (ret < 0)
+ return NULL;
+ return str_value;
}
/** Checks whether:
@@ -360,13 +402,31 @@ struct list_entry_context {
size_t key_prefix_len; /**< Prefix length. Prefix is a wildcard if zero. */
};
+/** Ensures that the `root` node contains an object (and only an object - not a
+ * number, array, or anything else) with the specified `key`. If this cannot be
+ * ensured, fails on an assertion, or returns `NULL` if asserts are disabled. */
+static JsonNode *ensure_object(JsonNode *root, const char *key)
+{
+ JsonNode *node = json_find_member(root, key);
+ if (node) {
+ if (kr_fails_assert(node->tag == JSON_OBJECT))
+ return NULL;
+ } else {
+ node = json_mkobject();
+ if (kr_fails_assert(node))
+ return NULL;
+ json_append_member(root, key, node);
+ }
+ return node;
+}
+
/** Inserts the entry with a matching key into the JSON object. */
static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *baton)
{
struct list_entry_context *ctx = baton;
if (!key_matches_prefix(key, key_len, ctx->key_prefix, ctx->key_prefix_len))
return 0;
- size_t number = (size_t) *val;
+ size_t number = (size_t)*val;
uint32_t dot_index = 0;
for (uint32_t i = 0; i < key_len; i++) {
@@ -380,17 +440,13 @@ static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *
if (dot_index) {
auto_free char *sup_key_nt = strndup(key, dot_index);
auto_free char *sub_key_nt = strndup(key + dot_index + 1, key_len - dot_index - 1);
- JsonNode *sup = json_find_member(ctx->root, sup_key_nt);
- if (!sup) {
- sup = json_mkobject();
- json_append_member(ctx->root, sup_key_nt, sup);
- }
- if (kr_fails_assert(sup))
+ JsonNode *sup = ensure_object(ctx->root, sup_key_nt);
+ if (!sup)
return 0;
- json_append_member(sup, sub_key_nt, json_mknumber(number));
+ json_append_member(sup, sub_key_nt, json_mknumber((double)number));
} else {
auto_free char *key_nt = strndup(key, key_len);
- json_append_member(ctx->root, key_nt, json_mknumber(number));
+ json_append_member(ctx->root, key_nt, json_mknumber((double)number));
}
return 0;
}
@@ -402,22 +458,36 @@ static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *
*/
static char* stats_list(void *env, struct kr_module *module, const char *args)
{
+ char *ret;
JsonNode *root = json_mkobject();
/* Walk const metrics map */
size_t args_len = args ? strlen(args) : 0;
for (unsigned i = 0; i < metric_const_end; ++i) {
struct const_metric_elm *elm = &const_metrics[i];
if (!args || strcmp(elm->sup_key, args) == 0) {
- JsonNode *sup = json_find_member(root, elm->sup_key);
+ JsonNode *sup = ensure_object(root, elm->sup_key);
if (!sup) {
- sup = json_mkobject();
- json_append_member(root, elm->sup_key, sup);
+ ret = strdup("\"ERROR\"");
+ goto exit;
}
- if (kr_fails_assert(sup))
- break;
- json_append_member(sup, elm->sub_key, json_mknumber(elm->val));
+ json_append_member(sup, elm->sub_key, json_mknumber((double)elm->val));
}
}
+
+ /* Walk sum metrics map */
+ JsonNode *sum_sup = ensure_object(root, SUM_METRICS_SUP_KEY);
+ if (!sum_sup) {
+ ret = strdup("\"ERROR\"");
+ goto exit;
+ }
+ for (int i = 0; i < sum_metrics_len; ++i) {
+ const struct sum_metric *elm = &sum_metrics[i];
+ if (!args || strncmp(elm->sub_key, args, args_len) == 0) {
+ size_t val = *elm->val1 + *elm->val2;
+ json_append_member(sum_sup, elm->sub_key, json_mknumber(val));
+ }
+ }
+
struct list_entry_context ctx = {
.root = root,
.key_prefix = args,
@@ -425,7 +495,8 @@ static char* stats_list(void *env, struct kr_module *module, const char *args)
};
struct stat_data *data = module->data;
trie_apply_with_key(data->trie, list_entry, &ctx);
- char *ret = json_encode(root);
+ ret = json_encode(root);
+exit:
json_delete(root);
return ret;
}