[PGW] Gy+PFCP improvements (#1555)

* [SMF] Gy,PFCP: Improve {Time,Volume} {Threshold,Quota} handling

* [UPF] Implement URR Usage Report for ValidityTime/TimeQuota/TimeThreshold

* [UPF] Implement Usage report trigger for Volume Quota/Threshold

* [SMF] Set Gy Reporting-Reason based on PFCP Report Trigger
This commit is contained in:
Pau Espin 2022-05-24 15:54:30 +02:00 committed by GitHub
parent 2c2ce143a3
commit c18e9f32cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 304 additions and 88 deletions

View File

@ -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;
};

View File

@ -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;

View File

@ -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)
{

View File

@ -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
*

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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);
}
}
}