1 Star 1 Fork 1

刘昭 / smf

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
user_plane_information.go 8.42 KB
一键复制 编辑 原始数据 按行查看 历史
刘昭 提交于 2022-01-25 19:32 . 0.2.0
package context
import (
"net"
"reflect"
"gitee.com/liu-zhao234568/smf/factory"
"gitee.com/liu-zhao234568/smf/logger"
"github.com/free5gc/pfcp/pfcpType"
)
// UserPlaneInformation store userplane topology
type UserPlaneInformation struct {
UPNodes map[string]*UPNode
UPFs map[string]*UPNode
AccessNetwork map[string]*UPNode
UPFIPToName map[string]string
UPFsID map[string]string // name to id
UPFsIPtoID map[string]string // ip->id table, for speed optimization
DefaultUserPlanePath map[string][]*UPNode // DNN to Default Path
}
type UPNodeType string
const (
UPNODE_UPF UPNodeType = "UPF"
UPNODE_AN UPNodeType = "AN"
)
// UPNode represent the user plane node topology
type UPNode struct {
Type UPNodeType
NodeID pfcpType.NodeID
ANIP net.IP
Dnn string
Links []*UPNode
UPF *UPF
}
// UPPath represent User Plane Sequence of this path
type UPPath []*UPNode
func AllocateUPFID() {
UPFsID := smfContext.UserPlaneInformation.UPFsID
UPFsIPtoID := smfContext.UserPlaneInformation.UPFsIPtoID
for upfName, upfNode := range smfContext.UserPlaneInformation.UPFs {
upfid := upfNode.UPF.UUID()
upfip := upfNode.NodeID.ResolveNodeIdToIp().String()
UPFsID[upfName] = upfid
UPFsIPtoID[upfip] = upfid
}
}
// NewUserPlaneInformation process the configuration then returns a new instance of UserPlaneInformation
func NewUserPlaneInformation(upTopology *factory.UserPlaneInformation) *UserPlaneInformation {
nodePool := make(map[string]*UPNode)
upfPool := make(map[string]*UPNode)
anPool := make(map[string]*UPNode)
upfIPMap := make(map[string]string)
for name, node := range upTopology.UPNodes {
upNode := new(UPNode)
upNode.Type = UPNodeType(node.Type)
switch upNode.Type {
case UPNODE_AN:
upNode.ANIP = net.ParseIP(node.ANIP)
anPool[name] = upNode
case UPNODE_UPF:
// ParseIp() always return 16 bytes
// so we can't use the length of return ip to separate IPv4 and IPv6
// This is just a work around
var ip net.IP
if net.ParseIP(node.NodeID).To4() == nil {
ip = net.ParseIP(node.NodeID)
} else {
ip = net.ParseIP(node.NodeID).To4()
}
switch len(ip) {
case net.IPv4len:
upNode.NodeID = pfcpType.NodeID{
NodeIdType: pfcpType.NodeIdTypeIpv4Address,
NodeIdValue: ip,
}
case net.IPv6len:
upNode.NodeID = pfcpType.NodeID{
NodeIdType: pfcpType.NodeIdTypeIpv6Address,
NodeIdValue: ip,
}
default:
upNode.NodeID = pfcpType.NodeID{
NodeIdType: pfcpType.NodeIdTypeFqdn,
NodeIdValue: []byte(node.NodeID),
}
}
upNode.UPF = NewUPF(&upNode.NodeID, node.InterfaceUpfInfoList)
snssaiInfos := make([]SnssaiUPFInfo, 0)
for _, snssaiInfoConfig := range node.SNssaiInfos {
snssaiInfo := SnssaiUPFInfo{
SNssai: SNssai{
Sst: snssaiInfoConfig.SNssai.Sst,
Sd: snssaiInfoConfig.SNssai.Sd,
},
DnnList: make([]DnnUPFInfoItem, 0),
}
for _, dnnInfoConfig := range snssaiInfoConfig.DnnUpfInfoList {
snssaiInfo.DnnList = append(snssaiInfo.DnnList, DnnUPFInfoItem{
Dnn: dnnInfoConfig.Dnn,
DnaiList: dnnInfoConfig.DnaiList,
PduSessionTypes: dnnInfoConfig.PduSessionTypes,
})
}
snssaiInfos = append(snssaiInfos, snssaiInfo)
}
upNode.UPF.SNssaiInfos = snssaiInfos
upfPool[name] = upNode
default:
logger.InitLog.Warningf("invalid UPNodeType: %s\n", upNode.Type)
}
nodePool[name] = upNode
ipStr := upNode.NodeID.ResolveNodeIdToIp().String()
upfIPMap[ipStr] = name
}
for _, link := range upTopology.Links {
nodeA := nodePool[link.A]
nodeB := nodePool[link.B]
if nodeA == nil || nodeB == nil {
logger.InitLog.Warningf("UPLink [%s] <=> [%s] not establish\n", link.A, link.B)
continue
}
nodeA.Links = append(nodeA.Links, nodeB)
nodeB.Links = append(nodeB.Links, nodeA)
}
userplaneInformation := &UserPlaneInformation{
UPNodes: nodePool,
UPFs: upfPool,
AccessNetwork: anPool,
UPFIPToName: upfIPMap,
UPFsID: make(map[string]string),
UPFsIPtoID: make(map[string]string),
DefaultUserPlanePath: make(map[string][]*UPNode),
}
return userplaneInformation
}
func (upi *UserPlaneInformation) GetUPFNameByIp(ip string) string {
return upi.UPFIPToName[ip]
}
func (upi *UserPlaneInformation) GetUPFNodeIDByName(name string) pfcpType.NodeID {
return upi.UPFs[name].NodeID
}
func (upi *UserPlaneInformation) GetUPFNodeByIP(ip string) *UPNode {
upfName := upi.GetUPFNameByIp(ip)
return upi.UPFs[upfName]
}
func (upi *UserPlaneInformation) GetUPFIDByIP(ip string) string {
return upi.UPFsIPtoID[ip]
}
func (upi *UserPlaneInformation) GetDefaultUserPlanePathByDNN(selection *UPFSelectionParams) (path UPPath) {
path, pathExist := upi.DefaultUserPlanePath[selection.String()]
logger.CtxLog.Traceln("In GetDefaultUserPlanePathByDNN")
logger.CtxLog.Traceln("selection: ", selection.String())
if pathExist {
return
} else {
pathExist = upi.GenerateDefaultPath(selection)
if pathExist {
return upi.DefaultUserPlanePath[selection.String()]
}
}
return nil
}
func (upi *UserPlaneInformation) ExistDefaultPath(dnn string) bool {
_, exist := upi.DefaultUserPlanePath[dnn]
return exist
}
func GenerateDataPath(upPath UPPath, smContext *SMContext) *DataPath {
if len(upPath) < 1 {
logger.CtxLog.Errorf("Invalid data path")
return nil
}
lowerBound := 0
upperBound := len(upPath) - 1
var root *DataPathNode
var curDataPathNode *DataPathNode
var prevDataPathNode *DataPathNode
for idx, upNode := range upPath {
curDataPathNode = NewDataPathNode()
curDataPathNode.UPF = upNode.UPF
if idx == lowerBound {
root = curDataPathNode
root.AddPrev(nil)
}
if idx == upperBound {
curDataPathNode.AddNext(nil)
}
if prevDataPathNode != nil {
prevDataPathNode.AddNext(curDataPathNode)
curDataPathNode.AddPrev(prevDataPathNode)
}
prevDataPathNode = curDataPathNode
}
dataPath := &DataPath{
Destination: Destination{
DestinationIP: "",
DestinationPort: "",
Url: "",
},
FirstDPNode: root,
}
return dataPath
}
func (upi *UserPlaneInformation) GenerateDefaultPath(selection *UPFSelectionParams) bool {
var source *UPNode
var destinations []*UPNode
for _, node := range upi.AccessNetwork {
if node.Type == UPNODE_AN {
source = node
break
}
}
if source == nil {
logger.CtxLog.Errorf("There is no AN Node in config file!")
return false
}
destinations = upi.selectMatchUPF(selection)
if len(destinations) == 0 {
logger.CtxLog.Errorf("Can't find UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]\n", selection.Dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
return false
} else {
logger.CtxLog.Tracef("Find UPF with DNN[%s] S-NSSAI[sst: %d sd: %s] DNAI[%s]\n", selection.Dnn,
selection.SNssai.Sst, selection.SNssai.Sd, selection.Dnai)
}
// Run DFS
visited := make(map[*UPNode]bool)
for _, upNode := range upi.UPNodes {
visited[upNode] = false
}
path, pathExist := getPathBetween(source, destinations[0], visited, selection)
if pathExist {
if path[0].Type == UPNODE_AN {
path = path[1:]
}
upi.DefaultUserPlanePath[selection.String()] = path
}
return pathExist
}
func (upi *UserPlaneInformation) selectMatchUPF(selection *UPFSelectionParams) []*UPNode {
upList := make([]*UPNode, 0)
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
}
}
}
}
}
return upList
}
func getPathBetween(cur *UPNode, dest *UPNode, visited map[*UPNode]bool,
selection *UPFSelectionParams) (path []*UPNode, pathExist bool) {
visited[cur] = true
if reflect.DeepEqual(*cur, *dest) {
path = make([]*UPNode, 0)
path = append(path, cur)
pathExist = true
return
}
selectedSNssai := selection.SNssai
for _, nodes := range cur.Links {
if !visited[nodes] {
if !nodes.UPF.isSupportSnssai(selectedSNssai) {
visited[nodes] = true
continue
}
path_tail, path_exist := getPathBetween(nodes, dest, visited, selection)
if path_exist {
path = make([]*UPNode, 0)
path = append(path, cur)
path = append(path, path_tail...)
pathExist = true
return
}
}
}
return nil, false
}
1
https://gitee.com/liu-zhao234568/smf.git
git@gitee.com:liu-zhao234568/smf.git
liu-zhao234568
smf
smf
v1.0.0

搜索帮助