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

Commit

Permalink
feat: Adds support for optional parameters (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
gruyaume authored Dec 30, 2023
1 parent fbfc55d commit cacde0a
Show file tree
Hide file tree
Showing 17 changed files with 389 additions and 113 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ func main() {
pfcpClient := client.New("1.2.3.4:8805")
recoveryTimeStamp := ie.NewRecoveryTimeStamp(time.Now())
sequenceNumber := uint32(21)
heartbeatRequestMsg := messages.NewHeartbeatRequest(recoveryTimeStamp)
heartbeatRequestMsg := messages.HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
}

_, err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)
err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)
if err != nil {
log.Fatalf("SendHeartbeatRequest failed: %v", err)
}
Expand Down
18 changes: 12 additions & 6 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,30 @@ func serializeMessage(header headers.PFCPHeader, payload []byte) []byte {
return append(headerBytes, payload...)
}

func (pfcp *Pfcp) SendHeartbeatRequest(msg messages.HeartbeatRequest, sequenceNumber uint32) (ie.RecoveryTimeStamp, error) {
func (pfcp *Pfcp) SendHeartbeatRequest(msg messages.HeartbeatRequest, sequenceNumber uint32) error {
header := headers.NewPFCPHeader(messages.HeartbeatRequestMessageType, sequenceNumber)

payload := []ie.InformationElement{msg.RecoveryTimeStamp}

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

err := pfcp.sendPfcpMessage(header, payload)
if err != nil {
return msg.RecoveryTimeStamp, fmt.Errorf("error sending PFCP Heartbeat Request: %w", err)
return fmt.Errorf("error sending PFCP Heartbeat Request: %w", err)
}
return msg.RecoveryTimeStamp, nil
return nil
}

func (pfcp *Pfcp) SendHeartbeatResponse(msg messages.HeartbeatResponse, sequenceNumber uint32) (ie.RecoveryTimeStamp, error) {
func (pfcp *Pfcp) SendHeartbeatResponse(msg messages.HeartbeatResponse, sequenceNumber uint32) error {
header := headers.NewPFCPHeader(messages.HeartbeatResponseMessageType, sequenceNumber)
payload := []ie.InformationElement{msg.RecoveryTimeStamp}
err := pfcp.sendPfcpMessage(header, payload)
if err != nil {
return msg.RecoveryTimeStamp, fmt.Errorf("error sending PFCP Heartbeat Response: %w", err)
return fmt.Errorf("error sending PFCP Heartbeat Response: %w", err)
}
return msg.RecoveryTimeStamp, nil
return nil
}

func (pfcp *Pfcp) SendPFCPAssociationSetupRequest(msg messages.PFCPAssociationSetupRequest, sequenceNumber uint32) error {
Expand Down
6 changes: 4 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ func TestGivenPfcpWhenSendHeartbeatRequestThenNoError(t *testing.T) {
pfcpClient.Udp = mockSender
recoveryTimeStamp := ie.NewRecoveryTimeStamp(time.Now())
sequenceNumber := uint32(21)
heartbeatRequestMsg := messages.NewHeartbeatRequest(recoveryTimeStamp)
heartbeatRequestMsg := messages.HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
}

_, err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)
err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)

if err != nil {
t.Errorf("SendHeartbeatRequest failed: %v", err)
Expand Down
2 changes: 2 additions & 0 deletions ie/ie.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func ParseInformationElements(b []byte) ([]InformationElement, error) {
ie = DeserializeRecoveryTimeStamp(ieType, ieLength, ieValue)
case 101:
ie = DeserializeNodeReportType(ieType, ieLength, ieValue)
case 192:
ie, err = DeserializeSourceIPAddress(ieType, ieLength, ieValue)
default:
err = fmt.Errorf("unknown IE type %d", ieType)
}
Expand Down
109 changes: 109 additions & 0 deletions ie/sourceIPAddress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package ie

import (
"fmt"
"net"
)

type SourceIPAddress struct {
IEtype uint16
Length uint16
MPL bool
V4 bool
V6 bool
IPv4Address []byte
IPv6Address []byte
MaskPrefixLength uint8
}

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

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

if ip.To4() != nil {
sourceIPAddress.V4 = true
sourceIPAddress.IPv4Address = ip.To4()
sourceIPAddress.Length = 6
} else {
sourceIPAddress.V6 = true
sourceIPAddress.IPv6Address = ip.To16()
sourceIPAddress.Length = 18
}

if ipnet != nil {
sourceIPAddress.MPL = true
ones, _ := ipnet.Mask.Size()
sourceIPAddress.MaskPrefixLength = uint8(ones)
}
return sourceIPAddress, nil
}

func (sourceIPAddress SourceIPAddress) IsZeroValue() bool {
return sourceIPAddress.Length == 0
}

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

if sourceIPAddress.V4 {
length = 6
}
if sourceIPAddress.V6 {
length = 18
}
bytes := make([]byte, 4+length)
bytes[0] = byte(sourceIPAddress.IEtype >> 8)
bytes[1] = byte(sourceIPAddress.IEtype)
bytes[2] = byte(length >> 8)
bytes[3] = byte(length)
if sourceIPAddress.MPL {
bytes[4] = 0x80
}
if sourceIPAddress.V4 {
bytes[4] |= 0x40
}
if sourceIPAddress.V6 {
bytes[4] |= 0x20
}
if sourceIPAddress.V4 {
copy(bytes[5:9], sourceIPAddress.IPv4Address)
bytes[9] = sourceIPAddress.MaskPrefixLength
}
if sourceIPAddress.V6 {
copy(bytes[5:21], sourceIPAddress.IPv6Address)
bytes[21] = sourceIPAddress.MaskPrefixLength
}
return bytes
}

func DeserializeSourceIPAddress(ieType uint16, ieLength uint16, ieValue []byte) (SourceIPAddress, error) {
sourceIPAddress := SourceIPAddress{
IEtype: ieType,
Length: ieLength,
}

if ieValue[0]&0x80 == 0x80 {
sourceIPAddress.MPL = true
}
if ieValue[0]&0x40 == 0x40 {
sourceIPAddress.V4 = true
sourceIPAddress.IPv4Address = ieValue[1:5]
if sourceIPAddress.MPL {
sourceIPAddress.MaskPrefixLength = ieValue[5]
}
}
if ieValue[0]&0x20 == 0x20 {
sourceIPAddress.V6 = true
sourceIPAddress.IPv6Address = ieValue[1:17]
if sourceIPAddress.MPL {
sourceIPAddress.MaskPrefixLength = ieValue[17]
}
}
return sourceIPAddress, nil
}
111 changes: 111 additions & 0 deletions ie/sourceIPAddress_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package ie_test

import (
"testing"

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

func TestGivenCorrectIPv4AddressWhenSourceIPAddressThenFieldsSetCorrectly(t *testing.T) {

sourceIPAddress, err := ie.NewSourceIPAddress("1.2.3.4/24")

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

if sourceIPAddress.IEtype != 192 {
t.Errorf("Expected NodeID, got %d", sourceIPAddress.IEtype)
}

if sourceIPAddress.Length != 6 {
t.Errorf("Expected NodeID length 5, got %d", sourceIPAddress.Length)
}

if sourceIPAddress.MPL != true {
t.Errorf("Expected NodeID MPL true, got %v", sourceIPAddress.MPL)
}

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

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

if sourceIPAddress.MaskPrefixLength != 24 {
t.Errorf("Expected NodeID MaskPrefixLength 24, got %d", sourceIPAddress.MaskPrefixLength)
}
}

func TestGivenCorrectIPv6AddressWhenSourceIPAddressThenFieldsSetCorrectly(t *testing.T) {

sourceIPAddress, err := ie.NewSourceIPAddress("2001:db8::/32")

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

if sourceIPAddress.IEtype != 192 {
t.Errorf("Expected NodeID, got %d", sourceIPAddress.IEtype)
}

if sourceIPAddress.Length != 18 {
t.Errorf("Expected NodeID length 17, got %d", sourceIPAddress.Length)
}

if sourceIPAddress.MPL != true {
t.Errorf("Expected NodeID MPL true, got %v", sourceIPAddress.MPL)
}

if sourceIPAddress.V4 != false {
t.Errorf("Expected NodeID V4 false, got %v", sourceIPAddress.V4)
}

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

if sourceIPAddress.MaskPrefixLength != 32 {
t.Errorf("Expected NodeID MaskPrefixLength 32, got %d", sourceIPAddress.MaskPrefixLength)
}
}

func TestGivenSerializedIPV4AddressWhenDeserializeThenFieldsSetCorrectly(t *testing.T) {

sourceIPAddress, err := ie.NewSourceIPAddress("2.2.3.1/24")

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

serializedSourceIPAddress := sourceIPAddress.Serialize()

deserializedSourceIPAddress, err := ie.DeserializeSourceIPAddress(192, 6, serializedSourceIPAddress[4:])

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

if deserializedSourceIPAddress.IEtype != 192 {
t.Errorf("Expected NodeID, got %d", deserializedSourceIPAddress.IEtype)
}

if deserializedSourceIPAddress.Length != 6 {
t.Errorf("Expected NodeID length 5, got %d", deserializedSourceIPAddress.Length)
}

if deserializedSourceIPAddress.MPL != true {
t.Errorf("Expected NodeID MPL true, got %v", deserializedSourceIPAddress.MPL)
}

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

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

}
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ func main() {
pfcpClient := client.New("1.2.3.4:8805")
recoveryTimeStamp := ie.NewRecoveryTimeStamp(time.Now())
sequenceNumber := uint32(21)
heartbeatRequestMsg := messages.NewHeartbeatRequest(recoveryTimeStamp)
heartbeatRequestMsg := messages.HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
}

_, err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)
err := pfcpClient.SendHeartbeatRequest(heartbeatRequestMsg, sequenceNumber)
if err != nil {
log.Fatalf("SendHeartbeatRequest failed: %v", err)
}
Expand Down
24 changes: 9 additions & 15 deletions messages/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,32 @@ import (
)

type HeartbeatRequest struct {
MessageType MessageType
RecoveryTimeStamp ie.RecoveryTimeStamp
RecoveryTimeStamp ie.RecoveryTimeStamp // Mandatory
SourceIPAddress ie.SourceIPAddress // Optional
}

type HeartbeatResponse struct {
RecoveryTimeStamp ie.RecoveryTimeStamp
}

func NewHeartbeatRequest(recoveryTimeStamp ie.RecoveryTimeStamp) HeartbeatRequest {
return HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
}
}

func NewHeartbeatResponse(recoveryTimeStamp ie.RecoveryTimeStamp) HeartbeatResponse {
return HeartbeatResponse{
RecoveryTimeStamp: recoveryTimeStamp,
}
RecoveryTimeStamp ie.RecoveryTimeStamp // Mandatory
}

func ParseHeartbeatRequest(data []byte) (HeartbeatRequest, error) {
ies, err := ie.ParseInformationElements(data)
var recoveryTimeStamp ie.RecoveryTimeStamp
var sourceIPAddress ie.SourceIPAddress
for _, elem := range ies {
if tsIE, ok := elem.(ie.RecoveryTimeStamp); ok {
recoveryTimeStamp = tsIE
continue
}
if ipIE, ok := elem.(ie.SourceIPAddress); ok {
sourceIPAddress = ipIE
continue
}
}

return HeartbeatRequest{
RecoveryTimeStamp: recoveryTimeStamp,
SourceIPAddress: sourceIPAddress,
}, err
}

Expand Down
19 changes: 3 additions & 16 deletions messages/pfcp_association_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@ package messages
import "github.com/dot-5g/pfcp/ie"

type PFCPAssociationReleaseRequest struct {
NodeID ie.NodeID
NodeID ie.NodeID // Mandatory
}

type PFCPAssociationReleaseResponse struct {
NodeID ie.NodeID
Cause ie.Cause
}

func NewPFCPAssociationReleaseRequest(nodeID ie.NodeID) PFCPAssociationReleaseRequest {
return PFCPAssociationReleaseRequest{
NodeID: nodeID,
}
}

func NewPFCPAssociationReleaseResponse(nodeID ie.NodeID, cause ie.Cause) PFCPAssociationReleaseResponse {
return PFCPAssociationReleaseResponse{
NodeID: nodeID,
Cause: cause,
}
NodeID ie.NodeID // Mandatory
Cause ie.Cause // Mandatory
}

func ParsePFCPAssociationReleaseRequest(data []byte) (PFCPAssociationReleaseRequest, error) {
Expand Down
Loading

0 comments on commit cacde0a

Please sign in to comment.