forked from acouzens/open5gs
391 lines
12 KiB
C
391 lines
12 KiB
C
#include "ogs-app.h"
|
|
#include "context.h"
|
|
|
|
#include "metrics.h"
|
|
|
|
typedef struct upf_metrics_spec_def_s {
|
|
unsigned int type;
|
|
const char *name;
|
|
const char *description;
|
|
int initial_val;
|
|
unsigned int num_labels;
|
|
const char **labels;
|
|
} upf_metrics_spec_def_t;
|
|
|
|
/* Helper generic functions: */
|
|
static int upf_metrics_init_inst(ogs_metrics_inst_t **inst,
|
|
ogs_metrics_spec_t **specs, unsigned int len,
|
|
unsigned int num_labels, const char **labels)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++)
|
|
inst[i] = ogs_metrics_inst_new(specs[i], num_labels, labels);
|
|
return OGS_OK;
|
|
}
|
|
|
|
static int upf_metrics_free_inst(ogs_metrics_inst_t **inst,
|
|
unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++)
|
|
ogs_metrics_inst_free(inst[i]);
|
|
memset(inst, 0, sizeof(inst[0]) * len);
|
|
return OGS_OK;
|
|
}
|
|
|
|
static int upf_metrics_init_spec(ogs_metrics_context_t *ctx,
|
|
ogs_metrics_spec_t **dst, upf_metrics_spec_def_t *src, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++) {
|
|
dst[i] = ogs_metrics_spec_new(ctx, src[i].type,
|
|
src[i].name, src[i].description,
|
|
src[i].initial_val, src[i].num_labels, src[i].labels,
|
|
NULL);
|
|
}
|
|
return OGS_OK;
|
|
}
|
|
|
|
/* GLOBAL */
|
|
ogs_metrics_spec_t *upf_metrics_spec_global[_UPF_METR_GLOB_MAX];
|
|
ogs_metrics_inst_t *upf_metrics_inst_global[_UPF_METR_GLOB_MAX];
|
|
upf_metrics_spec_def_t upf_metrics_spec_def_global[_UPF_METR_GLOB_MAX] = {
|
|
/* Global Counters: */
|
|
[UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER,
|
|
.name = "fivegs_ep_n3_gtp_indatapktn3upf",
|
|
.description = "Number of incoming GTP data packets on the N3 interface",
|
|
},
|
|
[UPF_METR_GLOB_CTR_GTP_OUTDATAPKTN3UPF] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER,
|
|
.name = "fivegs_ep_n3_gtp_outdatapktn3upf",
|
|
.description = "Number of outgoing GTP data packets on the N3 interface",
|
|
},
|
|
[UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER,
|
|
.name = "fivegs_upffunction_sm_n4sessionestabreq",
|
|
.description = "Number of requested N4 session establishments",
|
|
},
|
|
[UPF_METR_GLOB_CTR_SM_N4SESSIONREPORT] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER,
|
|
.name = "fivegs_upffunction_sm_n4sessionreport",
|
|
.description = "Number of requested N4 session reports",
|
|
},
|
|
[UPF_METR_GLOB_CTR_SM_N4SESSIONREPORTSUCC] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER,
|
|
.name = "fivegs_upffunction_sm_n4sessionreportsucc",
|
|
.description = "Number of successful N4 session reports",
|
|
},
|
|
/* Global Gauges: */
|
|
[UPF_METR_GLOB_GAUGE_UPF_SESSIONNBR] = {
|
|
.type = OGS_METRICS_METRIC_TYPE_GAUGE,
|
|
.name = "fivegs_upffunction_upf_sessionnbr",
|
|
.description = "Active Sessions",
|
|
},
|
|
};
|
|
int upf_metrics_init_inst_global(void)
|
|
{
|
|
return upf_metrics_init_inst(upf_metrics_inst_global, upf_metrics_spec_global,
|
|
_UPF_METR_GLOB_MAX, 0, NULL);
|
|
}
|
|
int upf_metrics_free_inst_global(void)
|
|
{
|
|
return upf_metrics_free_inst(upf_metrics_inst_global, _UPF_METR_GLOB_MAX);
|
|
}
|
|
|
|
/* BY_QFI */
|
|
const char *labels_qfi[] = {
|
|
"qfi"
|
|
};
|
|
#define UPF_METR_BY_QFI_CTR_ENTRY(_id, _name, _desc) \
|
|
[_id] = { \
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER, \
|
|
.name = _name, \
|
|
.description = _desc, \
|
|
.num_labels = OGS_ARRAY_SIZE(labels_qfi), \
|
|
.labels = labels_qfi, \
|
|
},
|
|
ogs_metrics_spec_t *upf_metrics_spec_by_qfi[_UPF_METR_BY_QFI_MAX];
|
|
ogs_hash_t *metrics_hash_by_qfi = NULL; /* hash table for QFI label */
|
|
upf_metrics_spec_def_t upf_metrics_spec_def_by_qfi[_UPF_METR_BY_QFI_MAX] = {
|
|
/* Counters: */
|
|
UPF_METR_BY_QFI_CTR_ENTRY(
|
|
UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF,
|
|
"fivegs_ep_n3_gtp_indatavolumeqosleveln3upf",
|
|
"Data volume of incoming GTP data packets per QoS level on the N3 interface")
|
|
UPF_METR_BY_QFI_CTR_ENTRY(
|
|
UPF_METR_CTR_GTP_OUTDATAVOLUMEQOSLEVELN3UPF,
|
|
"fivegs_ep_n3_gtp_outdatavolumeqosleveln3upf",
|
|
"Data volume of outgoing GTP data packets per QoS level on the N3 interface")
|
|
};
|
|
void upf_metrics_init_by_qfi(void);
|
|
int upf_metrics_free_inst_by_qfi(ogs_metrics_inst_t **inst);
|
|
typedef struct upf_metric_key_by_qfi_s {
|
|
uint8_t qfi;
|
|
upf_metric_type_by_qfi_t t;
|
|
} upf_metric_key_by_qfi_t;
|
|
|
|
void upf_metrics_init_by_qfi(void)
|
|
{
|
|
metrics_hash_by_qfi = ogs_hash_make();
|
|
ogs_assert(metrics_hash_by_qfi);
|
|
}
|
|
void upf_metrics_inst_by_qfi_add(uint8_t qfi,
|
|
upf_metric_type_by_qfi_t t, int val)
|
|
{
|
|
ogs_metrics_inst_t *metrics = NULL;
|
|
upf_metric_key_by_qfi_t *qfi_key;
|
|
|
|
qfi_key = ogs_calloc(1, sizeof(*qfi_key));
|
|
ogs_assert(qfi_key);
|
|
|
|
qfi_key->qfi = qfi;
|
|
qfi_key->t = t;
|
|
|
|
metrics = ogs_hash_get(metrics_hash_by_qfi,
|
|
qfi_key, sizeof(*qfi_key));
|
|
|
|
if (!metrics) {
|
|
char qfi_str[4];
|
|
ogs_snprintf(qfi_str, sizeof(qfi_str), "%d", qfi);
|
|
|
|
metrics = ogs_metrics_inst_new(upf_metrics_spec_by_qfi[t],
|
|
upf_metrics_spec_def_by_qfi->num_labels,
|
|
(const char *[]){ qfi_str });
|
|
|
|
ogs_assert(metrics);
|
|
ogs_hash_set(metrics_hash_by_qfi,
|
|
qfi_key, sizeof(*qfi_key), metrics);
|
|
} else {
|
|
ogs_free(qfi_key);
|
|
}
|
|
|
|
ogs_metrics_inst_add(metrics, val);
|
|
}
|
|
|
|
int upf_metrics_free_inst_by_qfi(ogs_metrics_inst_t **inst)
|
|
{
|
|
return upf_metrics_free_inst(inst, _UPF_METR_BY_QFI_MAX);
|
|
}
|
|
|
|
/* BY_CAUSE */
|
|
const char *labels_cause[] = {
|
|
"cause"
|
|
};
|
|
|
|
#define UPF_METR_BY_CAUSE_CTR_ENTRY(_id, _name, _desc) \
|
|
[_id] = { \
|
|
.type = OGS_METRICS_METRIC_TYPE_COUNTER, \
|
|
.name = _name, \
|
|
.description = _desc, \
|
|
.num_labels = OGS_ARRAY_SIZE(labels_cause), \
|
|
.labels = labels_cause, \
|
|
},
|
|
ogs_metrics_spec_t *upf_metrics_spec_by_cause[_UPF_METR_BY_CAUSE_MAX];
|
|
ogs_hash_t *metrics_hash_by_cause = NULL; /* hash table for CAUSE labels */
|
|
upf_metrics_spec_def_t upf_metrics_spec_def_by_cause[_UPF_METR_BY_CAUSE_MAX] = {
|
|
/* Counters: */
|
|
UPF_METR_BY_CAUSE_CTR_ENTRY(
|
|
UPF_METR_CTR_SM_N4SESSIONESTABFAIL,
|
|
"fivegs_upffunction_sm_n4sessionestabfail",
|
|
"Number of failed N4 session establishments")
|
|
};
|
|
void upf_metrics_init_by_cause(void);
|
|
int upf_metrics_free_inst_by_cause(ogs_metrics_inst_t **inst);
|
|
typedef struct upf_metric_key_by_cause_s {
|
|
uint8_t cause;
|
|
upf_metric_type_by_cause_t t;
|
|
} upf_metric_key_by_cause_t;
|
|
|
|
void upf_metrics_init_by_cause(void)
|
|
{
|
|
metrics_hash_by_cause = ogs_hash_make();
|
|
ogs_assert(metrics_hash_by_cause);
|
|
}
|
|
|
|
void upf_metrics_inst_by_cause_add(uint8_t cause,
|
|
upf_metric_type_by_cause_t t, int val)
|
|
{
|
|
ogs_metrics_inst_t *metrics = NULL;
|
|
upf_metric_key_by_cause_t *cause_key;
|
|
|
|
cause_key = ogs_calloc(1, sizeof(*cause_key));
|
|
ogs_assert(cause_key);
|
|
|
|
cause_key->cause = cause;
|
|
cause_key->t = t;
|
|
|
|
metrics = ogs_hash_get(metrics_hash_by_cause,
|
|
cause_key, sizeof(*cause_key));
|
|
|
|
if (!metrics) {
|
|
char cause_str[4];
|
|
ogs_snprintf(cause_str, sizeof(cause_str), "%d", cause);
|
|
|
|
metrics = ogs_metrics_inst_new(upf_metrics_spec_by_cause[t],
|
|
upf_metrics_spec_def_by_cause->num_labels,
|
|
(const char *[]){ cause_str });
|
|
|
|
ogs_assert(metrics);
|
|
ogs_hash_set(metrics_hash_by_cause,
|
|
cause_key, sizeof(*cause_key), metrics);
|
|
} else {
|
|
ogs_free(cause_key);
|
|
}
|
|
|
|
ogs_metrics_inst_add(metrics, val);
|
|
}
|
|
|
|
int upf_metrics_free_inst_by_cause(ogs_metrics_inst_t **inst)
|
|
{
|
|
return upf_metrics_free_inst(inst, _UPF_METR_BY_CAUSE_MAX);
|
|
}
|
|
|
|
/* BY_DNN */
|
|
const char *labels_dnn[] = {
|
|
"dnn"
|
|
};
|
|
|
|
#define UPF_METR_BY_DNN_GAUGE_ENTRY(_id, _name, _desc) \
|
|
[_id] = { \
|
|
.type = OGS_METRICS_METRIC_TYPE_GAUGE, \
|
|
.name = _name, \
|
|
.description = _desc, \
|
|
.num_labels = OGS_ARRAY_SIZE(labels_dnn), \
|
|
.labels = labels_dnn, \
|
|
},
|
|
ogs_metrics_spec_t *upf_metrics_spec_by_dnn[_UPF_METR_BY_DNN_MAX];
|
|
ogs_hash_t *metrics_hash_by_dnn = NULL; /* hash table for DNN labels */
|
|
upf_metrics_spec_def_t upf_metrics_spec_def_by_dnn[_UPF_METR_BY_DNN_MAX] = {
|
|
/* Gauges: */
|
|
UPF_METR_BY_DNN_GAUGE_ENTRY(
|
|
UPF_METR_GAUGE_UPF_QOSFLOWS,
|
|
"fivegs_upffunction_upf_qosflows",
|
|
"Number of QoS flows of UPF")
|
|
};
|
|
void upf_metrics_init_by_dnn(void);
|
|
int upf_metrics_free_inst_by_dnn(ogs_metrics_inst_t **inst);
|
|
typedef struct upf_metric_key_by_dnn_s {
|
|
char dnn[OGS_MAX_DNN_LEN+1];
|
|
upf_metric_type_by_dnn_t t;
|
|
} upf_metric_key_by_dnn_t;
|
|
|
|
void upf_metrics_init_by_dnn(void)
|
|
{
|
|
metrics_hash_by_dnn = ogs_hash_make();
|
|
ogs_assert(metrics_hash_by_dnn);
|
|
}
|
|
|
|
void upf_metrics_inst_by_dnn_add(char *dnn,
|
|
upf_metric_type_by_dnn_t t, int val)
|
|
{
|
|
ogs_metrics_inst_t *metrics = NULL;
|
|
upf_metric_key_by_dnn_t *dnn_key;
|
|
|
|
dnn_key = ogs_calloc(1, sizeof(*dnn_key));
|
|
ogs_assert(dnn_key);
|
|
|
|
if (dnn) {
|
|
ogs_cpystrn(dnn_key->dnn, dnn, ogs_min(strlen(dnn), OGS_MAX_DNN_LEN)+1);
|
|
} else {
|
|
dnn_key->dnn[0] = '\0';
|
|
}
|
|
|
|
dnn_key->t = t;
|
|
|
|
metrics = ogs_hash_get(metrics_hash_by_dnn,
|
|
dnn_key, sizeof(*dnn_key));
|
|
|
|
if (!metrics) {
|
|
metrics = ogs_metrics_inst_new(upf_metrics_spec_by_dnn[t],
|
|
upf_metrics_spec_def_by_dnn->num_labels,
|
|
(const char *[]){ dnn_key->dnn });
|
|
|
|
ogs_assert(metrics);
|
|
ogs_hash_set(metrics_hash_by_dnn,
|
|
dnn_key, sizeof(*dnn_key), metrics);
|
|
} else {
|
|
ogs_free(dnn_key);
|
|
}
|
|
|
|
ogs_metrics_inst_add(metrics, val);
|
|
}
|
|
|
|
int upf_metrics_free_inst_by_dnn(ogs_metrics_inst_t **inst)
|
|
{
|
|
return upf_metrics_free_inst(inst, _UPF_METR_BY_DNN_MAX);
|
|
}
|
|
|
|
void upf_metrics_init(void)
|
|
{
|
|
ogs_metrics_context_t *ctx = ogs_metrics_self();
|
|
ogs_metrics_context_init();
|
|
|
|
upf_metrics_init_spec(ctx, upf_metrics_spec_global, upf_metrics_spec_def_global,
|
|
_UPF_METR_GLOB_MAX);
|
|
upf_metrics_init_spec(ctx, upf_metrics_spec_by_qfi,
|
|
upf_metrics_spec_def_by_qfi, _UPF_METR_BY_QFI_MAX);
|
|
upf_metrics_init_spec(ctx, upf_metrics_spec_by_cause,
|
|
upf_metrics_spec_def_by_cause, _UPF_METR_BY_CAUSE_MAX);
|
|
upf_metrics_init_spec(ctx, upf_metrics_spec_by_dnn,
|
|
upf_metrics_spec_def_by_dnn, _UPF_METR_BY_DNN_MAX);
|
|
|
|
upf_metrics_init_inst_global();
|
|
upf_metrics_init_by_qfi();
|
|
upf_metrics_init_by_cause();
|
|
upf_metrics_init_by_dnn();
|
|
}
|
|
|
|
void upf_metrics_final(void)
|
|
{
|
|
ogs_hash_index_t *hi;
|
|
|
|
if (metrics_hash_by_qfi) {
|
|
for (hi = ogs_hash_first(metrics_hash_by_qfi); hi; hi = ogs_hash_next(hi)) {
|
|
upf_metric_key_by_qfi_t *key =
|
|
(upf_metric_key_by_qfi_t *)ogs_hash_this_key(hi);
|
|
//void *val = ogs_hash_this_val(hi);
|
|
|
|
ogs_hash_set(metrics_hash_by_qfi, key, sizeof(*key), NULL);
|
|
|
|
ogs_free(key);
|
|
/* don't free val (metric itself) -
|
|
* it will be free'd by ogs_metrics_context_final() */
|
|
//ogs_free(val);
|
|
}
|
|
ogs_hash_destroy(metrics_hash_by_qfi);
|
|
}
|
|
if (metrics_hash_by_cause) {
|
|
for (hi = ogs_hash_first(metrics_hash_by_cause); hi; hi = ogs_hash_next(hi)) {
|
|
upf_metric_key_by_cause_t *key =
|
|
(upf_metric_key_by_cause_t *)ogs_hash_this_key(hi);
|
|
//void *val = ogs_hash_this_val(hi);
|
|
|
|
ogs_hash_set(metrics_hash_by_cause, key, sizeof(*key), NULL);
|
|
|
|
ogs_free(key);
|
|
/* don't free val (metric itself) -
|
|
* it will be free'd by ogs_metrics_context_final() */
|
|
//ogs_free(val);
|
|
}
|
|
ogs_hash_destroy(metrics_hash_by_cause);
|
|
}
|
|
if (metrics_hash_by_dnn) {
|
|
for (hi = ogs_hash_first(metrics_hash_by_dnn); hi; hi = ogs_hash_next(hi)) {
|
|
upf_metric_key_by_dnn_t *key =
|
|
(upf_metric_key_by_dnn_t *)ogs_hash_this_key(hi);
|
|
//void *val = ogs_hash_this_val(hi);
|
|
|
|
ogs_hash_set(metrics_hash_by_dnn, key, sizeof(*key), NULL);
|
|
|
|
ogs_free(key);
|
|
/* don't free val (metric itself) -
|
|
* it will be free'd by ogs_metrics_context_final() */
|
|
//ogs_free(val);
|
|
}
|
|
ogs_hash_destroy(metrics_hash_by_dnn);
|
|
}
|
|
|
|
ogs_metrics_context_final();
|
|
}
|