Skip to content

Support for Multiple DNNs per Device Group with a Single UPF #439

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 32 additions & 11 deletions context/upf.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"net"
"reflect"
"strconv"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -90,9 +91,9 @@ type UPF struct {

// UPFSelectionParams ... parameters for upf selection
type UPFSelectionParams struct {
Dnn string
SNssai *SNssai
Dnai string
DnnList []string
SNssai *SNssai
Dnai string
}

// UPFInterfaceInfo store the UPF interface information
Expand Down Expand Up @@ -163,12 +164,20 @@ func (i *UPFInterfaceInfo) IP(pduSessType uint8) (net.IP, error) {
}

func (upfSelectionParams *UPFSelectionParams) String() string {
if upfSelectionParams == nil {
return "UPFSelectionParams is nil"
}
str := ""
Dnn := upfSelectionParams.Dnn
if Dnn != "" {
str += fmt.Sprintf("Dnn: %s\n", Dnn)
// Handle the DnnList
if len(upfSelectionParams.DnnList) > 0 {
str += "Dnn List: "
for _, dnn := range upfSelectionParams.DnnList {
str += fmt.Sprintf("%s ", dnn)
}
str += "\n"
} else {
str += "Dnn List is empty\n"
}

SNssai := upfSelectionParams.SNssai
if SNssai != nil {
str += fmt.Sprintf("Sst: %d, Sd: %s\n", int(SNssai.Sst), SNssai.Sd)
Expand Down Expand Up @@ -249,14 +258,26 @@ func (upf *UPF) GetInterface(interfaceType models.UpInterfaceType, dnn string) *
switch interfaceType {
case models.UpInterfaceType_N3:
for i, iface := range upf.N3Interfaces {
if iface.NetworkInstance == dnn {
return &upf.N3Interfaces[i]
logger.CtxLog.Infof("Checking UPF N3 Interface: %v", iface.NetworkInstance)

// Split multiple DNNs and check if dnn exists
dnnList := strings.Split(iface.NetworkInstance, ",")
for _, d := range dnnList {
if strings.TrimSpace(d) == strings.TrimSpace(dnn) {
return &upf.N3Interfaces[i]
}
}
}
case models.UpInterfaceType_N9:
for i, iface := range upf.N9Interfaces {
if iface.NetworkInstance == dnn {
return &upf.N9Interfaces[i]
logger.CtxLog.Infof("Checking UPF N9 Interface: %v", iface.NetworkInstance)

// Split multiple DNNs and check if dnn exists
dnnList := strings.Split(iface.NetworkInstance, ",")
for _, d := range dnnList {
if strings.TrimSpace(d) == strings.TrimSpace(dnn) {
return &upf.N9Interfaces[i]
}
}
}
}
Expand Down
23 changes: 15 additions & 8 deletions context/user_plane_information.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,16 @@ func (upi *UserPlaneInformation) GenerateDefaultPath(selection *UPFSelectionPara
destinations = upi.selectMatchUPF(selection)

if len(destinations) == 0 {
logger.CtxLog.Errorf("can not find UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]", selection.Dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
for _, dnn := range selection.DnnList {
logger.CtxLog.Errorf("Can't find UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]\n", dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
}
return false
} else {
logger.CtxLog.Debugf("found UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]", selection.Dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
for _, dnn := range selection.DnnList {
logger.CtxLog.Infof("Found UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]\n", dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
}
}

// Run DFS
Expand Down Expand Up @@ -223,17 +227,20 @@ func (upi *UserPlaneInformation) GenerateDefaultPath(selection *UPFSelectionPara

func (upi *UserPlaneInformation) selectMatchUPF(selection *UPFSelectionParams) []*UPNode {
upList := make([]*UPNode, 0)

logger.CtxLog.Infof("Selecting matching UPFs for DNNs[%v] and S-NSSAI[sst: %d, sd: %s]", selection.DnnList, selection.SNssai.Sst, selection.SNssai.Sd)
for _, upNode := range upi.UPFs {
for _, snssaiInfo := range upNode.UPF.SNssaiInfos {
currentSnssai := &snssaiInfo.SNssai
targetSnssai := selection.SNssai

if currentSnssai.Equal(targetSnssai) {
for _, dnnInfo := range snssaiInfo.DnnList {
if dnnInfo.Dnn == selection.Dnn && dnnInfo.ContainsDNAI(selection.Dnai) {
upList = append(upList, upNode)
break
for _, dnn := range selection.DnnList {
if dnnInfo.Dnn == dnn && dnnInfo.ContainsDNAI(selection.Dnai) {
upList = append(upList, upNode)
logger.CtxLog.Infof("Matching UPF found: %v for DNN[%s] and DNAI[%s]", upNode, dnn, selection.Dnai)
break
}
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions context/user_plane_information_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestGenerateDefaultPath(t *testing.T) {
Sst: 1,
Sd: "112232",
},
Dnn: "internet",
DnnList: []string{"internet"},
},
expected: true,
},
Expand All @@ -171,7 +171,7 @@ func TestGenerateDefaultPath(t *testing.T) {
Sst: 2,
Sd: "112233",
},
Dnn: "internet",
DnnList: []string{"internet"},
},
expected: true,
},
Expand All @@ -182,7 +182,7 @@ func TestGenerateDefaultPath(t *testing.T) {
Sst: 3,
Sd: "112234",
},
Dnn: "internet",
DnnList: []string{"internet"},
},
expected: true,
},
Expand All @@ -193,7 +193,7 @@ func TestGenerateDefaultPath(t *testing.T) {
Sst: 1,
Sd: "112235",
},
Dnn: "internet",
DnnList: []string{"internet"},
},
expected: true,
},
Expand All @@ -204,7 +204,7 @@ func TestGenerateDefaultPath(t *testing.T) {
Sst: 1,
Sd: "010203",
},
Dnn: "internet",
DnnList: []string{"internet"},
},
expected: false,
},
Expand Down
45 changes: 25 additions & 20 deletions factory/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"strings"
"time"

protos "github.com/omec-project/config5g/proto/sdcoreConfig"
protos "github.com/5GC-DEV/config5g-cdac/proto/sdcoreConfig"
"github.com/omec-project/openapi/models"
"github.com/omec-project/smf/logger"
utilLogger "github.com/omec-project/util/logger"
Expand Down Expand Up @@ -325,14 +325,16 @@ func (c *Configuration) parseRocConfig(rsp *protos.NetworkSliceResponse) error {
// make DNN Info structure
sNssaiInfoItem.DnnInfos = make([]SnssaiDnnInfoItem, 0)
for _, devGrp := range ns.DeviceGroup {
var dnnInfo SnssaiDnnInfoItem
dnnInfo.Dnn = devGrp.IpDomainDetails.DnnName
dnnInfo.DNS.IPv4Addr = devGrp.IpDomainDetails.DnsPrimary
dnnInfo.UESubnet = devGrp.IpDomainDetails.UePool
dnnInfo.MTU = uint16(devGrp.IpDomainDetails.Mtu)

// update to Slice structure
sNssaiInfoItem.DnnInfos = append(sNssaiInfoItem.DnnInfos, dnnInfo)
for _, ipDomain := range devGrp.IpDomainDetails { // Iterate over IpDomainDetails slice
var dnnInfo SnssaiDnnInfoItem
dnnInfo.Dnn = ipDomain.DnnName
dnnInfo.DNS.IPv4Addr = ipDomain.DnsPrimary
dnnInfo.UESubnet = ipDomain.UePool
dnnInfo.MTU = uint16(ipDomain.Mtu)

// Update to Slice structure
sNssaiInfoItem.DnnInfos = append(sNssaiInfoItem.DnnInfos, dnnInfo)
}
}

// Update to SMF config structure
Expand Down Expand Up @@ -376,18 +378,21 @@ func (c *Configuration) parseRocConfig(rsp *protos.NetworkSliceResponse) error {

// Popoulate DNN names per UPF slice Info
for _, devGrp := range ns.DeviceGroup {
// DNN Info in UPF per Slice
var dnnUpfInfo models.DnnUpfInfoItem
dnnUpfInfo.Dnn = devGrp.IpDomainDetails.DnnName
snsUpfInfoItem.DnnUpfInfoList = append(snsUpfInfoItem.DnnUpfInfoList, dnnUpfInfo)

// Populate UPF Interface Info and DNN info in UPF per Interface
intfUpfInfoItem := InterfaceUpfInfoItem{
InterfaceType: models.UpInterfaceType_N3,
Endpoints: make([]string, 0), NetworkInstance: devGrp.IpDomainDetails.DnnName,
for _, ipDomain := range devGrp.IpDomainDetails { // Iterate over IpDomainDetails slice
// DNN Info in UPF per Slice
var dnnUpfInfo models.DnnUpfInfoItem
dnnUpfInfo.Dnn = ipDomain.DnnName
snsUpfInfoItem.DnnUpfInfoList = append(snsUpfInfoItem.DnnUpfInfoList, dnnUpfInfo)

// Populate UPF Interface Info and DNN info in UPF per Interface
intfUpfInfoItem := InterfaceUpfInfoItem{
InterfaceType: models.UpInterfaceType_N3,
Endpoints: make([]string, 0),
NetworkInstance: ipDomain.DnnName,
}
intfUpfInfoItem.Endpoints = append(intfUpfInfoItem.Endpoints, ns.Site.Upf.UpfName)
upf.InterfaceUpfInfoList = append(upf.InterfaceUpfInfoList, intfUpfInfoItem)
}
intfUpfInfoItem.Endpoints = append(intfUpfInfoItem.Endpoints, ns.Site.Upf.UpfName)
upf.InterfaceUpfInfoList = append(upf.InterfaceUpfInfoList, intfUpfInfoItem)
}
upf.SNssaiInfos = append(upf.SNssaiInfos, snsUpfInfoItem)

Expand Down
4 changes: 2 additions & 2 deletions factory/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package factory
import (
"testing"

protos "github.com/omec-project/config5g/proto/sdcoreConfig"
protos "github.com/5GC-DEV/config5g-cdac/proto/sdcoreConfig"
"github.com/omec-project/openapi/models"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -50,7 +50,7 @@ func makeDummyConfig(sst, sd string) *protos.NetworkSliceResponse {

ns.DeviceGroup = make([]*protos.DeviceGroup, 0)
ipDomain := protos.IpDomain{DnnName: "internet", UePool: "60.60.0.0/16", DnsPrimary: "8.8.8.8", Mtu: 1400}
devGrp := protos.DeviceGroup{IpDomainDetails: &ipDomain}
devGrp := protos.DeviceGroup{IpDomainDetails: []*protos.IpDomain{&ipDomain}}
ns.DeviceGroup = append(ns.DeviceGroup, &devGrp)

rsp.NetworkSlice = append(rsp.NetworkSlice, &ns)
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ require (
github.com/google/uuid v1.6.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/omec-project/aper v1.3.1
github.com/omec-project/config5g v1.6.2
github.com/omec-project/nas v1.6.0
github.com/omec-project/ngap v1.5.0
github.com/omec-project/openapi v1.5.0
Expand All @@ -23,6 +22,8 @@ require (
gopkg.in/yaml.v2 v2.4.0
)

require github.com/5GC-DEV/config5g-cdac v0.2.1 // indirect

require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/5GC-DEV/config5g-cdac v0.2.1 h1:7Cqwmqh5jqeWtwYTrITflrGotglIRBIb1P3EF2f85OA=
github.com/5GC-DEV/config5g-cdac v0.2.1/go.mod h1:0OEL6UoNKKlx2tlNSoKpRtzckwxR2SL+pRBDAOCT4BU=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
Expand Down Expand Up @@ -175,8 +177,6 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/omec-project/aper v1.3.1 h1:3Vyqn2xQEulzsQ9JganXqxbR1E2IM7oUm4IW1HiPnr0=
github.com/omec-project/aper v1.3.1/go.mod h1:W0i+XhbXHeeLQ4BhMmAS8h83yZ5pnD3w0sdIlnuPS70=
github.com/omec-project/config5g v1.6.2 h1:bfLxwVSt6LAWCQtBmjUuks5CO3qambvcy3VjSVAMHdk=
github.com/omec-project/config5g v1.6.2/go.mod h1:LuaRiJTCJXCkQF7nKB5fOcz6oVMF/8oid+EKCYFAy0E=
github.com/omec-project/nas v1.6.0 h1:Bar13cFszi8l4AStLGRLbznFx93OYNV9n/Ba4A2RN1Y=
github.com/omec-project/nas v1.6.0/go.mod h1:C5mXN3MiZZBF0YRiPkxB2RWc8RvTFb0xWGcUTZ6efng=
github.com/omec-project/ngap v1.5.0 h1:Fu0JIDxDxuNnlz9iomehxn2ZSryqwcY0YS8a73cSIsM=
Expand Down
2 changes: 1 addition & 1 deletion producer/pdu_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func HandlePDUSessionSMContextCreate(eventData interface{}) error {
smContext.Tunnel = smf_context.NewUPTunnel()
var defaultPath *smf_context.DataPath
upfSelectionParams := &smf_context.UPFSelectionParams{
Dnn: createData.Dnn,
DnnList: []string{createData.Dnn},
SNssai: &smf_context.SNssai{
Sst: createData.SNssai.Sst,
Sd: createData.SNssai.Sd,
Expand Down
17 changes: 16 additions & 1 deletion qos/qos_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package qos

import (
"reflect"
"strconv"
"strings"

Expand Down Expand Up @@ -351,7 +352,21 @@ func GetQosDataChanges(qf1, qf2 *models.QosData) bool {
}

func GetQoSDataFromPolicyDecision(smPolicyDecision *models.SmPolicyDecision, refQosData string) *models.QosData {
return smPolicyDecision.QosDecs[refQosData]
if smPolicyDecision == nil {
logger.PduSessLog.Errorln("smPolicyDecision is nil")
return nil
}
if smPolicyDecision.QosDecs == nil {
logger.PduSessLog.Errorln("QosDecs map is nil")
return nil
}
qos, exists := smPolicyDecision.QosDecs[refQosData]
if !exists {
logger.PduSessLog.Errorf("QoS Data [%s] not found in QosDecs. Available keys: %v", refQosData, reflect.ValueOf(smPolicyDecision.QosDecs).MapKeys())
return nil
}

return qos
}

func (d *QosFlowDescriptionsAuthorized) AddDefaultQosFlowDescription(sessRule *models.SessionRule) {
Expand Down
4 changes: 2 additions & 2 deletions service/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"syscall"
"time"

grpcClient "github.com/5GC-DEV/config5g-cdac/proto/client"
protos "github.com/5GC-DEV/config5g-cdac/proto/sdcoreConfig"
aperLogger "github.com/omec-project/aper/logger"
grpcClient "github.com/omec-project/config5g/proto/client"
protos "github.com/omec-project/config5g/proto/sdcoreConfig"
nasLogger "github.com/omec-project/nas/logger"
ngapLogger "github.com/omec-project/ngap/logger"
openapiLogger "github.com/omec-project/openapi/logger"
Expand Down
Loading