diff --git a/lib/diameter/gy/message.h b/lib/diameter/gy/message.h index 36dae478b..6b06d5494 100644 --- a/lib/diameter/gy/message.h +++ b/lib/diameter/gy/message.h @@ -44,6 +44,8 @@ extern "C" { #define OGS_DIAM_GY_AVP_CODE_VALIDITY_TIME (448) #define OGS_DIAM_GY_AVP_CODE_MULTIPLE_SERVICES_CREDIT_CONTROL (456) #define OGS_DIAM_GY_AVP_CODE_SUPPORTED_FEATURES (628) +#define OGS_DIAM_GY_AVP_CODE_TIME_QUOTA_THRESHOLD (868) +#define OGS_DIAM_GY_AVP_CODE_VOLUME_QUOTA_THRESHOLD (869) #define OGS_DIAM_GY_AVP_CODE_CHARGING_RULE_BASE_NAME (1004) #define OGS_DIAM_GY_AVP_CODE_FLOW_INFORMATION (1058) #define OGS_DIAM_GY_AVP_CODE_QOS_INFORMATION (1016) @@ -182,6 +184,8 @@ typedef struct ogs_diam_gy_message_s { union { struct { uint32_t validity_time; + uint32_t time_threshold; + uint32_t volume_threshold; ogs_diam_gy_service_unit_t granted; } cca; }; diff --git a/lib/pfcp/build.c b/lib/pfcp/build.c index aa56508a3..b60dfc8da 100644 --- a/lib/pfcp/build.c +++ b/lib/pfcp/build.c @@ -654,7 +654,10 @@ void ogs_pfcp_build_update_urr( /* No change requested, skip. */ if (!(modify_flags & (OGS_PFCP_MODIFY_URR_MEAS_METHOD| OGS_PFCP_MODIFY_URR_REPORT_TRIGGER| + OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME| + OGS_PFCP_MODIFY_URR_VOLUME_QUOTA| OGS_PFCP_MODIFY_URR_VOLUME_THRESH| + OGS_PFCP_MODIFY_URR_TIME_QUOTA| OGS_PFCP_MODIFY_URR_TIME_THRESH))) return; diff --git a/lib/pfcp/types.c b/lib/pfcp/types.c index 366319e11..3a8775dad 100644 --- a/lib/pfcp/types.c +++ b/lib/pfcp/types.c @@ -449,6 +449,15 @@ int16_t ogs_pfcp_build_volume(ogs_tlv_octet_t *octet, return octet->len; } +void ogs_pfcp_parse_usage_report_trigger( + ogs_pfcp_usage_report_trigger_t *rep_trig, + ogs_pfcp_tlv_usage_report_trigger_t *tlv) +{ + rep_trig->reptri_5 = (tlv->u24 >> 16) & 0xff; + rep_trig->reptri_6 = (tlv->u24 >> 8) & 0xff; + rep_trig->reptri_7 = (tlv->u24) & 0xff; +} + int16_t ogs_pfcp_parse_volume( ogs_pfcp_volume_threshold_t *volume, ogs_tlv_octet_t *octet) { diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index 16bdc62c9..03ebd6dc5 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -1023,6 +1023,10 @@ ED6(uint8_t spare:3;, }; } __attribute__ ((packed)) ogs_pfcp_usage_report_trigger_t; +void ogs_pfcp_parse_usage_report_trigger( + ogs_pfcp_usage_report_trigger_t *rep_trig, + ogs_pfcp_tlv_usage_report_trigger_t *tlv); + /* * 8.2.42 Measurement Period * diff --git a/lib/pfcp/xact.h b/lib/pfcp/xact.h index 113b6048d..c1b857b37 100644 --- a/lib/pfcp/xact.h +++ b/lib/pfcp/xact.h @@ -102,8 +102,11 @@ typedef struct ogs_pfcp_xact_s { #define OGS_PFCP_MODIFY_URR ((uint64_t)1<<24) /* type of trigger */ #define OGS_PFCP_MODIFY_URR_MEAS_METHOD ((uint64_t)1<<25) #define OGS_PFCP_MODIFY_URR_REPORT_TRIGGER ((uint64_t)1<<26) -#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<27) -#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<28) +#define OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME ((uint64_t)1<<27) +#define OGS_PFCP_MODIFY_URR_VOLUME_QUOTA ((uint64_t)1<<28) +#define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<29) +#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<30) +#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<31) uint64_t modify_flags; diff --git a/src/smf/context.h b/src/smf/context.h index 0903fbf5a..eee32a941 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -336,6 +336,7 @@ typedef struct smf_sess_s { uint64_t ul_octets; uint64_t dl_octets; ogs_time_t duration; + uint32_t reporting_reason; /* OGS_DIAM_GY_REPORTING_REASON_* */ /* Snapshot of measurement when last report was sent: */ struct { uint64_t ul_octets; diff --git a/src/smf/gy-handler.c b/src/smf/gy-handler.c index af8b463a2..ea2347e39 100644 --- a/src/smf/gy-handler.c +++ b/src/smf/gy-handler.c @@ -24,55 +24,90 @@ #include "gy-handler.h" #include "binding.h" -static void urr_enable_total_volume_threshold(smf_sess_t *sess, ogs_pfcp_urr_t *urr, - uint64_t total_volume_threshold) +static void urr_update_volume(smf_sess_t *sess, ogs_pfcp_urr_t *urr, ogs_diam_gy_message_t *gy_message) { - ogs_debug("Adding CC Grant total_octets=%" PRIu64, total_volume_threshold); - urr->meas_method |= OGS_PFCP_MEASUREMENT_METHOD_VOLUME; - urr->rep_triggers.volume_threshold = 1; - urr->vol_threshold.tovol = 1; - urr->vol_threshold.total_volume = total_volume_threshold; - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.mnop) - urr->meas_info.mnop = 1; + if (gy_message->cca.granted.cc_total_octets_present || gy_message->cca.volume_threshold) { + urr->meas_method |= OGS_PFCP_MEASUREMENT_METHOD_VOLUME; + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.mnop) + urr->meas_info.mnop = 1; + } else { + urr->meas_method &= ~OGS_PFCP_MEASUREMENT_METHOD_VOLUME; + } + + /* Volume Quota */ + if (gy_message->cca.granted.cc_total_octets_present) { + ogs_debug("Adding Volume Quota total_octets=%" PRIu64, gy_message->cca.granted.cc_total_octets); + urr->rep_triggers.volume_quota = 1; + urr->vol_quota.tovol = 1; + urr->vol_quota.total_volume = gy_message->cca.granted.cc_total_octets; + } else { + urr->rep_triggers.volume_quota = 0; + urr->vol_quota.tovol = 0; + urr->vol_quota.total_volume = 0; + } + + /* Volume Threshold */ + if (gy_message->cca.volume_threshold) { + ogs_debug("Adding Volume Threshold total_octets=%" PRIu32, gy_message->cca.volume_threshold); + urr->rep_triggers.volume_threshold = 1; + urr->vol_threshold.tovol = 1; + urr->vol_threshold.total_volume = gy_message->cca.volume_threshold; + } else { + urr->rep_triggers.volume_threshold = 0; + urr->vol_threshold.tovol = 0; + urr->vol_threshold.total_volume = 0; + } } -static void urr_disable_total_volume_threshold(ogs_pfcp_urr_t *urr) +static void urr_update_time(smf_sess_t *sess, ogs_pfcp_urr_t *urr, ogs_diam_gy_message_t *gy_message) { - urr->meas_method &= ~OGS_PFCP_MEASUREMENT_METHOD_VOLUME; - urr->rep_triggers.volume_threshold = 0; - urr->vol_threshold.tovol = 0; - urr->vol_threshold.total_volume = 0; -} + uint32_t time_quota; -static void urr_update_total_volume_threshold(smf_sess_t *sess, ogs_pfcp_urr_t *urr, ogs_diam_gy_message_t *gy_message) -{ - if (gy_message->cca.granted.cc_total_octets_present) - urr_enable_total_volume_threshold(sess, urr, gy_message->cca.granted.cc_total_octets); - else - urr_disable_total_volume_threshold(urr); -} + if (sess->pfcp_node->up_function_features.vtime) { + if (gy_message->cca.validity_time > 0) { + urr->rep_triggers.quota_validity_time = 1; + urr->quota_validity_time = gy_message->cca.validity_time; + } else { + urr->rep_triggers.quota_validity_time = 0; + urr->quota_validity_time = 0; + } + time_quota = gy_message->cca.granted.cc_time_present ? gy_message->cca.granted.cc_time : 0; + } else { + /* Store Validity Time as Volume Quota (if not longer than Volume Quota) */ + if (gy_message->cca.validity_time && (gy_message->cca.granted.cc_time_present && gy_message->cca.granted.cc_time > 0)) + time_quota = (gy_message->cca.validity_time <= gy_message->cca.granted.cc_time) ? + gy_message->cca.validity_time : gy_message->cca.granted.cc_time; + else if (gy_message->cca.validity_time) + time_quota = gy_message->cca.validity_time; + else if (gy_message->cca.granted.cc_time_present && gy_message->cca.granted.cc_time > 0) + time_quota = gy_message->cca.granted.cc_time; + else + time_quota = 0; + } -static void urr_update_time_threshold(ogs_pfcp_urr_t *urr, ogs_diam_gy_message_t *gy_message) -{ - uint32_t time_threshold; - if (gy_message->cca.validity_time && (gy_message->cca.granted.cc_time_present && gy_message->cca.granted.cc_time > 0)) - time_threshold = (gy_message->cca.validity_time <= gy_message->cca.granted.cc_time) ? - gy_message->cca.validity_time : gy_message->cca.granted.cc_time; - else if (gy_message->cca.validity_time) - time_threshold = gy_message->cca.validity_time; - else if (gy_message->cca.granted.cc_time_present && gy_message->cca.granted.cc_time > 0) - time_threshold = gy_message->cca.granted.cc_time; - else - time_threshold = 0; - if (time_threshold) { - ogs_debug("Adding CC Grant time=%" PRIu32, time_threshold); + if (gy_message->cca.validity_time || time_quota || gy_message->cca.time_threshold) { urr->meas_method |= OGS_PFCP_MEASUREMENT_METHOD_DURATION; - urr->rep_triggers.time_threshold = 1; - urr->time_threshold = time_threshold; urr->meas_info.istm = 1; } else { + urr->meas_info.istm = 0; urr->meas_method &= ~OGS_PFCP_MEASUREMENT_METHOD_DURATION; + } + + if (time_quota) { + ogs_debug("Adding Time Quota secs=%" PRIu32, time_quota); + urr->rep_triggers.time_quota = 1; + urr->time_quota = time_quota; + } else { + urr->rep_triggers.time_quota = 0; + urr->time_quota = 0; + } + + if (gy_message->cca.time_threshold) { + ogs_debug("Adding Time Threshold secs=%" PRIu32, gy_message->cca.time_threshold); + urr->rep_triggers.time_threshold = 1; + urr->time_threshold = gy_message->cca.time_threshold; + } else { urr->rep_triggers.time_threshold = 0; urr->time_threshold = 0; } @@ -105,8 +140,8 @@ uint32_t smf_gy_handle_cca_initial_request( ogs_assert(bearer->urr); /* Configure based on what we received from OCS: */ - urr_update_time_threshold(bearer->urr, gy_message); - urr_update_total_volume_threshold(sess, bearer->urr, gy_message); + urr_update_time(sess, bearer->urr, gy_message); + urr_update_volume(sess, bearer->urr, gy_message); /* Associate acconting URR each direction PDR: */ ogs_pfcp_pdr_associate_urr(bearer->ul_pdr, bearer->urr); @@ -124,6 +159,9 @@ void smf_gy_handle_cca_update_request( uint64_t modify_flags = 0; ogs_pfcp_measurement_method_t prev_meas_method; ogs_pfcp_reporting_triggers_t prev_rep_triggers; + ogs_pfcp_quota_validity_time_t prev_quota_validity_time; + ogs_pfcp_volume_quota_t prev_vol_quota; + ogs_pfcp_time_quota_t prev_time_quota; ogs_pfcp_volume_threshold_t prev_vol_threshold; ogs_pfcp_time_threshold_t prev_time_threshold; @@ -151,19 +189,35 @@ void smf_gy_handle_cca_update_request( ogs_assert(urr); prev_meas_method = urr->meas_method; prev_rep_triggers = urr->rep_triggers; + prev_quota_validity_time = urr->quota_validity_time; + prev_vol_quota = urr->vol_quota; + prev_time_quota = urr->time_quota; prev_vol_threshold = urr->vol_threshold; prev_time_threshold = urr->time_threshold; - urr_update_time_threshold(urr, gy_message); - urr_update_total_volume_threshold(sess, urr, gy_message); + urr_update_time(sess, urr, gy_message); + urr_update_volume(sess, urr, gy_message); ogs_pfcp_pdr_associate_urr(bearer->ul_pdr, urr); if (urr->meas_method != prev_meas_method) modify_flags |= OGS_PFCP_MODIFY_URR_MEAS_METHOD; - if (urr->rep_triggers.time_threshold != prev_rep_triggers.time_threshold || + if (urr->rep_triggers.quota_validity_time != prev_rep_triggers.quota_validity_time || + urr->rep_triggers.time_quota != prev_rep_triggers.time_quota || + urr->rep_triggers.volume_quota != prev_rep_triggers.volume_quota || + urr->rep_triggers.time_threshold != prev_rep_triggers.time_threshold || urr->rep_triggers.volume_threshold != prev_rep_triggers.volume_threshold) modify_flags |= OGS_PFCP_MODIFY_URR_REPORT_TRIGGER; + if (urr->quota_validity_time != prev_quota_validity_time) + modify_flags |= OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME; + + if (urr->time_quota != prev_time_quota) + modify_flags |= OGS_PFCP_MODIFY_URR_TIME_QUOTA; + + if (urr->vol_quota.tovol != prev_vol_quota.tovol || + urr->vol_quota.total_volume != prev_vol_quota.total_volume) + modify_flags |= OGS_PFCP_MODIFY_URR_VOLUME_QUOTA; + if (urr->time_threshold != prev_time_threshold) modify_flags |= OGS_PFCP_MODIFY_URR_TIME_THRESH; diff --git a/src/smf/gy-path.c b/src/smf/gy-path.c index 710c1de76..0f8d721c5 100644 --- a/src/smf/gy-path.c +++ b/src/smf/gy-path.c @@ -114,18 +114,23 @@ static void fill_multiple_services_credit_control_ccr(smf_sess_t *sess, /* Reporting-Reason, TS 32.299 7.2.175 */ /* "values THRESHOLD, QUOTA_EXHAUSTED and OTHER_QUOTA_TYPE apply to one particular quota type and shall occur only in the Used-Service-Units AVP" */ -#if 0 - /* TODO: set when update is triggered by threshold from PFCP URR. Not yet supported. */ if (cc_request_type == OGS_DIAM_GY_CC_REQUEST_TYPE_UPDATE_REQUEST) { - ret = fd_msg_avp_new(ogs_diam_gy_reporting_reason, 0, &avpch2); - ogs_assert(ret == 0); - val.u32 = OGS_DIAM_GY_REPORTING_REASON_THRESHOLD; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); + switch (sess->gy.reporting_reason) { + case OGS_DIAM_GY_REPORTING_REASON_THRESHOLD: + case OGS_DIAM_GY_REPORTING_REASON_QUOTA_EXHAUSTED: + case OGS_DIAM_GY_REPORTING_REASON_OTHER_QUOTA_TYPE: + ret = fd_msg_avp_new(ogs_diam_gy_reporting_reason, 0, &avpch2); + ogs_assert(ret == 0); + val.u32 = sess->gy.reporting_reason; + ret = fd_msg_avp_setvalue (avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + break; + default: + break; + } } -#endif /* Tariff-Change-Usage */ @@ -176,19 +181,24 @@ static void fill_multiple_services_credit_control_ccr(smf_sess_t *sess, */ if (cc_request_type == OGS_DIAM_GY_CC_REQUEST_TYPE_UPDATE_REQUEST || cc_request_type == OGS_DIAM_GY_CC_REQUEST_TYPE_TERMINATION_REQUEST) { - ret = fd_msg_avp_new(ogs_diam_gy_reporting_reason, 0, &avpch1); - ogs_assert(ret == 0); - if (cc_request_type == OGS_DIAM_GY_CC_REQUEST_TYPE_UPDATE_REQUEST) { - val.u32 = OGS_DIAM_GY_REPORTING_REASON_VALIDITY_TIME; - /* TODO: do NOT set when update is triggered by threshold from - * PFCP URR (not yet supported) */ - } else { - val.u32 = OGS_DIAM_GY_REPORTING_REASON_FINAL; + switch (sess->gy.reporting_reason) { + case OGS_DIAM_GY_REPORTING_REASON_QHT: + case OGS_DIAM_GY_REPORTING_REASON_FINAL: + case OGS_DIAM_GY_REPORTING_REASON_FORCED_REAUTHORISATION: + case OGS_DIAM_GY_REPORTING_REASON_VALIDITY_TIME: + case OGS_DIAM_GY_REPORTING_REASON_RATING_CONDITION_CHANGE: + case OGS_DIAM_GY_REPORTING_REASON_UNUSED_QUOTA_TIMER: + ret = fd_msg_avp_new(ogs_diam_gy_reporting_reason, 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->gy.reporting_reason; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + break; + default: + break; } - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); } /* ... lots of AVPs ... */ @@ -1056,6 +1066,12 @@ static void smf_gy_cca_cb(void *data, struct msg **msg) case OGS_DIAM_GY_AVP_CODE_VALIDITY_TIME: gy_message->cca.validity_time = hdr->avp_value->u32; break; + case OGS_DIAM_GY_AVP_CODE_TIME_QUOTA_THRESHOLD: + gy_message->cca.time_threshold = hdr->avp_value->u32; + break; + case OGS_DIAM_GY_AVP_CODE_VOLUME_QUOTA_THRESHOLD: + gy_message->cca.volume_threshold = hdr->avp_value->u32; + break; default: ogs_warn("Not supported(%d)", hdr->avp_code); break; diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index c88482c41..66a367dbe 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -1074,6 +1074,7 @@ uint8_t smf_epc_n4_handle_session_deletion_response( &rsp->usage_report[i]; uint32_t urr_id; ogs_pfcp_volume_measurement_t volume; + ogs_pfcp_usage_report_trigger_t rep_trig; if (use_rep->presence == 0) break; if (use_rep->urr_id.presence == 0) @@ -1088,6 +1089,10 @@ uint8_t smf_epc_n4_handle_session_deletion_response( if (volume.dlvol) sess->gy.dl_octets += volume.downlink_volume; sess->gy.duration += use_rep->duration_measurement.u32; + ogs_pfcp_parse_usage_report_trigger( + &rep_trig, &use_rep->usage_report_trigger); + sess->gy.reporting_reason = + smf_pfcp_urr_usage_report_trigger2diam_gy_reporting_reason(&rep_trig); } return OGS_PFCP_CAUSE_REQUEST_ACCEPTED; @@ -1237,6 +1242,7 @@ void smf_n4_handle_session_report_request( &pfcp_req->usage_report[i]; uint32_t urr_id; ogs_pfcp_volume_measurement_t volume; + ogs_pfcp_usage_report_trigger_t rep_trig; if (use_rep->presence == 0) break; if (use_rep->urr_id.presence == 0) @@ -1251,6 +1257,10 @@ void smf_n4_handle_session_report_request( if (volume.dlvol) sess->gy.dl_octets += volume.downlink_volume; sess->gy.duration += use_rep->duration_measurement.u32; + ogs_pfcp_parse_usage_report_trigger( + &rep_trig, &use_rep->usage_report_trigger); + sess->gy.reporting_reason = + smf_pfcp_urr_usage_report_trigger2diam_gy_reporting_reason(&rep_trig); } switch(smf_use_gy_iface()) { case 1: diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index a3d326497..958df2c56 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -20,6 +20,45 @@ #include "sbi-path.h" #include "pfcp-path.h" +/* Converts PFCP "Usage Report" "Report Trigger" bitmask to Gy "Reporting-Reason" AVP enum value. + * PFCP: 3GPP TS 29.244 sec 8.2.41 + * Gy: 3GPP TS 32.299 sec 7.2.175 (OGS_DIAM_GY_REPORTING_REASON_*) */ +uint32_t smf_pfcp_urr_usage_report_trigger2diam_gy_reporting_reason(ogs_pfcp_usage_report_trigger_t *rep_trigger) +{ + + if (rep_trigger->termination_report || + rep_trigger->termination_by_up_function_report) + return OGS_DIAM_GY_REPORTING_REASON_FINAL; + + if (rep_trigger->time_threshold || + rep_trigger->volume_threshold) + return OGS_DIAM_GY_REPORTING_REASON_THRESHOLD; + + if (rep_trigger->time_quota || + rep_trigger->volume_quota || + rep_trigger->event_quota) + return OGS_DIAM_GY_REPORTING_REASON_QUOTA_EXHAUSTED; + + if (rep_trigger->quota_validity_time) + return OGS_DIAM_GY_REPORTING_REASON_VALIDITY_TIME; + + /* if (rep_trigger->immediate_report || + rep_trigger->dropped_dl_traffic_threshold || + rep_trigger->stop_of_traffic || + rep_trigger->start_of_traffic || + rep_trigger->quota_holding_time || + rep_trigger->periodic_reporting || + rep_trigger->event_threshold || + rep_trigger->mac_addresses_reporting || + rep_trigger->envelope_closure || + rep_trigger->monitoring_time || + rep_trigger->linked_usage_reporting || + rep_trigger->report_the_end_marker_reception || + rep_trigger->ip_multicast_join_leave + ) */ + return OGS_DIAM_GY_REPORTING_REASON_UNUSED_QUOTA_TIMER; +} + static void pfcp_node_fsm_init(ogs_pfcp_node_t *node, bool try_to_assoicate) { smf_event_t e; diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h index 2f023555d..a7a70180e 100644 --- a/src/smf/pfcp-path.h +++ b/src/smf/pfcp-path.h @@ -62,6 +62,9 @@ int smf_epc_pfcp_send_deactivation(smf_sess_t *sess, uint8_t gtp_cause); int smf_pfcp_send_session_report_response( ogs_pfcp_xact_t *xact, smf_sess_t *sess, uint8_t cause); +uint32_t smf_pfcp_urr_usage_report_trigger2diam_gy_reporting_reason( + ogs_pfcp_usage_report_trigger_t *rep_trigger); + #ifdef __cplusplus } #endif diff --git a/src/upf/context.c b/src/upf/context.c index 192559631..94d38fa99 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -43,7 +43,8 @@ void upf_context_init(void) ogs_pfcp_self()->up_function_features.ftup = 1; ogs_pfcp_self()->up_function_features.empu = 1; ogs_pfcp_self()->up_function_features.mnop = 1; - ogs_pfcp_self()->up_function_features_len = 3; + ogs_pfcp_self()->up_function_features.vtime = 1; + ogs_pfcp_self()->up_function_features_len = 4; ogs_list_init(&self.sess_list); ogs_pool_init(&upf_sess_pool, ogs_app()->pool.sess); @@ -406,6 +407,8 @@ uint8_t upf_sess_set_ue_ip(upf_sess_t *sess, void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bool is_uplink) { upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id]; + uint64_t vol; + /* Increment total & ul octets + pkts */ urr_acc->total_octets += size; urr_acc->total_pkts++; @@ -421,7 +424,21 @@ void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bo if (urr_acc->time_of_first_packet == 0) urr_acc->time_of_first_packet = urr_acc->time_of_last_packet; - /* TODO: generate report if volume threshold/quota is reached, eg sess->urr_acc[urr->id].total_octets - sess->urr_acc[urr->id].last_report.total_octets > threshold */ + /* generate report if volume threshold/quota is reached */ + vol = urr_acc->total_octets - urr_acc->last_report.total_octets; + if ((urr->rep_triggers.volume_quota && urr->vol_quota.tovol && vol >= urr->vol_quota.total_volume) || + (urr->rep_triggers.volume_threshold && urr->vol_threshold.tovol && vol >= urr->vol_threshold.total_volume)) { + ogs_pfcp_user_plane_report_t report; + memset(&report, 0, sizeof(report)); + upf_sess_urr_acc_fill_usage_report(sess, urr, &report, 0); + report.num_of_usage_report = 1; + upf_sess_urr_acc_snapshot(sess, urr); + + ogs_assert(OGS_OK == + upf_pfcp_send_session_report_request(sess, &report)); + /* Start new report period/iteration: */ + upf_sess_urr_acc_timers_setup(sess, urr); + } } /* report struct must be memzeroed before first use of this function. @@ -438,12 +455,12 @@ void upf_sess_urr_acc_fill_usage_report(upf_sess_t *sess, const ogs_pfcp_urr_t * if (urr_acc->last_report.timestamp) last_report_timestamp = urr_acc->last_report.timestamp; else - last_report_timestamp = ogs_time_from_ntp32(urr_acc->time_threshold_start); + last_report_timestamp = ogs_time_from_ntp32(urr_acc->time_start); report->type.usage_report = 1; report->usage_report[idx].id = urr->id; report->usage_report[idx].seqn = urr_acc->report_seqn++; - report->usage_report[idx].start_time = urr_acc->time_threshold_start; + report->usage_report[idx].start_time = urr_acc->time_start; report->usage_report[idx].end_time = ogs_time_to_ntp32(now); report->usage_report[idx].vol_measurement = (ogs_pfcp_volume_measurement_t){ .dlnop = 1, @@ -465,9 +482,24 @@ void upf_sess_urr_acc_fill_usage_report(upf_sess_t *sess, const ogs_pfcp_urr_t * report->usage_report[idx].time_of_first_packet = ogs_time_to_ntp32(urr_acc->time_of_first_packet); /* TODO: First since last report? */ report->usage_report[idx].time_of_last_packet = ogs_time_to_ntp32(urr_acc->time_of_last_packet); + /* Time triggers: */ + if (urr->quota_validity_time > 0 && + report->usage_report[idx].dur_measurement >= urr->quota_validity_time) + report->usage_report[idx].rep_trigger.quota_validity_time = 1; + if (urr->time_quota > 0 && + report->usage_report[idx].dur_measurement >= urr->time_quota) + report->usage_report[idx].rep_trigger.time_quota = 1; if (urr->time_threshold > 0 && report->usage_report[idx].dur_measurement >= urr->time_threshold) report->usage_report[idx].rep_trigger.time_threshold = 1; + + /* Volume triggers: */ + if (urr->rep_triggers.volume_quota && urr->vol_quota.tovol && + report->usage_report[idx].vol_measurement.total_volume >= urr->vol_quota.total_volume) + report->usage_report[idx].rep_trigger.volume_quota = 1; + if (urr->rep_triggers.volume_threshold && urr->vol_threshold.tovol && + report->usage_report[idx].vol_measurement.total_volume >= urr->vol_threshold.total_volume) + report->usage_report[idx].rep_trigger.volume_threshold = 1; } void upf_sess_urr_acc_snapshot(upf_sess_t *sess, ogs_pfcp_urr_t *urr) @@ -482,7 +514,7 @@ void upf_sess_urr_acc_snapshot(upf_sess_t *sess, ogs_pfcp_urr_t *urr) urr_acc->last_report.timestamp = ogs_time_now(); } -static void upf_sess_urr_acc_time_threshold_cb(void *data) +static void upf_sess_urr_acc_timers_cb(void *data) { ogs_pfcp_urr_t *urr = (ogs_pfcp_urr_t *)data; ogs_pfcp_user_plane_report_t report; @@ -491,7 +523,9 @@ static void upf_sess_urr_acc_time_threshold_cb(void *data) ogs_warn("upf_time_threshold_cb() triggered! urr=%p", urr); - if (urr->rep_triggers.time_threshold) { + if (urr->rep_triggers.quota_validity_time || + urr->rep_triggers.time_quota || + urr->rep_triggers.time_threshold) { memset(&report, 0, sizeof(report)); upf_sess_urr_acc_fill_usage_report(sess, urr, &report, 0); report.num_of_usage_report = 1; @@ -501,27 +535,64 @@ static void upf_sess_urr_acc_time_threshold_cb(void *data) upf_pfcp_send_session_report_request(sess, &report)); } /* Start new report period/iteration: */ - upf_sess_urr_acc_time_threshold_setup(sess, urr); + upf_sess_urr_acc_timers_setup(sess, urr); } -void upf_sess_urr_acc_time_threshold_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) +static void upf_sess_urr_acc_validity_time_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) { upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id]; - ogs_debug("Installing URR time threshold timer"); + ogs_debug("Installing URR Quota Validity Time timer"); + urr_acc->reporting_enabled = true; + if (!urr_acc->t_validity_time) + urr_acc->t_validity_time = ogs_timer_add(ogs_app()->timer_mgr, + upf_sess_urr_acc_timers_cb, urr); + ogs_timer_start(urr_acc->t_validity_time, urr->quota_validity_time * OGS_USEC_PER_SEC); +} +static void upf_sess_urr_acc_time_quota_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) +{ + upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id]; + + ogs_debug("Installing URR Time Quota timer"); + urr_acc->reporting_enabled = true; + if (!urr_acc->t_time_quota) + urr_acc->t_time_quota = ogs_timer_add(ogs_app()->timer_mgr, + upf_sess_urr_acc_timers_cb, urr); + ogs_timer_start(urr_acc->t_time_quota, urr->time_quota * OGS_USEC_PER_SEC); +} +static void upf_sess_urr_acc_time_threshold_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) +{ + upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id]; + + ogs_debug("Installing URR Time Threshold timer"); urr_acc->reporting_enabled = true; if (!urr_acc->t_time_threshold) urr_acc->t_time_threshold = ogs_timer_add(ogs_app()->timer_mgr, - upf_sess_urr_acc_time_threshold_cb, urr); - urr_acc->time_threshold_start = ogs_time_ntp32_now(); + upf_sess_urr_acc_timers_cb, urr); ogs_timer_start(urr_acc->t_time_threshold, urr->time_threshold * OGS_USEC_PER_SEC); } +void upf_sess_urr_acc_timers_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) +{ + upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id]; + urr_acc->time_start = ogs_time_ntp32_now(); + if (urr->rep_triggers.quota_validity_time && urr->quota_validity_time > 0) + upf_sess_urr_acc_validity_time_setup(sess, urr); + if (urr->rep_triggers.time_quota && urr->time_quota > 0) + upf_sess_urr_acc_time_quota_setup(sess, urr); + if (urr->rep_triggers.time_threshold && urr->time_threshold > 0) + upf_sess_urr_acc_time_threshold_setup(sess, urr); +} + static void upf_sess_urr_acc_remove_all(upf_sess_t *sess) { unsigned int i; for (i = 0; i < OGS_ARRAY_SIZE(sess->urr_acc); i++) { if (sess->urr_acc[i].t_time_threshold) { + ogs_timer_delete(sess->urr_acc[i].t_validity_time); + sess->urr_acc[i].t_validity_time = NULL; + ogs_timer_delete(sess->urr_acc[i].t_time_quota); + sess->urr_acc[i].t_time_quota = NULL; ogs_timer_delete(sess->urr_acc[i].t_time_threshold); sess->urr_acc[i].t_time_threshold = NULL; } diff --git a/src/upf/context.h b/src/upf/context.h index dba0b155c..03569c555 100644 --- a/src/upf/context.h +++ b/src/upf/context.h @@ -56,8 +56,10 @@ typedef struct upf_context_s { /* Accounting: */ typedef struct upf_sess_urr_acc_s { bool reporting_enabled; - ogs_timer_t *t_time_threshold; /* Time threshold expiration handler */ - uint32_t time_threshold_start; /* When t_time_threshold started */ + ogs_timer_t *t_validity_time; /* Quota Validity Time expiration handler */ + ogs_timer_t *t_time_quota; /* Time Quota expiration handler */ + ogs_timer_t *t_time_threshold; /* Time Threshold expiration handler */ + uint32_t time_start; /* When t_time_* started */ ogs_pfcp_urr_ur_seqn_t report_seqn; /* Next seqn to use when reporting */ uint64_t total_octets; uint64_t ul_octets; @@ -128,7 +130,7 @@ void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bo void upf_sess_urr_acc_fill_usage_report(upf_sess_t *sess, const ogs_pfcp_urr_t *urr, ogs_pfcp_user_plane_report_t *report, unsigned int idx); void upf_sess_urr_acc_snapshot(upf_sess_t *sess, ogs_pfcp_urr_t *urr); -void upf_sess_urr_acc_time_threshold_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr); +void upf_sess_urr_acc_timers_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr); #ifdef __cplusplus } diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index 327c13789..6396953a1 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -36,12 +36,9 @@ static void upf_n4_handle_create_urr(upf_sess_t *sess, ogs_pfcp_tlv_create_urr_t if (!urr) return; - /* TODO: here we should check for Reporting Triggers IMTH=1 instead? */ - if ((urr->meas_method & OGS_PFCP_MEASUREMENT_METHOD_DURATION) && urr->time_threshold > 0) { - /* if ISTM bit set in Measurement Information: */ - if (urr->meas_info.istm) { - upf_sess_urr_acc_time_threshold_setup(sess, urr); - } /* else: TODO: call upf_sess_urr_acc_time_threshold_setup() upon first pkt received */ + /* TODO: enable counters somewhere else if ISTM not set, upon first pkt received */ + if (urr->meas_info.istm) { + upf_sess_urr_acc_timers_setup(sess, urr); } } }