Closed herugen closed 4 years ago
this is how we are using it https://github.com/omec-project/upf-epc/blob/topics/misc_updates/pfcpiface/parser.go#L225-L257
Due to the lack of consideration, we cannot retrieve multiple IEs by accessing fields of a Message with the current code base, but @krsna1729's workaround works.
In the near future I'll update the struct definitions of messages.
FYI, the new release will contain this change, too: https://github.com/wmnsk/go-pfcp/pull/45#issuecomment-663345738 Sorry for breaking changes but please understand this project is still not tested enough...
@wmnsk are you planning on connection/session handling development too, like in go-gtp?
@wmnsk This library has saved us a lot of work. The code is really clean. We too are developing at a fast pace so no worries at all regarding breaking changes at the moment
@krsna1729 Thanks!
are you planning on connection/session handling development too, like in go-gtp?
Yes, I've been working on that little by little. It'll be something similar to go-gtp's gtpv2c
package (hopefully it could be a bit more simple). Actually it's planned to be released in mid-July but delaying for some personal reasons (July is ending... 🙃).
this is how we are using it https://github.com/omec-project/upf-epc/blob/topics/misc_updates/pfcpiface/parser.go#L225-L257
This is a good solution for single type multiple IEs, but 29244 have so many multiple IE array definitions,I'm looking forward to wmnsk's solution, hope its clean & gorgeous
The idea currently in my mind is just to change the field type to []*ie.IE
for all the fields which have this description: "Several IEs with the same IE type may be present to represent multiple..." in the specification (it should be described more explicitly, 3GPP...). Not sure this is clean & gorgeous way, though 🙂
FYI, as another workaround, you can find the second(or third, fourth, ...) CreatePDR IE in IEs
field into which undefined IEs are parced.
https://github.com/wmnsk/go-pfcp/blob/master/message/session-establishment-request.go
@wmnsk I updated array IEs in session establishment request like this, can this work around?
(EDIT: code block formatting)
// Copyright 2019-2020 go-pfcp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
package message
import (
"github.com/wmnsk/go-pfcp/ie"
)
// SessionEstablishmentRequest is a SessionEstablishmentRequest formed PFCP Header and its IEs above.
type SessionEstablishmentRequest struct {
*Header
NodeID *ie.IE
CPFSEID *ie.IE
CreatePDR []*ie.IE
CreateFAR []*ie.IE
CreateURR []*ie.IE
CreateQER []*ie.IE
CreateBAR *ie.IE
CreateTrafficEndpoint []*ie.IE
PDNType *ie.IE
FQCSID *ie.IE
UserPlaneInactivityTimer *ie.IE
UserID *ie.IE
TraceInformation *ie.IE
APNDNN *ie.IE
CreateMAR []*ie.IE
PFCPSEReqFlags *ie.IE
CreateBridgeInfoForTSC *ie.IE
CreateSRR []*ie.IE
ProvideATSSSControlInformation *ie.IE
RecoveryTimeStamp *ie.IE
IEs []*ie.IE
}
// NewSessionEstablishmentRequest creates a new SessionEstablishmentRequest.
func NewSessionEstablishmentRequest(mp, fo uint8, seid uint64, seq uint32, pri uint8, ies ...*ie.IE) *SessionEstablishmentRequest {
m := &SessionEstablishmentRequest{
Header: NewHeader(
1, fo, mp, 1,
MsgTypeSessionEstablishmentRequest, seid, seq, pri,
nil,
),
}
for _, i := range ies {
switch i.Type {
case ie.NodeID:
m.NodeID = i
case ie.FSEID:
m.CPFSEID = i
case ie.CreatePDR:
m.CreatePDR = append(m.CreatePDR, i)
case ie.CreateFAR:
m.CreateFAR = append(m.CreateFAR, i)
case ie.CreateURR:
m.CreateURR = append(m.CreateURR, i)
case ie.CreateQER:
m.CreateQER = append(m.CreateQER, i)
case ie.CreateBAR:
m.CreateBAR = i
case ie.CreateTrafficEndpoint:
m.CreateTrafficEndpoint = append(m.CreateTrafficEndpoint, i)
case ie.PDNType:
m.PDNType = i
case ie.FQCSID:
m.FQCSID = i
case ie.UserPlaneInactivityTimer:
m.UserPlaneInactivityTimer = i
case ie.UserID:
m.UserID = i
case ie.TraceInformation:
m.TraceInformation = i
case ie.APNDNN:
m.APNDNN = i
case ie.CreateMAR:
m.CreateMAR = append(m.CreateMAR, i)
case ie.PFCPSEReqFlags:
m.PFCPSEReqFlags = i
case ie.CreateBridgeInfoForTSC:
m.CreateBridgeInfoForTSC = i
case ie.CreateSRR:
m.CreateSRR = append(m.CreateSRR, i)
case ie.ProvideATSSSControlInformation:
m.ProvideATSSSControlInformation = i
case ie.RecoveryTimeStamp:
m.RecoveryTimeStamp = i
default:
m.IEs = append(m.IEs, i)
}
}
m.SetLength()
return m
}
// Marshal returns the byte sequence generated from a SessionEstablishmentRequest.
func (m *SessionEstablishmentRequest) Marshal() ([]byte, error) {
b := make([]byte, m.MarshalLen())
if err := m.MarshalTo(b); err != nil {
return nil, err
}
return b, nil
}
// MarshalTo puts the byte sequence in the byte array given as b.
func (m *SessionEstablishmentRequest) MarshalTo(b []byte) error {
if m.Header.Payload != nil {
m.Header.Payload = nil
}
m.Header.Payload = make([]byte, m.MarshalLen()-m.Header.MarshalLen())
offset := 0
if i := m.NodeID; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.CPFSEID; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
for _, pdr := range m.CreatePDR {
if i := pdr; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
for _, far := range m.CreateFAR {
if i := far; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
for _, urr := range m.CreateURR {
if i := urr; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
for _, qer := range m.CreateQER {
if i := qer; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
if i := m.CreateBAR; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
for _, endpoint := range m.CreateTrafficEndpoint {
if i := endpoint; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
if i := m.PDNType; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.FQCSID; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.UserPlaneInactivityTimer; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.UserID; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.TraceInformation; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.APNDNN; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
for _, mar := range m.CreateMAR {
if i := mar; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
if i := m.PFCPSEReqFlags; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.CreateBridgeInfoForTSC; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
for _, srr := range m.CreateSRR {
if i := srr; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
}
if i := m.ProvideATSSSControlInformation; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
if i := m.RecoveryTimeStamp; i != nil {
if err := i.MarshalTo(m.Payload[offset:]); err != nil {
return err
}
offset += i.MarshalLen()
}
for _, ie := range m.IEs {
if ie == nil {
continue
}
if err := ie.MarshalTo(m.Header.Payload[offset:]); err != nil {
return err
}
offset += ie.MarshalLen()
}
m.Header.SetLength()
return m.Header.MarshalTo(b)
}
// ParseSessionEstablishmentRequest decodes a given byte sequence as a SessionEstablishmentRequest.
func ParseSessionEstablishmentRequest(b []byte) (*SessionEstablishmentRequest, error) {
m := &SessionEstablishmentRequest{}
if err := m.UnmarshalBinary(b); err != nil {
return nil, err
}
return m, nil
}
// UnmarshalBinary decodes a given byte sequence as a SessionEstablishmentRequest.
func (m *SessionEstablishmentRequest) UnmarshalBinary(b []byte) error {
var err error
m.Header, err = ParseHeader(b)
if err != nil {
return err
}
if len(m.Header.Payload) < 2 {
return nil
}
ies, err := ie.ParseMultiIEs(m.Header.Payload)
if err != nil {
return err
}
for _, i := range ies {
switch i.Type {
case ie.NodeID:
m.NodeID = i
case ie.FSEID:
m.CPFSEID = i
case ie.CreatePDR:
m.CreatePDR = append(m.CreatePDR, i)
case ie.CreateFAR:
m.CreateFAR = append(m.CreateFAR, i)
case ie.CreateURR:
m.CreateURR = append(m.CreateURR, i)
case ie.CreateQER:
m.CreateQER = append(m.CreateQER, i)
case ie.CreateBAR:
m.CreateBAR = i
case ie.CreateTrafficEndpoint:
m.CreateTrafficEndpoint = append(m.CreateTrafficEndpoint, i)
case ie.PDNType:
m.PDNType = i
case ie.FQCSID:
m.FQCSID = i
case ie.UserPlaneInactivityTimer:
m.UserPlaneInactivityTimer = i
case ie.UserID:
m.UserID = i
case ie.TraceInformation:
m.TraceInformation = i
case ie.APNDNN:
m.APNDNN = i
case ie.CreateMAR:
m.CreateMAR = append(m.CreateMAR, i)
case ie.PFCPSEReqFlags:
m.PFCPSEReqFlags = i
case ie.CreateBridgeInfoForTSC:
m.CreateBridgeInfoForTSC = i
case ie.CreateSRR:
m.CreateSRR = append(m.CreateSRR, i)
case ie.ProvideATSSSControlInformation:
m.ProvideATSSSControlInformation = i
case ie.RecoveryTimeStamp:
m.RecoveryTimeStamp = i
default:
m.IEs = append(m.IEs, i)
}
}
return nil
}
// MarshalLen returns the serial length of Data.
func (m *SessionEstablishmentRequest) MarshalLen() int {
l := m.Header.MarshalLen() - len(m.Header.Payload)
if i := m.NodeID; i != nil {
l += i.MarshalLen()
}
if i := m.CPFSEID; i != nil {
l += i.MarshalLen()
}
for _, pdr := range m.CreatePDR {
if i := pdr; i != nil {
l += i.MarshalLen()
}
}
for _, far := range m.CreateFAR {
if i := far; i != nil {
l += i.MarshalLen()
}
}
for _, urr := range m.CreateURR {
if i := urr; i != nil {
l += i.MarshalLen()
}
}
for _, qer := range m.CreateQER {
if i := qer; i != nil {
l += i.MarshalLen()
}
}
if i := m.CreateBAR; i != nil {
l += i.MarshalLen()
}
for _, endpoint := range m.CreateTrafficEndpoint {
if i := endpoint; i != nil {
l += i.MarshalLen()
}
}
if i := m.PDNType; i != nil {
l += i.MarshalLen()
}
if i := m.FQCSID; i != nil {
l += i.MarshalLen()
}
if i := m.UserPlaneInactivityTimer; i != nil {
l += i.MarshalLen()
}
if i := m.UserID; i != nil {
l += i.MarshalLen()
}
if i := m.TraceInformation; i != nil {
l += i.MarshalLen()
}
if i := m.APNDNN; i != nil {
l += i.MarshalLen()
}
for _, mar := range m.CreateMAR {
if i := mar; i != nil {
l += i.MarshalLen()
}
}
if i := m.PFCPSEReqFlags; i != nil {
l += i.MarshalLen()
}
if i := m.CreateBridgeInfoForTSC; i != nil {
l += i.MarshalLen()
}
for _, srr := range m.CreateSRR {
if i := srr; i != nil {
l += i.MarshalLen()
}
}
if i := m.ProvideATSSSControlInformation; i != nil {
l += i.MarshalLen()
}
if i := m.RecoveryTimeStamp; i != nil {
l += i.MarshalLen()
}
for _, ie := range m.IEs {
if ie == nil {
continue
}
l += ie.MarshalLen()
}
return l
}
// SetLength sets the length in Length field.
func (m *SessionEstablishmentRequest) SetLength() {
m.Header.Length = uint16(m.MarshalLen() - 4)
}
// MessageTypeName returns the name of protocol.
func (m *SessionEstablishmentRequest) MessageTypeName() string {
return "Session Establishment Request"
}
// SEID returns the SEID in uint64.
func (m *SessionEstablishmentRequest) SEID() uint64 {
return m.Header.seid()
}
yes ideally the struct definitions will need to be slices and we iterate through and parse all these only once - in the library. @TheWayYouMakeMeFeel can you open a PR. I am sure it will help @wmnsk and us too :)
yes ideally the struct definitions will need to be slices and we iterate through and parse all these only once - in the library. @TheWayYouMakeMeFeel can you open a PR. I am sure it will help @wmnsk and us too :)
I'm working on messages now, haven't done yet
@krsna1729 @wmnsk It may take much longer than I thought before opening the PR, the code needs much more test. I've found some bugs and working on it.
Thank you for working on this 😉 Perhaps opening a draft PR help us discuss “some bugs”? Let me know if you need any help, anyway.
@wmnsk @krsna1729 sorry for delay so long, i've make a pull request to close this issue, refers to "re-pull request "make message support IE array, IE support sub IE array" #52"
Hi, thanks for your gorgeous code, it really helps a lot! I know that this code done perfect with single IE & group IE & all kinds of messages, but I don't know how to code with array IEs, like multi CreatePDR in one SessionEstablishmentRequest,or multi URRID in one CreatePDR. Does this code done with this kind of array IEs, how to use it? Please tell me, thanks a lot!