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

Commit

Permalink
feat: Adds pfcp session establishment
Browse files Browse the repository at this point in the history
  • Loading branch information
gruyaume committed Dec 30, 2023
1 parent 91b3ea1 commit cf7b690
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 75 deletions.
94 changes: 94 additions & 0 deletions ie/fseid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package ie

import (
"bytes"
"encoding/binary"
"net"
)

type FSEID struct {
IEType uint16
Length uint16
V4 bool
V6 bool
SEID uint64
IPv4 []byte
IPv6 []byte
}

func NewFSEID(seid uint64, ipv4Address string, ipv6Address string) (FSEID, error) {
fseid := FSEID{
IEType: 57,
SEID: seid,
}
var length uint16 = 9

ipv4 := net.ParseIP(ipv4Address)
ipv6 := net.ParseIP(ipv6Address)

if ipv4.To4() != nil {
fseid.V4 = true
fseid.IPv4 = ipv4.To4()
length += 4
}
if ipv6.To16() != nil {
fseid.V6 = true
fseid.IPv6 = ipv6.To16()
length += 16
}
fseid.Length = length
return fseid, nil
}

func (fseid FSEID) Serialize() []byte {
buf := new(bytes.Buffer)

// Octets 1 to 2: Type (57)
binary.Write(buf, binary.BigEndian, uint16(fseid.IEType))

// Octets 3 to 4: Length
binary.Write(buf, binary.BigEndian, uint16(fseid.Length))

// Octet 5: Spare (6 bits) + V4 (1 bit) + V6 (1 bit)
var flags byte
if fseid.V4 {
flags |= 1 << 1 // Set the second bit from the right if V4 is true
}
if fseid.V6 {
flags |= 1 << 0 // Set the first bit from the right if V6 is true
}
buf.WriteByte(flags)

// Octets 6 13: SEID
binary.Write(buf, binary.BigEndian, fseid.SEID)

// Octet m to (m+3) IPv4 address
if fseid.V4 {
buf.Write(fseid.IPv4)
}

// Octet p to (p+15): IPv6 address
if fseid.V6 {
buf.Write(fseid.IPv6)
}

return buf.Bytes()
}

func DeserializeFSEID(ieType uint16, ieLength uint16, ieValue []byte) FSEID {
v4 := ieValue[0]&0x02 > 0
v6 := ieValue[0]&0x01 > 0
seid := binary.BigEndian.Uint64(ieValue[1:9])
ipv4 := ieValue[9:13]
ipv6 := ieValue[13:29]

return FSEID{
IEType: ieType,
Length: ieLength,
V4: v4,
V6: v6,
SEID: seid,
IPv4: ipv4,
IPv6: ipv6,
}
}
99 changes: 99 additions & 0 deletions ie/fseid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package ie_test

import (
"fmt"
"testing"

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

func TestGivenValidIPAddressWhenNewFSEIDThenFieldsAreSetCorrectly(t *testing.T) {
seid := uint64(0x1234567890ABCDEF)

fseid, err := ie.NewFSEID(seid, "1.2.3.4", "")

if err != nil {
t.Fatalf("Error creating FSEID: %v", err)
}

if fseid.IEType != 57 {
t.Errorf("Expected FSEID IEType 97, got %d", fseid.IEType)
}

if fseid.Length != 13 {
t.Errorf("Expected FSEID length 12, got %d", fseid.Length)
}

if fseid.V4 != true {
t.Errorf("Expected FSEID V4 true, got %v", fseid.V4)
}

if fseid.V6 != false {
t.Errorf("Expected FSEID V6 false, got %v", fseid.V6)
}

if fseid.SEID != seid {
t.Errorf("Expected FSEID SEID %d, got %d", seid, fseid.SEID)
}

expectedIPv4 := []byte{1, 2, 3, 4}
for i := range fseid.IPv4 {
if fseid.IPv4[i] != expectedIPv4[i] {
t.Errorf("Expected FSEID IPv4 %v, got %v", expectedIPv4, fseid.IPv4)
}
}

}

func TestGivenSerializedWhenDeserializeThenFieldsSetCorrectly(t *testing.T) {
seid := uint64(0x1234567890ABCDEF)
ipv4 := "2.3.4.5"
ipv6 := "2001:db8::68"

fseid, err := ie.NewFSEID(seid, ipv4, ipv6)

if err != nil {
t.Fatalf("Error creating FSEID: %v", err)
}

serialized := fseid.Serialize()

fmt.Printf("Serialized FSEID: %v\n", serialized)

deserialized := ie.DeserializeFSEID(57, 12, serialized[4:])

if deserialized.IEType != 57 {
t.Errorf("Expected FSEID IEType 57, got %d", deserialized.IEType)
}

if deserialized.Length != 12 {
t.Errorf("Expected FSEID length 12, got %d", deserialized.Length)
}

if deserialized.V4 != true {
t.Errorf("Expected FSEID V4 true, got %v", deserialized.V4)
}

if deserialized.V6 != true {
t.Errorf("Expected FSEID V6 true, got %v", deserialized.V6)
}

if deserialized.SEID != seid {
t.Errorf("Expected FSEID SEID %d, got %d", seid, deserialized.SEID)
}

expectedIPv4 := []byte{2, 3, 4, 5}
for i := range deserialized.IPv4 {
if deserialized.IPv4[i] != expectedIPv4[i] {
t.Errorf("Expected FSEID IPv4 %v, got %v", expectedIPv4, deserialized.IPv4)
}
}

expectedIPv6 := []byte{32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, 0x68}
for i := range deserialized.IPv6 {
if deserialized.IPv6[i] != expectedIPv6[i] {
t.Errorf("Expected FSEID IPv6 %v, got %v", expectedIPv6, deserialized.IPv6)
}
}

}
3 changes: 3 additions & 0 deletions ie/ie.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
NodeReportTypeIEType IEType = 101
SourceIPAddressIEType IEType = 192
UPFunctionFeaturesIEType IEType = 43
FSEIDIEType IEType = 57
)

type InformationElement interface {
Expand Down Expand Up @@ -56,6 +57,8 @@ func ParseInformationElements(b []byte) ([]InformationElement, error) {
ie, err = DeserializeSourceIPAddress(uint16(ieType), ieLength, ieValue)
case UPFunctionFeaturesIEType:
ie, err = DeserializeUPFunctionFeatures(uint16(ieType), ieLength, ieValue)
// case FSEIDIEType:
// ie, err = DeserializeFSEID(uint16(ieType), ieLength, ieValue)
default:
err = fmt.Errorf("unknown IE type %d", ieType)
}
Expand Down
42 changes: 14 additions & 28 deletions ie/nodeId.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package ie
import (
"bytes"
"encoding/binary"
"fmt"
"net"
)

Expand All @@ -22,44 +21,31 @@ type NodeID struct {
NodeIDValue []byte
}

func NewNodeID(nodeIDType NodeIDType, nodeIDValue string) NodeID {
func NewNodeID(nodeID string) NodeID {
var nodeIDValueBytes []byte
var length uint16
var nodeIDType NodeIDType

switch nodeIDType {
case IPv4:
ip := net.ParseIP(nodeIDValue)
if ip == nil {
panic("invalid IPv4 address")
}
ipv4 := ip.To4()
if ipv4 == nil {
panic("invalid IPv4 address")
}
nodeIDValueBytes = ipv4
ip := net.ParseIP(nodeID)

if ip.To4() != nil {
nodeIDValueBytes = ip.To4()
length = uint16(len(nodeIDValueBytes)) + 1
case IPv6:
ip := net.ParseIP(nodeIDValue)
if ip == nil {
panic("invalid IPv6 address")
}
ipv6 := ip.To16()
if ipv6 == nil {
panic("invalid IPv6 address")
}
nodeIDValueBytes = ipv6
nodeIDType = IPv4
} else if ip.To16() != nil {
nodeIDValueBytes = ip.To16()
length = uint16(len(nodeIDValueBytes)) + 1
case FQDN:
fqdn := []byte(nodeIDValue)
nodeIDType = IPv6
} else {
fqdn := []byte(nodeID)
if len(fqdn) > 255 {
panic("FQDN too long")
}
nodeIDValueBytes = fqdn
length = uint16(len(nodeIDValueBytes)) + 1

default:
panic(fmt.Sprintf("invalid NodeIDType %d", nodeIDType))
nodeIDType = FQDN
}

return NodeID{
IEtype: 60,
Length: length,
Expand Down
6 changes: 3 additions & 3 deletions ie/nodeId_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestNewNodeIDIPv4(t *testing.T) {
nodeID := ie.NewNodeID(ie.IPv4, "1.2.3.4")
nodeID := ie.NewNodeID("1.2.3.4")

if nodeID.IEtype != 60 {
t.Errorf("Expected NodeID, got %d", nodeID.IEtype)
Expand Down Expand Up @@ -35,7 +35,7 @@ func TestNewNodeIDIPv4(t *testing.T) {
}

func TestNewNodeIDIPv6(t *testing.T) {
nodeID := ie.NewNodeID(ie.IPv6, "2001:db8::68")
nodeID := ie.NewNodeID("2001:db8::68")

if nodeID.IEtype != 60 {
t.Errorf("Expected NodeID, got %d", nodeID.IEtype)
Expand Down Expand Up @@ -63,7 +63,7 @@ func TestNewNodeIDIPv6(t *testing.T) {
}

func TestNewNodeIDFQDN(t *testing.T) {
nodeID := ie.NewNodeID(ie.FQDN, "www.example.com")
nodeID := ie.NewNodeID("www.example.com")

if nodeID.IEtype != 60 {
t.Errorf("Expected NodeID, got %d", nodeID.IEtype)
Expand Down
48 changes: 22 additions & 26 deletions ie/sourceIPAddress.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package ie

import (
"fmt"
"net"
)

Expand All @@ -16,31 +15,36 @@ type SourceIPAddress struct {
MaskPrefixLength uint8
}

func NewSourceIPAddress(cidr string) (SourceIPAddress, error) {
func NewSourceIPAddress(ipv4Address string, ipv6Address string) (SourceIPAddress, error) {
sourceIPAddress := SourceIPAddress{
IEtype: 192,
}

ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return sourceIPAddress, fmt.Errorf("invalid CIDR")
}
length := 2

ipv4, ipv4net, _ := net.ParseCIDR(ipv4Address)
ipv6, ipv6net, _ := net.ParseCIDR(ipv6Address)

if ip.To4() != nil {
if ipv4.To4() != nil {
sourceIPAddress.V4 = true
sourceIPAddress.IPv4Address = ip.To4()
sourceIPAddress.Length = 6
} else {
sourceIPAddress.V6 = true
sourceIPAddress.IPv6Address = ip.To16()
sourceIPAddress.Length = 18
sourceIPAddress.IPv4Address = ipv4.To4()
length += 4
sourceIPAddress.MPL = true
ones, _ := ipv4net.Mask.Size()
sourceIPAddress.MaskPrefixLength = uint8(ones)
}

if ipnet != nil {
if ipv6.To16() != nil {
sourceIPAddress.V6 = true
sourceIPAddress.IPv6Address = ipv6.To16()
sourceIPAddress.Length = 18
length += 16
sourceIPAddress.MPL = true
ones, _ := ipnet.Mask.Size()
ones, _ := ipv6net.Mask.Size()
sourceIPAddress.MaskPrefixLength = uint8(ones)
}
sourceIPAddress.Length = uint16(length)

return sourceIPAddress, nil
}

Expand All @@ -49,19 +53,11 @@ func (sourceIPAddress SourceIPAddress) IsZeroValue() bool {
}

func (sourceIPAddress SourceIPAddress) Serialize() []byte {
var length uint16

if sourceIPAddress.V4 {
length = 6
}
if sourceIPAddress.V6 {
length = 18
}
bytes := make([]byte, 4+length)
bytes := make([]byte, 4+sourceIPAddress.Length)
bytes[0] = byte(sourceIPAddress.IEtype >> 8)
bytes[1] = byte(sourceIPAddress.IEtype)
bytes[2] = byte(length >> 8)
bytes[3] = byte(length)
bytes[2] = byte(sourceIPAddress.Length >> 8)
bytes[3] = byte(sourceIPAddress.Length)
if sourceIPAddress.MPL {
bytes[4] = 0x80
}
Expand Down
Loading

0 comments on commit cf7b690

Please sign in to comment.