diff --git a/configs/open5gs/upf.yaml.in b/configs/open5gs/upf.yaml.in index eaac4a107..788f9e17d 100644 --- a/configs/open5gs/upf.yaml.in +++ b/configs/open5gs/upf.yaml.in @@ -164,6 +164,13 @@ logger: # dnn: ims # dev: ogstun3 # +# +# +# o Metrics Server(http://:9090) +# metrics: +# - addr: 0.0.0.0 +# port: 9090 +# upf: pfcp: - addr: 127.0.0.7 @@ -172,6 +179,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 # # smf: diff --git a/configs/sample.yaml.in b/configs/sample.yaml.in index 3661d77a1..fd5920e17 100644 --- a/configs/sample.yaml.in +++ b/configs/sample.yaml.in @@ -196,6 +196,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 hss: freeDiameter: diff --git a/configs/slice.yaml.in b/configs/slice.yaml.in index c5b7e0991..75c606834 100644 --- a/configs/slice.yaml.in +++ b/configs/slice.yaml.in @@ -166,6 +166,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 hss: freeDiameter: diff --git a/configs/srslte.yaml.in b/configs/srslte.yaml.in index 1d6f1871b..3c4aa1f2e 100644 --- a/configs/srslte.yaml.in +++ b/configs/srslte.yaml.in @@ -162,6 +162,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 hss: freeDiameter: diff --git a/configs/volte.yaml.in b/configs/volte.yaml.in index 39009b7af..600d2234a 100644 --- a/configs/volte.yaml.in +++ b/configs/volte.yaml.in @@ -165,6 +165,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 hss: freeDiameter: diff --git a/configs/vonr.yaml.in b/configs/vonr.yaml.in index fdca4d62d..60e488868 100644 --- a/configs/vonr.yaml.in +++ b/configs/vonr.yaml.in @@ -165,6 +165,9 @@ upf: subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 + metrics: + - addr: 127.0.0.7 + port: 9090 hss: freeDiameter: diff --git a/src/upf/context.c b/src/upf/context.c index dd7885dff..f9ae0c93a 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -132,6 +132,8 @@ int upf_context_parse_config(void) /* handle config in pfcp library */ } else if (!strcmp(upf_key, "subnet")) { /* handle config in pfcp library */ + } else if (!strcmp(upf_key, "metrics")) { + /* handle config in metrics library */ } else ogs_warn("unknown key `%s`", upf_key); } @@ -174,6 +176,7 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid) sizeof(sess->smf_n4_f_seid.seid), sess); ogs_list_add(&self.sess_list, sess); + upf_metrics_inst_global_inc(UPF_METR_GLOB_GAUGE_UPF_SESSIONNBR); ogs_info("[Added] Number of UPF-Sessions is now %d", ogs_list_count(&self.sess_list)); @@ -208,6 +211,7 @@ int upf_sess_remove(upf_sess_t *sess) ogs_pfcp_pool_final(&sess->pfcp); ogs_pool_free(&upf_sess_pool, sess); + upf_metrics_inst_global_dec(UPF_METR_GLOB_GAUGE_UPF_SESSIONNBR); ogs_info("[Removed] Number of UPF-sessions is now %d", ogs_list_count(&self.sess_list)); diff --git a/src/upf/context.h b/src/upf/context.h index 03569c555..6fa846219 100644 --- a/src/upf/context.h +++ b/src/upf/context.h @@ -34,6 +34,7 @@ #include "timer.h" #include "upf-sm.h" +#include "metrics.h" #ifdef __cplusplus extern "C" { diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index 35a1d8314..46f4799b3 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -184,6 +184,10 @@ static void _gtpv1_tun_recv_common_cb( ogs_assert(true == ogs_pfcp_up_handle_pdr( pdr, OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_GTP_OUTDATAPKTN3UPF); + upf_metrics_inst_by_qfi_add(pdr->qer->qfi, + UPF_METR_CTR_GTP_OUTDATAVOLUMEQOSLEVELN3UPF, recvbuf->len); + if (report.type.downlink_data_report) { ogs_assert(pdr->sess); sess = UPF_SESS(pdr->sess); @@ -361,6 +365,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ip_h = (struct ip *)pkbuf->data; ogs_assert(ip_h); + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF); + upf_metrics_inst_by_qfi_add(qfi, + UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF, pkbuf->len); + pfcp_object = ogs_pfcp_object_find_by_teid(teid); if (!pfcp_object) { /* TODO : Send Error Indication */ diff --git a/src/upf/init.c b/src/upf/init.c index 92d38014a..2e80a02f3 100644 --- a/src/upf/init.c +++ b/src/upf/init.c @@ -20,6 +20,7 @@ #include "context.h" #include "gtp-path.h" #include "pfcp-path.h" +#include "metrics.h" static ogs_thread_t *thread; static void upf_main(void *data); @@ -33,6 +34,7 @@ int upf_initialize() ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_pfcp_context_init(); + ogs_metrics_context_init(); upf_context_init(); upf_event_init(); upf_gtp_init(); @@ -46,9 +48,15 @@ int upf_initialize() rv = ogs_pfcp_context_parse_config("upf", "smf"); if (rv != OGS_OK) return rv; + rv = ogs_metrics_context_parse_config("upf"); + if (rv != OGS_OK) return rv; + rv = upf_context_parse_config(); if (rv != OGS_OK) return rv; + rv = upf_metrics_open(); + if (rv != 0) return OGS_ERROR; + rv = ogs_log_config_domain( ogs_app()->logger.domain, ogs_app()->logger.level); if (rv != OGS_OK) return rv; @@ -85,6 +93,8 @@ void upf_terminate(void) ogs_pfcp_context_final(); ogs_gtp_context_final(); + upf_metrics_close(); + ogs_metrics_context_final(); ogs_pfcp_xact_final(); diff --git a/src/upf/meson.build b/src/upf/meson.build index c84bf1f0b..81500689b 100644 --- a/src/upf/meson.build +++ b/src/upf/meson.build @@ -48,6 +48,7 @@ libupf_sources = files(''' rule-match.h event.h timer.h + metrics.h context.h upf-sm.h gtp-path.h @@ -57,6 +58,7 @@ libupf_sources = files(''' rule-match.c init.c + metrics.c event.c timer.c context.c @@ -86,6 +88,7 @@ libarp_nd_dep = declare_dependency( libupf = static_library('upf', sources : libupf_sources, dependencies : [ + libmetrics_dep, libpfcp_dep, libtun_dep, libarp_nd_dep, @@ -95,6 +98,7 @@ libupf = static_library('upf', libupf_dep = declare_dependency( link_with : libupf, dependencies : [ + libmetrics_dep, libpfcp_dep, libtun_dep, libarp_nd_dep, diff --git a/src/upf/metrics.c b/src/upf/metrics.c new file mode 100644 index 000000000..3949062af --- /dev/null +++ b/src/upf/metrics.c @@ -0,0 +1,394 @@ +#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); + } + 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", +}, +}; +static 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); +} +static 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) { + strcpy(dnn_key->dnn, dnn); + } 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); +} + +int upf_metrics_open(void) +{ + ogs_metrics_context_t *ctx = ogs_metrics_self(); + ogs_metrics_context_open(ctx); + + 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(); + + return 0; +} + +int upf_metrics_close(void) +{ + ogs_hash_index_t *hi; + ogs_metrics_context_t *ctx = ogs_metrics_self(); + upf_metrics_free_inst_global(); + + 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_close(ctx); + return OGS_OK; +} diff --git a/src/upf/metrics.h b/src/upf/metrics.h new file mode 100644 index 000000000..ebd579671 --- /dev/null +++ b/src/upf/metrics.h @@ -0,0 +1,66 @@ +#ifndef UPF_METRICS_H +#define UPF_METRICS_H + +#include "ogs-metrics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* GLOBAL */ +typedef enum upf_metric_type_global_s { + UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF = 0, + UPF_METR_GLOB_CTR_GTP_OUTDATAPKTN3UPF, + UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ, + UPF_METR_GLOB_CTR_SM_N4SESSIONREPORT, + UPF_METR_GLOB_CTR_SM_N4SESSIONREPORTSUCC, + UPF_METR_GLOB_GAUGE_UPF_SESSIONNBR, + _UPF_METR_GLOB_MAX, +} upf_metric_type_global_t; +extern ogs_metrics_inst_t *upf_metrics_inst_global[_UPF_METR_GLOB_MAX]; + +static inline void upf_metrics_inst_global_set(upf_metric_type_global_t t, int val) +{ ogs_metrics_inst_set(upf_metrics_inst_global[t], val); } +static inline void upf_metrics_inst_global_add(upf_metric_type_global_t t, int val) +{ ogs_metrics_inst_add(upf_metrics_inst_global[t], val); } +static inline void upf_metrics_inst_global_inc(upf_metric_type_global_t t) +{ ogs_metrics_inst_inc(upf_metrics_inst_global[t]); } +static inline void upf_metrics_inst_global_dec(upf_metric_type_global_t t) +{ ogs_metrics_inst_dec(upf_metrics_inst_global[t]); } + +/* BY QFI */ +typedef enum upf_metric_type_by_qfi_s { + UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF = 0, + UPF_METR_CTR_GTP_OUTDATAVOLUMEQOSLEVELN3UPF, + _UPF_METR_BY_QFI_MAX, +} upf_metric_type_by_qfi_t; + +void upf_metrics_inst_by_qfi_add( + uint8_t qfi, upf_metric_type_by_qfi_t t, int val); + +/* BY CAUSE */ +typedef enum upf_metric_type_by_cause_s { + UPF_METR_CTR_SM_N4SESSIONESTABFAIL = 0, + _UPF_METR_BY_CAUSE_MAX, +} upf_metric_type_by_cause_t; + +void upf_metrics_inst_by_cause_add( + uint8_t cause, upf_metric_type_by_cause_t t, int val); + +/* BY DNN */ +typedef enum upf_metric_type_by_dnn_s { + UPF_METR_GAUGE_UPF_QOSFLOWS = 0, + _UPF_METR_BY_DNN_MAX, +} upf_metric_type_by_dnn_t; + +void upf_metrics_inst_by_dnn_add( + char *dnn, upf_metric_type_by_dnn_t t, int val); + +int upf_metrics_open(void); +int upf_metrics_close(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_METRICS_H */ diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index cbfe63c4f..d11f7034b 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -55,6 +55,8 @@ void upf_n4_handle_session_establishment_request( uint8_t offending_ie_value = 0; int i; + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ); + ogs_assert(xact); ogs_assert(req); @@ -67,6 +69,8 @@ void upf_n4_handle_session_establishment_request( ogs_pfcp_send_error_message(xact, 0, OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, OGS_PFCP_CAUSE_MANDATORY_IE_MISSING, 0); + upf_metrics_inst_by_cause_add(OGS_PFCP_CAUSE_MANDATORY_IE_MISSING, + UPF_METR_CTR_SM_N4SESSIONESTABFAIL, 1); return; } @@ -96,6 +100,13 @@ void upf_n4_handle_session_establishment_request( if (ogs_pfcp_handle_create_qer(&sess->pfcp, &req->create_qer[i], &cause_value, &offending_ie_value) == NULL) break; + if (req->apn_dnn.presence == 1) { + upf_metrics_inst_by_dnn_add(req->apn_dnn.data, + UPF_METR_GAUGE_UPF_QOSFLOWS, 1); + } else { + upf_metrics_inst_by_dnn_add(NULL, + UPF_METR_GAUGE_UPF_QOSFLOWS, 1); + } } if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; @@ -202,6 +213,8 @@ void upf_n4_handle_session_establishment_request( return; cleanup: + upf_metrics_inst_by_cause_add(cause_value, + UPF_METR_CTR_SM_N4SESSIONESTABFAIL, 1); ogs_pfcp_sess_clear(&sess->pfcp); ogs_pfcp_send_error_message(xact, sess ? sess->smf_n4_f_seid.seid : 0, OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, @@ -329,6 +342,8 @@ void upf_n4_handle_session_modification_request( if (ogs_pfcp_handle_create_qer(&sess->pfcp, &req->create_qer[i], &cause_value, &offending_ie_value) == NULL) break; + upf_metrics_inst_by_dnn_add(NULL, + UPF_METR_GAUGE_UPF_QOSFLOWS, 1); } if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; @@ -345,6 +360,8 @@ void upf_n4_handle_session_modification_request( if (ogs_pfcp_handle_remove_qer(&sess->pfcp, &req->remove_qer[i], &cause_value, &offending_ie_value) == false) break; + upf_metrics_inst_by_dnn_add(NULL, + UPF_METR_GAUGE_UPF_QOSFLOWS, -1); } if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; @@ -455,6 +472,9 @@ void upf_n4_handle_session_deletion_request( upf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_deletion_request_t *req) { + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_qer_t *qer = NULL; + ogs_assert(xact); ogs_assert(req); @@ -468,6 +488,14 @@ void upf_n4_handle_session_deletion_request( return; } upf_pfcp_send_session_deletion_response(xact, sess); + + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + ogs_list_for_each(&sess->pfcp.qer_list, qer) { + upf_metrics_inst_by_dnn_add(NULL, + UPF_METR_GAUGE_UPF_QOSFLOWS, -1); + } + break; + } upf_sess_remove(sess); } @@ -504,5 +532,8 @@ void upf_n4_handle_session_report_response( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { ogs_error("Cause request not accepted[%d]", cause_value); return; + } else { + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONREPORTSUCC); } + } diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index 2b188d2e7..f4b74efc1 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -268,6 +268,8 @@ int upf_pfcp_send_session_report_request( ogs_pfcp_header_t h; ogs_pfcp_xact_t *xact = NULL; + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONREPORT); + ogs_assert(sess); ogs_assert(report);