#include "ogs-app.h" #include "context.h" #include "metrics.h" typedef struct pcf_metrics_spec_def_s { unsigned int type; const char *name; const char *description; int initial_val; unsigned int num_labels; const char **labels; } pcf_metrics_spec_def_t; /* Helper generic functions: */ static int pcf_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 pcf_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 pcf_metrics_init_spec(ogs_metrics_context_t *ctx, ogs_metrics_spec_t **dst, pcf_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); } return OGS_OK; } /* GLOBAL */ ogs_metrics_spec_t *pcf_metrics_spec_global[_PCF_METR_GLOB_MAX]; ogs_metrics_inst_t *pcf_metrics_inst_global[_PCF_METR_GLOB_MAX]; pcf_metrics_spec_def_t pcf_metrics_spec_def_global[_PCF_METR_GLOB_MAX] = { /* Global Counters: */ /* Global Gauges: */ }; int pcf_metrics_init_inst_global(void) { return pcf_metrics_init_inst(pcf_metrics_inst_global, pcf_metrics_spec_global, _PCF_METR_GLOB_MAX, 0, NULL); } int pcf_metrics_free_inst_global(void) { return pcf_metrics_free_inst(pcf_metrics_inst_global, _PCF_METR_GLOB_MAX); } /* BY_PLMN */ const char *labels_plmn[] = { "plmnid" }; #define PCF_METR_BY_PLMN_CTR_ENTRY(_id, _name, _desc) \ [_id] = { \ .type = OGS_METRICS_METRIC_TYPE_COUNTER, \ .name = _name, \ .description = _desc, \ .num_labels = OGS_ARRAY_SIZE(labels_plmn), \ .labels = labels_plmn, \ }, ogs_metrics_spec_t *pcf_metrics_spec_by_plmn[_PCF_METR_BY_PLMN_MAX]; ogs_hash_t *metrics_hash_by_plmn = NULL; /* hash table for PLMN label */ pcf_metrics_spec_def_t pcf_metrics_spec_def_by_plmn[_PCF_METR_BY_PLMN_MAX] = { /* Counters: */ PCF_METR_BY_PLMN_CTR_ENTRY( PCF_METR_CTR_PA_POLICYAMASSOREQ, "fivegs_pcffunction_pa_policyamassoreq", "Number of AM policy association requests") PCF_METR_BY_PLMN_CTR_ENTRY( PCF_METR_CTR_PA_POLICYAMASSOSUCC, "fivegs_pcffunction_pa_policyamassosucc", "Number of successful AM policy associations") }; void pcf_metrics_init_by_plmn(void); int pcf_metrics_free_inst_by_plmn(ogs_metrics_inst_t **inst); typedef struct pcf_metric_key_by_plmn_s { ogs_plmn_id_t plmn_id; pcf_metric_type_by_plmn_t t; } pcf_metric_key_by_plmn_t; void pcf_metrics_init_by_plmn(void) { metrics_hash_by_plmn = ogs_hash_make(); ogs_assert(metrics_hash_by_plmn); } void pcf_metrics_inst_by_plmn_add(ogs_plmn_id_t *plmn, pcf_metric_type_by_plmn_t t, int val) { ogs_metrics_inst_t *metrics = NULL; pcf_metric_key_by_plmn_t *plmn_key; plmn_key = ogs_calloc(1, sizeof(*plmn_key)); ogs_assert(plmn_key); if (plmn) { plmn_key->plmn_id = *plmn; } plmn_key->t = t; metrics = ogs_hash_get(metrics_hash_by_plmn, plmn_key, sizeof(*plmn_key)); if (!metrics) { char plmn_id[OGS_PLMNIDSTRLEN] = ""; if (plmn) { ogs_plmn_id_to_string(plmn, plmn_id); } metrics = ogs_metrics_inst_new(pcf_metrics_spec_by_plmn[t], pcf_metrics_spec_def_by_plmn->num_labels, (const char *[]){ plmn_id }); ogs_assert(metrics); ogs_hash_set(metrics_hash_by_plmn, plmn_key, sizeof(*plmn_key), metrics); } else { ogs_free(plmn_key); } ogs_metrics_inst_add(metrics, val); } int pcf_metrics_free_inst_by_plmn(ogs_metrics_inst_t **inst) { return pcf_metrics_free_inst(inst, _PCF_METR_BY_PLMN_MAX); } /* BY_SLICE */ const char *labels_slice[] = { "plmnid", "snssai" }; #define PCF_METR_BY_SLICE_CTR_ENTRY(_id, _name, _desc) \ [_id] = { \ .type = OGS_METRICS_METRIC_TYPE_COUNTER, \ .name = _name, \ .description = _desc, \ .num_labels = OGS_ARRAY_SIZE(labels_slice), \ .labels = labels_slice, \ }, #define PCF_METR_BY_SLICE_GAUGE_ENTRY(_id, _name, _desc) \ [_id] = { \ .type = OGS_METRICS_METRIC_TYPE_GAUGE, \ .name = _name, \ .description = _desc, \ .num_labels = OGS_ARRAY_SIZE(labels_slice), \ .labels = labels_slice, \ }, ogs_metrics_spec_t *pcf_metrics_spec_by_slice[_PCF_METR_BY_SLICE_MAX]; ogs_hash_t *metrics_hash_by_slice = NULL; /* hash table for SLICE labels */ pcf_metrics_spec_def_t pcf_metrics_spec_def_by_slice[_PCF_METR_BY_SLICE_MAX] = { /* Counters: */ PCF_METR_BY_SLICE_CTR_ENTRY( PCF_METR_CTR_PA_POLICYSMASSOREQ, "fivegs_pcffunction_pa_policysmassoreq", "Number of SM policy association requests") PCF_METR_BY_SLICE_CTR_ENTRY( PCF_METR_CTR_PA_POLICYSMASSOSUCC, "fivegs_pcffunction_pa_policysmassosucc", "Number of successful SM policy associations") /* Gauges: */ PCF_METR_BY_SLICE_GAUGE_ENTRY( PCF_METR_GAUGE_PA_SESSIONNBR, "fivegs_pcffunction_pa_sessionnbr", "Active Sessions") }; void pcf_metrics_init_by_slice(void); int pcf_metrics_free_inst_by_slice(ogs_metrics_inst_t **inst); typedef struct pcf_metric_key_by_slice_s { ogs_plmn_id_t plmn_id; ogs_s_nssai_t snssai; pcf_metric_type_by_slice_t t; } pcf_metric_key_by_slice_t; void pcf_metrics_init_by_slice(void) { metrics_hash_by_slice = ogs_hash_make(); ogs_assert(metrics_hash_by_slice); } void pcf_metrics_inst_by_slice_add(ogs_plmn_id_t *plmn, ogs_s_nssai_t *snssai, pcf_metric_type_by_slice_t t, int val) { ogs_metrics_inst_t *metrics = NULL; pcf_metric_key_by_slice_t *slice_key; slice_key = ogs_calloc(1, sizeof(*slice_key)); ogs_assert(slice_key); if (plmn) { slice_key->plmn_id = *plmn; } if (snssai) { slice_key->snssai = *snssai; } else { slice_key->snssai.sst = 0; slice_key->snssai.sd.v = OGS_S_NSSAI_NO_SD_VALUE; } slice_key->t = t; metrics = ogs_hash_get(metrics_hash_by_slice, slice_key, sizeof(*slice_key)); if (!metrics) { char plmn_id[OGS_PLMNIDSTRLEN] = ""; char *s_nssai = NULL; if (plmn) { ogs_plmn_id_to_string(plmn, plmn_id); } if (snssai) { s_nssai = ogs_sbi_s_nssai_to_string_plain(snssai); } else { s_nssai = ogs_strdup(""); } metrics = ogs_metrics_inst_new(pcf_metrics_spec_by_slice[t], pcf_metrics_spec_def_by_slice->num_labels, (const char *[]){ plmn_id, s_nssai }); ogs_assert(metrics); ogs_hash_set(metrics_hash_by_slice, slice_key, sizeof(*slice_key), metrics); if (s_nssai) ogs_free(s_nssai); } else { ogs_free(slice_key); } ogs_metrics_inst_add(metrics, val); } int pcf_metrics_free_inst_by_slice(ogs_metrics_inst_t **inst) { return pcf_metrics_free_inst(inst, _PCF_METR_BY_SLICE_MAX); } void pcf_metrics_init(void) { ogs_metrics_context_t *ctx = ogs_metrics_self(); ogs_metrics_context_init(); pcf_metrics_init_spec(ctx, pcf_metrics_spec_global, pcf_metrics_spec_def_global, _PCF_METR_GLOB_MAX); pcf_metrics_init_spec(ctx, pcf_metrics_spec_by_plmn, pcf_metrics_spec_def_by_plmn, _PCF_METR_BY_PLMN_MAX); pcf_metrics_init_spec(ctx, pcf_metrics_spec_by_slice, pcf_metrics_spec_def_by_slice, _PCF_METR_BY_SLICE_MAX); pcf_metrics_init_inst_global(); pcf_metrics_init_by_plmn(); pcf_metrics_init_by_slice(); } void pcf_metrics_final(void) { ogs_hash_index_t *hi; if (metrics_hash_by_slice) { for (hi = ogs_hash_first(metrics_hash_by_slice); hi; hi = ogs_hash_next(hi)) { pcf_metric_key_by_slice_t *key = (pcf_metric_key_by_slice_t *)ogs_hash_this_key(hi); //void *val = ogs_hash_this_val(hi); ogs_hash_set(metrics_hash_by_slice, 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_slice); } if (metrics_hash_by_plmn) { for (hi = ogs_hash_first(metrics_hash_by_plmn); hi; hi = ogs_hash_next(hi)) { pcf_metric_key_by_plmn_t *key = (pcf_metric_key_by_plmn_t *)ogs_hash_this_key(hi); //void *val = ogs_hash_this_val(hi); ogs_hash_set(metrics_hash_by_plmn, key, sizeof(*key), NULL); ogs_free(key); /* don't free val (metric ifself) - * it will be free'd by ogs_metrics_context_final() */ //ogs_free(val); } ogs_hash_destroy(metrics_hash_by_plmn); } ogs_metrics_context_final(); }