Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

Commit

Permalink
feat: Adds optional up function features IE
Browse files Browse the repository at this point in the history
  • Loading branch information
gruyaume committed Dec 30, 2023
1 parent cacde0a commit 29cb40e
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 23 deletions.
5 changes: 5 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ func (pfcp *Pfcp) SendHeartbeatResponse(msg messages.HeartbeatResponse, sequence
func (pfcp *Pfcp) SendPFCPAssociationSetupRequest(msg messages.PFCPAssociationSetupRequest, sequenceNumber uint32) error {
header := headers.NewPFCPHeader(messages.PFCPAssociationSetupRequestMessageType, sequenceNumber)
payload := []ie.InformationElement{msg.NodeID, msg.RecoveryTimeStamp}

if !msg.UPFunctionFeatures.IsZeroValue() {
payload = append(payload, msg.UPFunctionFeatures)
}

err := pfcp.sendPfcpMessage(header, payload)
if err != nil {
return fmt.Errorf("error sending PFCP Association Setup Request: %w", err)
Expand Down
4 changes: 4 additions & 0 deletions ie/cause.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func (cause Cause) Serialize() []byte {
return buf.Bytes()
}

func (cause Cause) IsZeroValue() bool {
return cause.Length == 0
}

func DeserializeCause(ieType uint16, ieLength uint16, ieValue []byte) Cause {
return Cause{
IEtype: ieType,
Expand Down
36 changes: 25 additions & 11 deletions ie/ie.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ import (

const IEHeaderLength = 4

type IEType uint16

const (
CauseIEType IEType = 19
NodeIDIEType IEType = 60
RecoveryTimeStampIEType IEType = 96
NodeReportTypeIEType IEType = 101
SourceIPAddressIEType IEType = 192
UPFunctionFeaturesIEType IEType = 43
)

type InformationElement interface {
Serialize() []byte
IsZeroValue() bool
}

func ParseInformationElements(b []byte) ([]InformationElement, error) {
Expand All @@ -22,7 +34,7 @@ func ParseInformationElements(b []byte) ([]InformationElement, error) {
return nil, fmt.Errorf("not enough bytes for IE header")
}

ieType := binary.BigEndian.Uint16(b[index : index+2])
ieType := IEType(binary.BigEndian.Uint16(b[index : index+2]))
ieLength := binary.BigEndian.Uint16(b[index+2 : index+4])
index += IEHeaderLength
if len(b[index:]) < int(ieLength) {
Expand All @@ -32,16 +44,18 @@ func ParseInformationElements(b []byte) ([]InformationElement, error) {
ieValue := b[index : index+int(ieLength)]
var ie InformationElement
switch ieType {
case 19:
ie = DeserializeCause(ieType, ieLength, ieValue)
case 60:
ie = DeserializeNodeID(ieType, ieLength, ieValue)
case 96:
ie = DeserializeRecoveryTimeStamp(ieType, ieLength, ieValue)
case 101:
ie = DeserializeNodeReportType(ieType, ieLength, ieValue)
case 192:
ie, err = DeserializeSourceIPAddress(ieType, ieLength, ieValue)
case CauseIEType:
ie = DeserializeCause(uint16(ieType), ieLength, ieValue)
case NodeIDIEType:
ie = DeserializeNodeID(uint16(ieType), ieLength, ieValue)
case RecoveryTimeStampIEType:
ie = DeserializeRecoveryTimeStamp(uint16(ieType), ieLength, ieValue)
case NodeReportTypeIEType:
ie = DeserializeNodeReportType(uint16(ieType), ieLength, ieValue)
case SourceIPAddressIEType:
ie, err = DeserializeSourceIPAddress(uint16(ieType), ieLength, ieValue)
case UPFunctionFeaturesIEType:
ie, err = DeserializeUPFunctionFeatures(uint16(ieType), ieLength, ieValue)
default:
err = fmt.Errorf("unknown IE type %d", ieType)
}
Expand Down
4 changes: 4 additions & 0 deletions ie/nodeId.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (n NodeID) Serialize() []byte {
return buf.Bytes()
}

func (n NodeID) IsZeroValue() bool {
return n.Length == 0
}

func DeserializeNodeID(ieType uint16, ieLength uint16, ieValue []byte) NodeID {
nodeIDType := NodeIDType(ieValue[0] & 0x0F) // Ensure NodeIDType is only 4 bits
nodeIDValue := ieValue[1:]
Expand Down
4 changes: 4 additions & 0 deletions ie/nodeReportType.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ func (nrt NodeReportType) Serialize() []byte {
return buf.Bytes()
}

func (nrt NodeReportType) IsZeroValue() bool {
return nrt.Length == 0
}

func DeserializeNodeReportType(ieType uint16, ieLength uint16, ieValue []byte) NodeReportType {
var nrt NodeReportType

Expand Down
4 changes: 4 additions & 0 deletions ie/recoveryTimeStamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ func (rt RecoveryTimeStamp) Serialize() []byte {
return bytes
}

func (rt RecoveryTimeStamp) IsZeroValue() bool {
return rt.Length == 0
}

func DeserializeRecoveryTimeStamp(ieType uint16, ieLength uint16, ieValue []byte) RecoveryTimeStamp {
return RecoveryTimeStamp{
IEtype: ieType,
Expand Down
137 changes: 137 additions & 0 deletions ie/upFunctionFeatures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package ie

import (
"encoding/binary"
"fmt"
)

type UPFunctionFeatures struct {
IEType uint16
Length uint16
SupportedFeatures []byte
AdditionalSupportedFeatures1 []byte
AdditionalSupportedFeatures2 []byte
}

type UPFeature int

const (
BUCP UPFeature = iota
DDND
DLBD
TRST
FTUP
PFDM
HEEU
TREU
EMPU
PDIU
UDBC
QUOAC
TRACE
FRRT
PFDE
EPFAR
DPDRA
ADPDP
UEIP
SSET
MNOP
MTE
BUNDL
GCOM
MPAS
RTTL
VTIME
NORP
IPTV
IP6PL
TSCU
MPTCP
ATSSSLL
QFQM
GPQM
MTEDT
CIOT
ETHAR
DDDS
RDS
RTTWP
NumberOfUPFeatures
)

func NewUPFunctionFeatures(supportedFeatures []UPFeature) UPFunctionFeatures {
featureBytes := make([]byte, 2)

for _, feature := range supportedFeatures {
if feature < NumberOfUPFeatures {
byteIndex := feature / 8
bitPosition := feature % 8
featureBytes[byteIndex] |= 1 << bitPosition
}
}

return UPFunctionFeatures{
IEType: 43,
Length: uint16(len(featureBytes)),
SupportedFeatures: featureBytes,
AdditionalSupportedFeatures1: nil,
AdditionalSupportedFeatures2: nil,
}
}

func (ie UPFunctionFeatures) Serialize() []byte {
totalLength := 4 + ie.Length
serialized := make([]byte, totalLength)

binary.BigEndian.PutUint16(serialized[0:2], ie.IEType)
binary.BigEndian.PutUint16(serialized[2:4], ie.Length)

copy(serialized[4:], ie.SupportedFeatures)

return serialized
}

func (ie UPFunctionFeatures) GetFeatures() []UPFeature {
features := make([]UPFeature, 0)

for i, byteValue := range ie.SupportedFeatures {
for j := 0; j < 8; j++ {
if byteValue&(1<<j) > 0 {
features = append(features, UPFeature(i*8+j))
}
}
}

return features
}

func (ie UPFunctionFeatures) IsZeroValue() bool {
return ie.Length == 0
}

func DeserializeUPFunctionFeatures(ieType uint16, ieLength uint16, ieValue []byte) (UPFunctionFeatures, error) {
if ieType != 43 {
return UPFunctionFeatures{}, fmt.Errorf("incorrect IE type")
}
if len(ieValue) != int(ieLength) {
return UPFunctionFeatures{}, fmt.Errorf("incorrect length: expected %d, got %d", ieLength, len(ieValue))
}

upFuncFeatures := UPFunctionFeatures{
IEType: ieType,
Length: ieLength,
SupportedFeatures: make([]byte, 0),
AdditionalSupportedFeatures1: make([]byte, 0),
AdditionalSupportedFeatures2: make([]byte, 0),
}

if ieLength >= 1 {
upFuncFeatures.SupportedFeatures = append(upFuncFeatures.SupportedFeatures, ieValue[0])
}
if ieLength >= 2 {
upFuncFeatures.SupportedFeatures = append(upFuncFeatures.SupportedFeatures, ieValue[1])
}

return upFuncFeatures, nil
}
49 changes: 49 additions & 0 deletions ie/upFunctionFeatures_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ie_test

import (
"testing"

"github.com/dot-5g/pfcp/ie"
)

func TestGivenSerializedWhenDeserializedThenDeserializedCorrectly(t *testing.T) {
features := [](ie.UPFeature){
ie.BUCP,
ie.TRACE,
}

upFunctionFeatures := ie.NewUPFunctionFeatures(features)
serializedUPFunctionFeatures := upFunctionFeatures.Serialize()

deserializedUPFunctionFeatures, err := ie.DeserializeUPFunctionFeatures(43, 2, serializedUPFunctionFeatures[4:])
if err != nil {
t.Fatalf("Error deserializing UPFunctionFeatures: %v", err)
}

if deserializedUPFunctionFeatures.IEType != 43 {
t.Errorf("Expected IE type 43, got %d", deserializedUPFunctionFeatures.IEType)
}

if deserializedUPFunctionFeatures.Length != 2 {
t.Errorf("Expected IE length 2, got %d", deserializedUPFunctionFeatures.Length)
}

if len(deserializedUPFunctionFeatures.SupportedFeatures) != 2 {
t.Errorf("Expected 2 supported features, got %d", len(deserializedUPFunctionFeatures.SupportedFeatures))
}

deserializedFeatures := deserializedUPFunctionFeatures.GetFeatures()

if len(deserializedFeatures) != 2 {
t.Errorf("Expected 2 features, got %d", len(deserializedFeatures))
}

if deserializedFeatures[0] != ie.BUCP {
t.Errorf("Expected BUCP feature, got %v", deserializedFeatures[0])
}

if deserializedFeatures[1] != ie.TRACE {
t.Errorf("Expected TRACE feature, got %v", deserializedFeatures[1])
}

}
22 changes: 17 additions & 5 deletions messages/pfcp_association_setup.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package messages

import "github.com/dot-5g/pfcp/ie"
import (
"fmt"

"github.com/dot-5g/pfcp/ie"
)

type PFCPAssociationSetupRequest struct {
NodeID ie.NodeID // Mandatory
RecoveryTimeStamp ie.RecoveryTimeStamp // Mandatory
NodeID ie.NodeID // Mandatory
RecoveryTimeStamp ie.RecoveryTimeStamp // Mandatory
UPFunctionFeatures ie.UPFunctionFeatures // Conditional
}

type PFCPAssociationSetupResponse struct {
Expand All @@ -17,6 +22,7 @@ func ParsePFCPAssociationSetupRequest(data []byte) (PFCPAssociationSetupRequest,
ies, err := ie.ParseInformationElements(data)
var nodeID ie.NodeID
var recoveryTimeStamp ie.RecoveryTimeStamp
var upfeatures ie.UPFunctionFeatures
for _, elem := range ies {
if tsIE, ok := elem.(ie.RecoveryTimeStamp); ok {
recoveryTimeStamp = tsIE
Expand All @@ -26,11 +32,17 @@ func ParsePFCPAssociationSetupRequest(data []byte) (PFCPAssociationSetupRequest,
nodeID = nodeIDIE
continue
}
if upfeaturesIE, ok := elem.(ie.UPFunctionFeatures); ok {
fmt.Printf("upfeaturesIE: %v\n", upfeaturesIE)
upfeatures = upfeaturesIE
continue
}
}

return PFCPAssociationSetupRequest{
NodeID: nodeID,
RecoveryTimeStamp: recoveryTimeStamp,
NodeID: nodeID,
RecoveryTimeStamp: recoveryTimeStamp,
UPFunctionFeatures: upfeatures,
}, err
}

Expand Down
Loading

0 comments on commit 29cb40e

Please sign in to comment.