Skip to content

Commit

Permalink
More helpers/better grouped IE handling
Browse files Browse the repository at this point in the history
  • Loading branch information
wmnsk committed Sep 30, 2023
1 parent 5a0f0bd commit 4c75f28
Show file tree
Hide file tree
Showing 113 changed files with 503 additions and 899 deletions.
37 changes: 30 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,15 @@ v, err := ni.NetworkInstance()

In the example above, calling the `NetworkInstance()` method returns `"some.instance.example", nil`. However, if `ni` is not of type `ie.NetworkInstance` or the payload is not in right format, it returns `"", SomeError`. It's important to always check the returned error, as the value may be empty _as expected_.

The type of returned values are determined as friendly as possible for the built-in Go types. For example, `QuotaValidityTime()` returns the value as `time.Duration`. In the cases that this is undesirable, such as when you need to pass the raw value to another node, you can use `ValueAsUint32()` method instead, which returns the value as `uint32`. This could also be useful for handling vendor-specific IEs whose value retrieval methods are not available in this package. Available `ValueAs`-methods are `ValueAsUin8()`, `ValueAsUint16()`, `ValueAsUint32()`, `ValueAsUint64()`, `ValueAsString()`, and `ValueAsFQDN()`.

```go
qvTime := ie.NewQuotaValidityTime(10 * time.Second)

vDuration, err := qvTime.QuotaValidityTime()
vUint32, err := qvTime.ValueAsUint32()
```

For IEs with more complex payloads, such as F-TEID, calling the `<IE-name>` method returns a `<IE-name>Fields` struct containing the values in its fields.

```go
Expand All @@ -444,35 +453,49 @@ teid := fteidFields.TEID // TEID as uint32
v4 := fteidFields.IPv4Address // IPv4 address as net.IP
```

For grouped IEs, calling `<IE-name>` method returns a list of IEs contained in the grouped IE.
For grouped IEs, accesing the `ChildIEs` field is the best way to retrieve the list of IEs contained. If you are not sure that the IE is already parsed, you can use `ValueAsGrouped()` method instead, which parses the payload into `[]*IE` and returns it if the `ChildIEs` field is empty.

```go
cpdrIE := ie.NewCreatePDR(
ie.NewPDRID(0xffff),
// ...
)

cpdrChildren, err := cpdrIE.CreatePDR() // `[]*IE` containing IEs in CreatePDR IE
// most efficient way
cpdrChildren := cpdrIE.ChildIEs
// or use this if you are not sure that the IE is already parsed
cpdrChildren, err := cpdrIE.ValueAsGrouped()
```

_NOTE: if you have called `ie.Parse`, the child IEs are already parsed._

_To determine if an IE is grouped or not, this package uses the `defaultGroupedIEMap` in `ie_grouped.go`, which contains the list of grouped IEs. You can add your own IE type to this map using `ie.AddGroupedIEType()` function, or you can change the entire logic to determine if an IE is grouped or not by setting your own function to `ie.SetIsGroupedFun` function._

`<IE-name>` method is also available for consistency with non-grouped IEs, but it is not recommended to use it as it always parses the payload into `[]*IE` and returns it though the `ChildIEs` field is already populated. In the rare case that the payload can be modified after the IE is created or parsed, this method could be useful.

```go
cpdrChildren, err := cpdrIE.CreatePDR()
```

For convenience, helper methods of the child IEs can be called directly on the grouped IE.
For convenience, helper methods of the child IEs can be called directly on the grouped IE, or you can call `FindByType()` method to get the child IE of the specified type.

```go
pdrID, err := cpdrIE.PDRID()

// or
pdrID, err := cpdrIE.FindByType(ie.PDRID)
```

This is useful when you only need a small number of IEs within a grouped IE. Since it calls `CreatePDR()` internally, retrieving everything using the child IE's method is very inefficient. When you need to check the value of many IEs, it is recommended to use the former method and iterate over the list of IEs in your own code.
This is useful when you only need a small number of IEs within a grouped IE. Since it iterates over all child IEs internally, retrieving everything using these method is very inefficient. When you need to retrieve the value of multiple IEs, it is recommended to iterate over the list of child IEs in your own code.

```go
cpdrChildren, err := cpdr.CreatePDR()

var (
pdrID uint16
farID uint32
// ...
)

for _, i := range cpdrChildren {
for _, i := range cpdrIE.ChildIEs {
switch i.Type {
case ie.PDRID:
v, err = i.PDRID()
Expand Down
8 changes: 1 addition & 7 deletions ie/access-availability-information.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

package ie

import "io"

// AccessType definitions.
const (
AccessType3GPP uint8 = 0
Expand All @@ -25,13 +23,9 @@ func NewAccessAvailabilityInformation(status, atype uint8) *IE {

// AccessAvailabilityInformation returns AccessAvailabilityInformation in uint8 if the type of IE matches.
func (i *IE) AccessAvailabilityInformation() (uint8, error) {
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case AccessAvailabilityInformation:
return i.Payload[0], nil
return i.ValueAsUint8()
case AccessAvailabilityReport:
ies, err := i.AccessAvailabilityReport()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion ie/activate-predefined-rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewActivatePredefinedRules(name string) *IE {
func (i *IE) ActivatePredefinedRules() (string, error) {
switch i.Type {
case ActivatePredefinedRules:
return string(i.Payload), nil
return i.ValueAsString()
case CreatePDR:
ies, err := i.CreatePDR()
if err != nil {
Expand Down
8 changes: 1 addition & 7 deletions ie/activation-time.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
package ie

import (
"encoding/binary"
"io"
"time"
)

Expand All @@ -18,13 +16,9 @@ func NewActivationTime(ts time.Time) *IE {

// ActivationTime returns ActivationTime in time.Time if the type of IE matches.
func (i *IE) ActivationTime() (time.Time, error) {
if len(i.Payload) < 4 {
return time.Time{}, io.ErrUnexpectedEOF
}

switch i.Type {
case ActivationTime:
return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil
return i.valueAs3GPPTimestamp()
case CreatePDR:
ies, err := i.CreatePDR()
if err != nil {
Expand Down
11 changes: 1 addition & 10 deletions ie/aggregated-urr-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@

package ie

import (
"encoding/binary"
"io"
)

// NewAggregatedURRID creates a new AggregatedURRID IE.
func NewAggregatedURRID(id uint32) *IE {
return newUint32ValIE(AggregatedURRID, id)
Expand All @@ -18,11 +13,7 @@ func NewAggregatedURRID(id uint32) *IE {
func (i *IE) AggregatedURRID() (uint32, error) {
switch i.Type {
case AggregatedURRID:
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

return binary.BigEndian.Uint32(i.Payload[0:4]), nil
return i.ValueAsUint32()
case AggregatedURRs:
ies, err := i.AggregatedURRs()
if err != nil {
Expand Down
6 changes: 1 addition & 5 deletions ie/apn-dnn.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

package ie

import (
"github.com/wmnsk/go-pfcp/internal/utils"
)

// NewAPNDNN creates a new APNDNN IE.
func NewAPNDNN(apn string) *IE {
return newFQDNIE(APNDNN, apn)
Expand All @@ -19,7 +15,7 @@ func (i *IE) APNDNN() (string, error) {
return "", &InvalidTypeError{Type: i.Type}
}

return utils.DecodeFQDN(i.Payload), nil
return i.ValueAsFQDN()
}

// MustAPNDNN returns APNDNN in string, ignoring errors.
Expand Down
2 changes: 1 addition & 1 deletion ie/application-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewApplicationID(instance string) *IE {
func (i *IE) ApplicationID() (string, error) {
switch i.Type {
case ApplicationID:
return string(i.Payload), nil
return i.ValueAsString()
case CreatePDR:
ies, err := i.CreatePDR()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion ie/application-instance-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewApplicationInstanceID(id string) *IE {
func (i *IE) ApplicationInstanceID() (string, error) {
switch i.Type {
case ApplicationInstanceID:
return string(i.Payload), nil
return i.ValueAsString()
case ApplicationDetectionInformation:
ies, err := i.ApplicationDetectionInformation()
if err != nil {
Expand Down
8 changes: 1 addition & 7 deletions ie/atsss-ll-control-information.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,16 @@

package ie

import "io"

// NewATSSSLLControlInformation creates a new ATSSSLLControlInformation IE.
func NewATSSSLLControlInformation(lli uint8) *IE {
return newUint8ValIE(ATSSSLLControlInformation, lli&0x01)
}

// ATSSSLLControlInformation returns ATSSSLLControlInformation in uint8 if the type of IE matches.
func (i *IE) ATSSSLLControlInformation() (uint8, error) {
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case ATSSSLLControlInformation:
return i.Payload[0], nil
return i.ValueAsUint8()
case ProvideATSSSControlInformation:
ies, err := i.ProvideATSSSControlInformation()
if err != nil {
Expand Down
8 changes: 1 addition & 7 deletions ie/atsss-ll-information.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,16 @@

package ie

import "io"

// NewATSSSLLInformation creates a new ATSSSLLInformation IE.
func NewATSSSLLInformation(lli uint8) *IE {
return newUint8ValIE(ATSSSLLInformation, lli&0x01)
}

// ATSSSLLInformation returns ATSSSLLInformation in uint8 if the type of IE matches.
func (i *IE) ATSSSLLInformation() (uint8, error) {
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case ATSSSLLInformation:
return i.Payload[0], nil
return i.ValueAsUint8()
case ATSSSControlParameters:
ies, err := i.ATSSSControlParameters()
if err != nil {
Expand Down
11 changes: 1 addition & 10 deletions ie/averaging-window.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,16 @@

package ie

import (
"encoding/binary"
"io"
)

// NewAveragingWindow creates a new AveragingWindow IE.
func NewAveragingWindow(window uint32) *IE {
return newUint32ValIE(AveragingWindow, window)
}

// AveragingWindow returns AveragingWindow in uint32 if the type of IE matches.
func (i *IE) AveragingWindow() (uint32, error) {
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case AveragingWindow:
return binary.BigEndian.Uint32(i.Payload[0:4]), nil
return i.ValueAsUint32()
case CreateQER:
ies, err := i.CreateQER()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion ie/bar-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (i *IE) BARID() (uint8, error) {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
case CreateFAR:
ies, err := i.CreateFAR()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion ie/bridge-management-information-container.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewBridgeManagementInformationContainer(info string) *IE {
func (i *IE) BridgeManagementInformationContainer() (string, error) {
switch i.Type {
case BridgeManagementInformationContainer:
return string(i.Payload), nil
return i.ValueAsString()
case TSCManagementInformationWithinSessionModificationRequest,
TSCManagementInformationWithinSessionModificationResponse,
TSCManagementInformationWithinSessionReportRequest:
Expand Down
2 changes: 1 addition & 1 deletion ie/cause.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ func (i *IE) Cause() (uint8, error) {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
}
9 changes: 1 addition & 8 deletions ie/cp-function-features.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

package ie

import (
"io"
)

// NewCPFunctionFeatures creates a new CPFunctionFeatures IE.
func NewCPFunctionFeatures(features uint8) *IE {
return newUint8ValIE(CPFunctionFeatures, features)
Expand All @@ -18,11 +14,8 @@ func (i *IE) CPFunctionFeatures() (uint8, error) {
if i.Type != CPFunctionFeatures {
return 0, &InvalidTypeError{Type: i.Type}
}
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
}

// HasLOAD reports whether an IE has LOAD bit.
Expand Down
8 changes: 1 addition & 7 deletions ie/create-bridge-info-for-tsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,16 @@

package ie

import "io"

// NewCreateBridgeInfoForTSC creates a new CreateBridgeInfoForTSC IE.
func NewCreateBridgeInfoForTSC(bii uint8) *IE {
return newUint8ValIE(CreateBridgeInfoForTSC, bii&0x01)
}

// CreateBridgeInfoForTSC returns CreateBridgeInfoForTSC in uint8 if the type of IE matches.
func (i *IE) CreateBridgeInfoForTSC() (uint8, error) {
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case CreateBridgeInfoForTSC:
return i.Payload[0], nil
return i.ValueAsUint8()
default:
return 0, &InvalidTypeError{Type: i.Type}
}
Expand Down
11 changes: 1 addition & 10 deletions ie/cumulative-rate-ratio-measurement.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,16 @@

package ie

import (
"encoding/binary"
"io"
)

// NewCumulativeRateRatioMeasurement creates a new CumulativeRateRatioMeasurement IE.
func NewCumulativeRateRatioMeasurement(measurement uint32) *IE {
return newUint32ValIE(CumulativeRateRatioMeasurement, measurement)
}

// CumulativeRateRatioMeasurement returns CumulativeRateRatioMeasurement in uint32 if the type of IE matches.
func (i *IE) CumulativeRateRatioMeasurement() (uint32, error) {
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case CumulativeRateRatioMeasurement:
return binary.BigEndian.Uint32(i.Payload[0:4]), nil
return i.ValueAsUint32()
default:
return 0, &InvalidTypeError{Type: i.Type}
}
Expand Down
11 changes: 1 addition & 10 deletions ie/cumulative-rate-ratio-threshold.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,16 @@

package ie

import (
"encoding/binary"
"io"
)

// NewCumulativeRateRatioThreshold creates a new CumulativeRateRatioThreshold IE.
func NewCumulativeRateRatioThreshold(threshold uint32) *IE {
return newUint32ValIE(CumulativeRateRatioThreshold, threshold)
}

// CumulativeRateRatioThreshold returns CumulativeRateRatioThreshold in uint32 if the type of IE matches.
func (i *IE) CumulativeRateRatioThreshold() (uint32, error) {
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case CumulativeRateRatioThreshold:
return binary.BigEndian.Uint32(i.Payload[0:4]), nil
return i.ValueAsUint32()
case ClockDriftControlInformation:
ies, err := i.ClockDriftControlInformation()
if err != nil {
Expand Down
Loading

0 comments on commit 4c75f28

Please sign in to comment.