字节1 按位设置:
- 位1: 代表 SEID 标记- 位2: 代表 MP 标记(message priority)
- 位3-5: spare,发送者设置为0,接收将忽略
- 位6-8: 版本
字节 2 是消息类型
字节3、4是两字节的消息长度
可选项 SEID,占8字节
最后3字节序列号.
Figure 7.2.2.1-1: General format of PFCP Header
- if S = 0, SEID field is not present, k = 0, m = 0 and n = 5;
- if S = 1, SEID field is present, k = 1, m = 5 and n = 13.
结构体 PFCP Header
type Header struct {
Version uint8
MP uint8
S uint8
MessageType MessageType
MessageLength uint16
SEID uint64
SequenceNumber uint32
MessagePriority uint8
}
参看: https://blog.csdn.net/zhonglinzhang/article/details/107542866 第 2.1 章节
根据所有配置文件定义的 UPF 发起 PFCP 关联请求,SMF PFCP 服务端端口 8805
for _, upf := range context.SMF_Self().UserPlaneInformation.UPFs {
addr := new(net.UDPAddr)
addr.IP = net.IP(upf.NodeID.NodeIdValue)
addr.Port = pfcpUdp.PFCP_PORT
logger.AppLog.Infof("Send PFCP Association Request to UPF[%s]\n", addr.String())
message.SendPfcpAssociationSetupRequest(addr)
}
1.1.1 SendPfcpAssociationSetupRequest 函数
创建 body,这里发送方未 CP 功能
- Node ID,发送方以为的标识符
- Recovery Time Stamp,当 CP 或 CP 已经启动的时间戳
- UP Function Features,指示 UP 功能支持的特性(UP 发送)
- CP Function Features,指示 CP 功能支持的特性(CP 发送)
- User Plane IP Resource Information,包含 IPv4 / IPv6,还有 TEID,用来在 UP 分配 GTP-U F-TEID(UP 发送)
func BuildPfcpAssociationSetupRequest() (pfcp.PFCPAssociationSetupRequest, error) {
msg := pfcp.PFCPAssociationSetupRequest{}
msg.NodeID = &context.SMF_Self().CPNodeID
msg.RecoveryTimeStamp = &pfcpType.RecoveryTimeStamp{
RecoveryTimeStamp: udp.ServerStartTime,
}
msg.CPFunctionFeatures = &pfcpType.CPFunctionFeatures{
SupportedFeatures: 0,
}
return msg, nil
}
1.1.1.1 PFCP 消息填充
消息类型为:PFCP_ASSOCIATION_SETUP_REQUEST,S 设置为 0
message := pfcp.Message{
Header: pfcp.Header{
Version: pfcp.PfcpVersion,
MP: 0,
S: pfcp.SEID_NOT_PRESENT,
MessageType: pfcp.PFCP_ASSOCIATION_SETUP_REQUEST,
SequenceNumber: getSeqNumber(),
},
Body: pfcpMsg,
}
1.1.2 SMF 处理 PFCP Association Response
如果原因设置为 CauseRequestAccepted 更新 UPF 信息状态为 AssociatedSetUpSuccess
func HandlePfcpAssociationSetupResponse(msg *pfcpUdp.Message) {
req := msg.PfcpMessage.Body.(pfcp.PFCPAssociationSetupResponse)
nodeID := req.NodeID
if req.Cause.CauseValue == pfcpType.CauseRequestAccepted {
if nodeID == nil {
logger.PfcpLog.Errorln("pfcp association needs NodeID")
return
}
upf := smf_context.RetrieveUPFNodeByNodeID(*req.NodeID)
upf.UPFStatus = smf_context.AssociatedSetUpSuccess
if req.UserPlaneIPResourceInformation != nil {
upf.UPIPInfo = *req.UserPlaneIPResourceInformation
logger.PfcpLog.Infof("UPF(%s)[%s] setup association", upf.NodeID.ResolveNodeIdToIp().String(), upf.UPIPInfo.NetworkInstance)
} else {
logger.PfcpLog.Errorln("pfcp association setup response has no UserPlane IP Resource Information")
}
}
}
SMF 从 AMF 接收 Nsmf_PDUSession_CreateSMContext 请求,/sm-contexts,则进入 PostSmContexts 函数处理,设置为 PDUSessionSMContextCreate 类型消息,丢进 channel 进行集中处理
2.1.1 SMF 创建会话管理上下文,实例化 SMContext
- supi
- pduSessionID
- gpsi
- DNn
- SNssai
- HplmnSnssai
- ServingNetwork
- AnType
- RatType
- UeLocation
- OldPduSessionId
- ServingNfId
- SmContextStatusUri
2.1.2 向 UDM 发起 Nudm_SubscriberDataManagement.请求 /{supi}/sm-data 步骤 4
为 UE 分配 IP 地址,PCF 选择,smContext.PCFSelection,调用 Nnrf_NFDiscovery /nf-instances 向 NRF 进行服务发现,实例化 SmPolicyContextData 并填充 Supi,PDUSessionID,Dnn,Snssai 等等。调用 /sm-policies 更新 PCF 策略配置
2.1.3 PCF 选择 4.3.2.2.1-1 步骤 7a
2.1.4 SM Policy /sm-policies 步骤 7b
2.1.6 ApplySmPolicyFromDecision 函数(新增)
应用 session rule
2.1.7 设置拓扑 (未预先设置 UE SUPI 的配置)
例如官方例子:
userplane_information:
- up_nodes:
- gNB1:
- type: AN
- an_ip: 192.188.2.3
- BranchingUPF:
- type: UPF
- node_id: 10.200.200.102
- up_resource_ip: 192.188.2.2
- AnchorUPF1:
- type: UPF
- node_id: 10.200.200.101
- up_resource_ip: 192.188.2.23
- AnchorUPF2:
- type: UPF
- node_id: 10.200.200.103
- up_resource_ip: 192.188.2.24
- links:
- A: gNB1 B: BranchingUPF
- A: BranchingUPF B: AnchorUPF1
- A: BranchingUPF B: AnchorUPF2
GenerateDataPath 终于更改了,原来写的不知道要干什么
在这里区分预先配置和未预先配置 UE SUPI 路径
对于首次没有 session 的情况,上行链路和下行链路 PDR (包检测规则)和 FAR (转发行为规则)
func SendPFCPRule(smContext *smf_context.SMContext, dataPath *smf_context.DataPath) {
logger.PduSessLog.Infof("Send PFCP Rule")
logger.PduSessLog.Infof("DataPath: ", dataPath)
for curDataPathNode := dataPath.FirstDPNode; curDataPathNode != nil; curDataPathNode = curDataPathNode.Next() {
pdrList := make([]*smf_context.PDR, 0, 2)
farList := make([]*smf_context.FAR, 0, 2)
if !curDataPathNode.HaveSession {
if curDataPathNode.UpLinkTunnel != nil && curDataPathNode.UpLinkTunnel.PDR != nil {
pdrList = append(pdrList, curDataPathNode.UpLinkTunnel.PDR)
farList = append(farList, curDataPathNode.UpLinkTunnel.PDR.FAR)
}
if curDataPathNode.DownLinkTunnel != nil && curDataPathNode.DownLinkTunnel.PDR != nil {
pdrList = append(pdrList, curDataPathNode.DownLinkTunnel.PDR)
farList = append(farList, curDataPathNode.DownLinkTunnel.PDR.FAR)
}
pfcp_message.SendPfcpSessionEstablishmentRequest(curDataPathNode.UPF.NodeID, smContext, pdrList, farList, nil)
curDataPathNode.HaveSession = true
2.3.1 SendPfcpSessionEstablishmentRequest 步骤 10a
建立 PFCP 会话建立请求到 UPF,包括 SM 上下文,PDR,FAR,BAR(目前空)
BuildPfcpSessionEstablishmentRequestForULCL 函数主要用来实例化 PFCPSessionEstablishmentRequest,并填充 CP NodeID,CreatePDR,CreateFAR 等,
创建的 PFCP 消息头,消息类型为 PFCP_SESSION_ESTABLISHMENT_REQUEST
func SendPfcpSessionEstablishmentRequest(upNodeID pfcpType.NodeID, ctx *context.SMContext, pdrList []*context.PDR, farList []*context.FAR, barList []*context.BAR) {
pfcpMsg, err := BuildPfcpSessionEstablishmentRequest(upNodeID, ctx, pdrList, farList, barList)
if err != nil {
logger.PfcpLog.Errorf("Build PFCP Session Establishment Request failed: %v", err)
return
}
message := pfcp.Message{
Header: pfcp.Header{
Version: pfcp.PfcpVersion,
MP: 1,
S: pfcp.SEID_PRESENT,
MessageType: pfcp.PFCP_SESSION_ESTABLISHMENT_REQUEST,
SEID: 0,
SequenceNumber: getSeqNumber(),
MessagePriority: 0,
},
Body: pfcpMsg,
}
upaddr := &net.UDPAddr{
IP: upNodeID.ResolveNodeIdToIp(),
Port: pfcpUdp.PFCP_PORT,
}
2.3.2 SendPfcpSessionModificationRequest 函数
对于已经存在的会话,修改的情况
从 UPF 收到回复请求,类型为 PFCP_SESSION_ESTABLISHMENT_RESPONSE
func HandlePfcpSessionEstablishmentResponse(msg *pfcpUdp.Message) {
rsp := msg.PfcpMessage.Body.(pfcp.PFCPSessionEstablishmentResponse)
SEID := msg.PfcpMessage.Header.SEID
smContext := smf_context.GetSMContextBySEID(SEID)
if rsp.UPFSEID != nil {
UPFSEID := rsp.UPFSEID
smContext.RemoteSEID = UPFSEID.Seid
}
实例化 NAS 消息,填充 GSM 消息,设置类型为 MsgTypePDUSessionEstablishmentAccept,PDUSessionEstablishmentAccept 结构体如下
type PDUSessionEstablishmentAccept struct {
nasType.ExtendedProtocolDiscriminator
nasType.PDUSessionID
nasType.PTI
nasType.PDUSESSIONESTABLISHMENTACCEPTMessageIdentity
nasType.SelectedSSCModeAndSelectedPDUSessionType
nasType.AuthorizedQosRules
nasType.SessionAMBR
*nasType.Cause5GSM
*nasType.PDUAddress
*nasType.RQTimerValue
*nasType.SNSSAI
*nasType.AlwaysonPDUSessionIndication
*nasType.MappedEPSBearerContexts
*nasType.EAPMessage
*nasType.AuthorizedQosFlowDescriptions
*nasType.ExtendedProtocolConfigurationOptions
*nasType.DNN
}
3.1.1 填充 PDUSessionEstablishmentAccept 结构体
- PDUSessionID
- 消息类型 MsgTypePDUSessionEstablishmentAccept
- PTI:0x00
- PDU 会话类型:这里实现为 IPv4
- SSC 模式,这里设置为 1
- SessionAMBR
- QOS 规则
- 【PDU Address】
pDUSessionEstablishmentAccept.SetPDUSessionID(uint8(smContext.PDUSessionID))
pDUSessionEstablishmentAccept.SetMessageType(nas.MsgTypePDUSessionEstablishmentAccept)
pDUSessionEstablishmentAccept.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSSessionManagementMessage)
pDUSessionEstablishmentAccept.SetPTI(0x00)
pDUSessionEstablishmentAccept.SetPDUSessionType(smContext.SelectedPDUSessionType)
pDUSessionEstablishmentAccept.SetSSCMode(1)
pDUSessionEstablishmentAccept.SessionAMBR = nasConvert.ModelsToSessionAMBR(smContext.SessionRule.AuthSessAmbr)
pDUSessionEstablishmentAccept.SessionAMBR.SetLen(uint8(len(pDUSessionEstablishmentAccept.SessionAMBR.Octet)))
实例化 PDUSessionResourceSetupRequestTransfer 对象,主要包含的是 IE 信息元素
func BuildPDUSessionResourceSetupRequestTransfer(ctx *SMContext) (buf []byte, err error) {
var UpNode = ctx.Tunnel.UpfRoot.UPF
var teidOct = make([]byte, 4)
binary.BigEndian.PutUint32(teidOct, ctx.Tunnel.UpfRoot.UpLinkTunnel.TEID)
resourceSetupRequestTransfer := ngapType.PDUSessionResourceSetupRequestTransfer{}
PDUSessionResourceSetupRequestTransferIEs 结构定义如下:
type PDUSessionResourceSetupRequestTransferIEs struct { Id ProtocolIEID Criticality Criticality Value PDUSessionResourceSetupRequestTransferIEsValue `aper:"openType,referenceFieldName:Id"` }
3.2.1 UL NG-U UP TNL Information
3.2.2 PDU Session Type
3.2.3 QoS Flow Setup Request List,use Default 5qi, arp
官方 3GPP 提供的 openapi 生成,包括 PDU 会话 ID,包括 N1,N2 消息,N2 信息包括 Snssai
n1n2Request := models.N1N2MessageTransferRequest{}
n1n2Request.JsonData = &models.N1N2MessageTransferReqData{
PduSessionId: smContext.PDUSessionID,
N1MessageContainer: &models.N1MessageContainer{
N1MessageClass: "SM",
N1MessageContent: &models.RefToBinaryData{ContentId: "GSM_NAS"},
},
N2InfoContainer: &models.N2InfoContainer{
N2InformationClass: models.N2InformationClass_SM,
SmInfo: &models.N2SmInformation{
PduSessionId: smContext.PDUSessionID,
N2InfoContent: &models.N2InfoContent{
NgapIeType: models.NgapIeType_PDU_RES_SETUP_REQ,
NgapData: &models.RefToBinaryData{
ContentId: "N2SmInformation",
},
},
SNssai: smContext.Snssai,
},
},
}
n1n2Request.BinaryDataN1Message = smNasBuf
n1n2Request.BinaryDataN2Information = n2Pdu
/ue-contexts/{ueContextId}/n1-n2-messages
SMF 配置文件
info:
version: 1.0.0
description: AMF initial local configuration
configuration:
amfName: AMF
ngapIpList:
- 127.0.0.10
sbi:
scheme: http
ipv4Addr: 127.0.0.1
port: 29518
serviceNameList:
- namf-comm
- namf-evts
- namf-mt
- namf-loc
- namf-oam
servedGuamiList:
- plmnId:
mcc: 208
mnc: 93
amfId: cafe00
supportTaiList:
- plmnId:
mcc: 208
mnc: 93
tac: 1
plmnSupportList:
- plmnId:
mcc: 208
mnc: 93
snssaiList:
- sst: 1
sd: 010203
- sst: 1
sd: 112233
supportDnnList:
- internet
nrfUri: http://localhost:29510
security:
integrityOrder:
- NIA2
- NIA0
cipheringOrder:
- NEA2
- NEA0
networkName:
full: free5GC
short: free
t3502: 720
t3512: 3600
non3gppDeregistrationTimer: 3240
NRF 中注册的 SMF
{
"_id": ObjectId("5f1a9c2364d2e538cb1309d4"),
"ipv4Addresses": [
"smf"
],
"smfInfo": {
"sNssaiSmfInfoList": null
},
"nfServices": [
{
"serviceInstanceId": "e1b3436a-f9b9-4820-b075-d16fb4814ddansmf-pdusession",
"serviceName": "nsmf-pdusession",
"versions": [
{
"expiry": "2020-07-24T08:30:27Z",
"apiVersionInUri": "v1",
"apiFullVersion": "https://smf:29502/nsmf-pdusession/v1"
}
],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"apiPrefix": "https://smf:29502"
},
{
"serviceName": "nsmf-event-exposure",
"versions": [
{
"apiVersionInUri": "v1",
"apiFullVersion": "https://smf:29502/nsmf-pdusession/v1",
"expiry": "2020-07-24T08:30:27Z"
}
],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"apiPrefix": "https://smf:29502",
"serviceInstanceId": "e1b3436a-f9b9-4820-b075-d16fb4814ddansmf-event-exposure"
}
],
"nfInstanceId": "e1b3436a-f9b9-4820-b075-d16fb4814dda",
"nfType": "SMF",
"nfStatus": "REGISTERED",
"plmnList": [
{
"mcc": "208",
"mnc": "93"
}
]
}