Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support setting charging rule in PCC by webconsole #12

Merged
merged 25 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4e456ff
support setting charging rule in PCC by webconsole
Mar 28, 2023
520f9b9
change charging reference
Apr 18, 2023
8047a84
update charging data collection
May 23, 2023
1cb282a
update pdu charging data filter
May 26, 2023
b72d5a0
refactor: createSMPolicyProcedure
ianchen0119 Aug 15, 2023
1254610
fix ci error
ianchen0119 Aug 15, 2023
8d2fbe5
createSMPolicyProcedure: handle charging only when no error
ianchen0119 Aug 16, 2023
feb818b
fix ci error
ianchen0119 Aug 16, 2023
db01dfe
add nil check on chargingInterface
ianchen0119 Aug 17, 2023
fac3082
fix: Case-insensitive in pcf_util.go
brianchennn Oct 3, 2023
a0f876f
update GetSMPolicyDnnData()
ianchen0119 Oct 3, 2023
db9a244
fix: qfi -> qosRef
brianchennn Oct 4, 2023
cffd6fd
change var name: dest -> tokens
brianchennn Oct 4, 2023
179d48f
fix: rating group is not match
ianchen0119 Oct 11, 2023
562eb1a
fix linter error
brianchennn Oct 12, 2023
748d036
fix: port handling in IP Filter
brianchennn Oct 12, 2023
7605465
fix: flow description's destination IP can only accept string "assigned"
brianchennn Nov 23, 2023
0928704
if port range is 1-65535, omit port range
brianchennn Nov 23, 2023
48713c3
fix: use case-insensitive mongoapi
brianchennn Nov 24, 2023
63d974e
Use Strength = 2 (cas-insensitive) when query to MongoDB
brianchennn Nov 27, 2023
666d21a
update util's hash
brianchennn Nov 27, 2023
671432c
add tracelog
brianchennn Dec 4, 2023
32d2f0e
move RatingGroupIdGenerator to pcf_context
brianchennn Dec 12, 2023
9bd661a
Fix: rebase and fix linter
andy89923 Dec 27, 2023
23453bb
Fix: remove unused code
andy89923 Feb 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/cydev/zero v0.0.0-20160322155811-4a4535dd56e7
github.com/free5gc/openapi v1.0.7
github.com/free5gc/util v1.0.5
github.com/free5gc/util v1.0.5-0.20231219085815-8972321e9748
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/free5gc/openapi v1.0.7 h1:I0HOgqRgER6DbyqB6EBxusmbeouIhcOn4eOJvL3veJA=
github.com/free5gc/openapi v1.0.7/go.mod h1:qv9KqEucoZSeENPRFGxfTe+33ZWYyiYFx1Rj+H0DoWA=
github.com/free5gc/util v1.0.5 h1:MjyEIX6gGbdS8FUAOxhE0FsMD6pmv5T+45LjBabVhS8=
github.com/free5gc/util v1.0.5/go.mod h1:jgiW/bNbNbX87CSTKXyfvkhQeDY9ThK+TtWTu4ILCS8=
github.com/free5gc/util v1.0.5-0.20231219085815-8972321e9748 h1:zx+0hkvsdwje0a3wPDz3gt9trLBRXUwpeHfQMWGY4MA=
github.com/free5gc/util v1.0.5-0.20231219085815-8972321e9748/go.mod h1:jgiW/bNbNbX87CSTKXyfvkhQeDY9ThK+TtWTu4ILCS8=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
Expand Down
4 changes: 4 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type PCFContext struct {
// lock
DefaultUdrURILock sync.RWMutex

// Charging
RatingGroupIdGenerator *idgenerator.IDGenerator

OAuth2Required bool
}

Expand Down Expand Up @@ -153,6 +156,7 @@ func Init() {
pcfContext.PcfServiceUris = make(map[models.ServiceName]string)
pcfContext.PcfSuppFeats = make(map[models.ServiceName]openapi.SupportedFeature)
pcfContext.BdtPolicyIDGenerator = idgenerator.NewGenerator(1, math.MaxInt64)
pcfContext.RatingGroupIdGenerator = idgenerator.NewGenerator(1, math.MaxInt64)
InitpcfContext(&pcfContext)
}

Expand Down
2 changes: 2 additions & 0 deletions internal/context/ue.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type UeSmPolicyData struct {
PackFiltIdGenerator int32
PccRuleIdGenerator int32
ChargingIdGenerator int32

// FlowMapsToPackFiltIds map[string][]string // use Flow Description(in TS 29214) as key map to pcc rule ids
PackFiltMapToPccRuleId map[string]string // use PackFiltId as Key
// Related to GBR
Expand Down Expand Up @@ -156,6 +157,7 @@ func (ue *UeContext) NewUeSmPolicyData(
// data.RefToAmPolicy = amData
data.PccRuleIdGenerator = 1
data.ChargingIdGenerator = 1

data.PcfUe = ue
ue.SmPolicyData[key] = &data
data.InfluenceDataToPccRule = make(map[string]string)
Expand Down
2 changes: 1 addition & 1 deletion internal/sbi/consumer/influenceDataSubscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func RemoveInfluenceDataSubscription(ue *pcf_context.UeContext, subscriptionID s
}()
if httpResp.Status != localErr.Error() {
err = localErr
return nil, err
return problemDetails, err
}
problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
problemDetails = &problem
Expand Down
165 changes: 152 additions & 13 deletions internal/sbi/producer/smpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import (
"github.com/free5gc/pcf/internal/logger"
"github.com/free5gc/pcf/internal/sbi/consumer"
"github.com/free5gc/pcf/internal/util"
"github.com/free5gc/util/flowdesc"
"github.com/free5gc/util/httpwrapper"
"github.com/free5gc/util/mongoapi"
)

const (
flowRuleDataColl = "policyData.ues.flowRule"
qosFlowDataColl = "policyData.ues.qosFlow"
chargingDataColl = "policyData.ues.chargingData"
)

// SmPoliciesPost -
Expand All @@ -48,7 +50,7 @@ func HandleCreateSmPolicyRequest(request *httpwrapper.Request) *httpwrapper.Resp

func newQosDataWithQosFlowMap(qosFlow map[string]interface{}) *models.QosData {
qosData := &models.QosData{
QosId: strconv.Itoa(int(qosFlow["qfi"].(float64))),
QosId: strconv.Itoa(int(qosFlow["qosRef"].(float64))),
Qnc: false,
Var5qi: int32(qosFlow["5qi"].(float64)),
}
Expand All @@ -72,6 +74,7 @@ func createSMPolicyProcedure(request models.SmPolicyContextData) (
header http.Header, response *models.SmPolicyDecision, problemDetails *models.ProblemDetails,
) {
var err error
queryStrength := 2 // 2: case-insensitive, 3: case-sensitive
logger.SmPolicyLog.Tracef("Handle Create SM Policy Request")

if request.Supi == "" || request.SliceInfo == nil || len(request.SliceInfo.Sd) != 6 {
Expand Down Expand Up @@ -207,7 +210,7 @@ func createSMPolicyProcedure(request models.SmPolicyContextData) (
}

filter := bson.M{"ueId": ue.Supi, "snssai": util.SnssaiModelsToHex(*request.SliceInfo), "dnn": request.Dnn}
qosFlowInterface, err := mongoapi.RestfulAPIGetMany(qosFlowDataColl, filter)
qosFlowInterface, err := mongoapi.RestfulAPIGetMany(qosFlowDataColl, filter, queryStrength)
if err != nil {
logger.SmPolicyLog.Errorf("createSMPolicyProcedure error: %+v", err)
}
Expand All @@ -222,22 +225,158 @@ func createSMPolicyProcedure(request models.SmPolicyContextData) (
}

// get flow rules from databases
flowRulesInterface, err := mongoapi.RestfulAPIGetMany(flowRuleDataColl, filter)
flowRulesInterface, err := mongoapi.RestfulAPIGetMany(flowRuleDataColl, filter, queryStrength)
if err != nil {
logger.SmPolicyLog.Errorf("createSMPolicyProcedure error: %+v", err)
}

for _, flowRule := range flowRulesInterface {
pcc := util.CreateDefaultPccRules(smPolicyData.PccRuleIdGenerator)
smPolicyData.PccRuleIdGenerator++

filterCharging := bson.M{
"ueId": ue.Supi,
"snssai": util.SnssaiModelsToHex(*request.SliceInfo),
"dnn": "",
"filter": "",
}

chargingInterface, err := mongoapi.RestfulAPIGetOne(chargingDataColl, filterCharging, queryStrength)

if err != nil {
logger.SmPolicyLog.Errorf("Fail to get charging data to mongoDB err: %+v", err)
logger.SmPolicyLog.Errorf("chargingInterface %+v", chargingInterface)
util.SetPccRuleRelatedData(&decision, pcc, nil, nil, nil, nil)
} else if chargingInterface != nil {
rg, err1 := pcf_context.GetSelf().RatingGroupIdGenerator.Allocate()
if err1 != nil {
logger.SmPolicyLog.Error("rating group allocate error")
problemDetails := util.GetProblemDetail("rating group allocate error", util.ERROR_IDGENERATOR)
return nil, nil, &problemDetails
}
chgData := &models.ChargingData{
ChgId: util.GetChgId(smPolicyData.ChargingIdGenerator),
RatingGroup: int32(rg),
ReportingLevel: models.ReportingLevel_RAT_GR_LEVEL,
MeteringMethod: models.MeteringMethod_VOLUME,
}

switch chargingInterface["chargingMethod"].(string) {
case "Online":
chgData.Online = true
chgData.Offline = false
case "Offline":
chgData.Online = false
chgData.Offline = true
}
util.SetPccRuleRelatedData(&decision, pcc, nil, nil, chgData, nil)

chargingBsonM := bson.M{
"ratingGroup": chgData.RatingGroup,
}
logger.SmPolicyLog.Traceln("put ratingGroup to MongoDB")
if _, err = mongoapi.RestfulAPIPutOne(chargingDataColl, filterCharging, chargingBsonM, queryStrength); err != nil {
logger.SmPolicyLog.Errorf("Fail to put charging data to mongoDB err: %+v", err)
}

smPolicyData.ChargingIdGenerator++
}

logger.SmPolicyLog.Traceln("FlowRules for ueId:", ue.Supi, "snssai:", util.SnssaiModelsToHex(*request.SliceInfo))
for i, flowRule := range flowRulesInterface {
logger.SmPolicyLog.Tracef("flowRule %d: %s\n", i, openapi.MarshToJsonString(flowRule))
precedence := int32(flowRule["precedence"].(float64))
pccRule := util.CreatePccRule(smPolicyData.PccRuleIdGenerator, precedence, []models.FlowInformation{
{
FlowDescription: flowRule["filter"].(string),
FlowDirection: models.FlowDirectionRm_BIDIRECTIONAL,
},
}, "")
qfi := strconv.Itoa(int(flowRule["qfi"].(float64)))
util.SetPccRuleRelatedByQFI(&decision, pccRule, qfi)
smPolicyData.PccRuleIdGenerator++
if val, ok := flowRule["filter"].(string); ok {
tokens := strings.Split(val, " ")

FlowDescription := flowdesc.NewIPFilterRule()
FlowDescription.Action = flowdesc.Permit
FlowDescription.Dir = flowdesc.Out
FlowDescription.Src = tokens[0]
FlowDescription.Dst = "assigned" // Hardcode destination (TS 29.212 5.4.2)

var err1, err2 error
portLowerBound := 1
portUpperBound := 65535
if len(tokens) > 1 {
portLowerBound, err1 = strconv.Atoi(strings.Split(tokens[1], "-")[0])
portUpperBound, err2 = strconv.Atoi(strings.Split(tokens[1], "-")[1])
}

if err1 != nil || err2 != nil {
logger.SmPolicyLog.Warnln("Wrong Port format in IP Filter's setting:", tokens[1], ", set to 1-65535")
}

if !(portLowerBound <= 1 && portUpperBound >= 65535) { // Port range need to be assigned
FlowDescription.SrcPorts = flowdesc.PortRanges{
flowdesc.PortRange{
Start: uint16(portLowerBound),
End: uint16(portUpperBound),
},
}
}

var FlowDescriptionStr string
FlowDescriptionStr, err = flowdesc.Encode(FlowDescription)
if err != nil {
logger.SmPolicyLog.Errorf("Error occurs when encoding flow despcription: %s\n", err)
}

pccRule := util.CreatePccRule(smPolicyData.PccRuleIdGenerator, precedence, []models.FlowInformation{
{
FlowDescription: FlowDescriptionStr,
FlowDirection: models.FlowDirectionRm_DOWNLINK,
},
}, "")

filterCharging := bson.M{
"ueId": ue.Supi, "snssai": util.SnssaiModelsToHex(*request.SliceInfo),
"dnn": request.Dnn, "filter": val,
}
var chargingInterface map[string]interface{}
chargingInterface, err = mongoapi.RestfulAPIGetOne(chargingDataColl, filterCharging, 2)
if err != nil {
logger.SmPolicyLog.Errorf("Fail to get charging data to mongoDB err: %+v", err)
} else {
rg, err1 := pcf_context.GetSelf().RatingGroupIdGenerator.Allocate()
if err1 != nil {
logger.SmPolicyLog.Error("rating group allocate error")
problemDetails := util.GetProblemDetail("rating group allocate error", util.ERROR_IDGENERATOR)
return nil, nil, &problemDetails
}
chgData := &models.ChargingData{
ChgId: util.GetChgId(smPolicyData.ChargingIdGenerator),
RatingGroup: int32(rg),
ReportingLevel: models.ReportingLevel_RAT_GR_LEVEL,
MeteringMethod: models.MeteringMethod_VOLUME,
}

switch chargingInterface["chargingMethod"].(string) {
case "Online":
chgData.Online = true
chgData.Offline = false
case "Offline":
chgData.Online = false
chgData.Offline = true
}

if decision.ChgDecs == nil {
decision.ChgDecs = make(map[string]*models.ChargingData)
}

chargingBsonM := bson.M{
"ratingGroup": chgData.RatingGroup,
}
if _, err = mongoapi.RestfulAPIPutOne(chargingDataColl, filterCharging, chargingBsonM, queryStrength); err != nil {
logger.SmPolicyLog.Errorf("Fail to put charging data to mongoDB err: %+v", err)
} else {
util.SetPccRuleRelatedData(&decision, pccRule, nil, nil, chgData, nil)
smPolicyData.ChargingIdGenerator++
}
}
qosRef := strconv.Itoa(int(flowRule["qosRef"].(float64)))
util.SetPccRuleRelatedByQosRef(&decision, pccRule, qosRef)
smPolicyData.PccRuleIdGenerator++
}
}

requestSuppFeat, err := openapi.NewSupportedFeature(request.SuppFeat)
Expand Down
14 changes: 3 additions & 11 deletions internal/util/pcc_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ func CreateDefaultPccRules(id int32) *models.PccRule {
PacketFilterUsage: true,
PackFiltId: "PackFiltId-0",
},
{
FlowDescription: "permit out ip from any to assigned",
FlowDirection: models.FlowDirectionRm_DOWNLINK,
PacketFilterUsage: true,
PackFiltId: "PackFiltId-1",
},
}
return CreatePccRule(id, 255, flowInfo, "")
}
Expand Down Expand Up @@ -176,13 +170,11 @@ func GetPccRuleByFlowInfos(pccRules map[string]*models.PccRule, flowInfos []mode
return nil
}

func SetPccRuleRelatedByQFI(decision *models.SmPolicyDecision, pccRule *models.PccRule, qfi string) {
if decision.QosDecs == nil {
return
} else if qosFlow := decision.QosDecs[qfi]; qosFlow == nil {
func SetPccRuleRelatedByQosRef(decision *models.SmPolicyDecision, pccRule *models.PccRule, qfi string) {
if decision.QosDecs == nil || decision.QosDecs[qfi] == nil {
return
}
pccRule.RefQosData = []string{qfi}
pccRule.RefQosData = append(pccRule.RefQosData, qfi)
if decision.PccRules == nil {
decision.PccRules = make(map[string]*models.PccRule)
}
Expand Down
1 change: 1 addition & 0 deletions internal/util/pcf_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
UNAUTHORIZED_SPONSORED_DATA_CONNECTIVITY = "UNAUTHORIZED_SPONSORED_DATA_CONNECTIVITY"
PDU_SESSION_NOT_AVAILABLE = "PDU_SESSION_NOT_AVAILABLE"
APPLICATION_SESSION_CONTEXT_NOT_FOUND = "APPLICATION_SESSION_CONTEXT_NOT_FOUND"
ERROR_IDGENERATOR = "ERROR_IDGENERATOR"
PcpErrHttpStatusMap = map[string]int32{
ERROR_REQUEST_PARAMETERS: http.StatusBadRequest,
USER_UNKNOWN: http.StatusBadRequest,
Expand Down
Loading