diff --git a/pfcp/api/far_interface.go b/pfcp/api/far_interface.go index 7c08d97..e43a2bc 100644 --- a/pfcp/api/far_interface.go +++ b/pfcp/api/far_interface.go @@ -12,9 +12,7 @@ type FARID = uint32 type FARInterface interface { ID() (FARID, error) ApplyAction() *ie.IE - SetApplyAction(*ie.IE) error ForwardingParameters() (*ie.IE, error) - SetForwardingParameters(*ie.IE) error NewCreateFAR() *ie.IE - NewUpdateFAR() *ie.IE + Update(FARUpdateInterface) error } diff --git a/pfcp/api/far_map_interface.go b/pfcp/api/far_map_interface.go index a8f4599..07b1589 100644 --- a/pfcp/api/far_map_interface.go +++ b/pfcp/api/far_map_interface.go @@ -12,12 +12,11 @@ import ( type FARMapInterface interface { Get(key FARID) (FARInterface, error) Add(far FARInterface) error - Update(far FARInterface) error + Update(far FARUpdateInterface) error Remove(key FARID) error SimulateAdd(far FARInterface) error - SimulateUpdate(far FARInterface) error + SimulateUpdate(far FARUpdateInterface) error SimulateRemove(key FARID) error Foreach(func(FARInterface) error) error IntoCreateFAR() []*ie.IE - IntoUpdateFAR() []*ie.IE } diff --git a/pfcp/api/far_map_update_interface.go b/pfcp/api/far_map_update_interface.go new file mode 100644 index 0000000..0ed7661 --- /dev/null +++ b/pfcp/api/far_map_update_interface.go @@ -0,0 +1,14 @@ +// Copyright Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package api + +import "github.com/wmnsk/go-pfcp/ie" + +type FARMapUpdateInterface interface { + Add(far FARUpdateInterface) error + IntoUpdateFAR() []*ie.IE + Foreach(f func(FARUpdateInterface) error) error +} diff --git a/pfcp/api/far_update_interface.go b/pfcp/api/far_update_interface.go new file mode 100644 index 0000000..bc8fec5 --- /dev/null +++ b/pfcp/api/far_update_interface.go @@ -0,0 +1,15 @@ +// Copyright Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package api + +import "github.com/wmnsk/go-pfcp/ie" + +type FARUpdateInterface interface { + ID() (FARID, error) + ApplyAction() *ie.IE + UpdateForwardingParameters() *ie.IE + NewUpdateFAR() *ie.IE +} diff --git a/pfcp/api/session_interface.go b/pfcp/api/session_interface.go index 6397f5b..589c492 100644 --- a/pfcp/api/session_interface.go +++ b/pfcp/api/session_interface.go @@ -21,7 +21,7 @@ type PFCPSessionInterface interface { GetSortedPDRIDs() []PDRID GetPDR(pdrid PDRID) (PDRInterface, error) GetFAR(farid FARID) (FARInterface, error) - AddUpdatePDRsFARs(createpdrs PDRMapInterface, createfars FARMapInterface, updatepdr PDRMapInterface, updatefars FARMapInterface) error + AddUpdatePDRsFARs(createpdrs PDRMapInterface, createfars FARMapInterface, updatepdr PDRMapInterface, updatefars FARMapUpdateInterface) error // SetRemoteFSEID(FSEID *ie.IE) Setup() error ForeachUnsortedPDR(f func(pdr PDRInterface) error) error diff --git a/pfcp/far.go b/pfcp/far.go index f4a36c1..198a9aa 100644 --- a/pfcp/far.go +++ b/pfcp/far.go @@ -33,11 +33,6 @@ func (far *FAR) ApplyAction() *ie.IE { return far.applyAction } -func (far *FAR) SetApplyAction(aa *ie.IE) error { - far.applyAction = aa - return nil -} - func (far *FAR) ForwardingParameters() (*ie.IE, error) { // This IE shall be present when the Apply Action requests // the packets to be forwarded. It may be present otherwise. @@ -48,11 +43,6 @@ func (far *FAR) ForwardingParameters() (*ie.IE, error) { } -func (far *FAR) SetForwardingParameters(fp *ie.IE) error { - far.forwardingParameters = fp - return nil -} - func (far *FAR) NewCreateFAR() *ie.IE { ies := make([]*ie.IE, 0) ies = append(ies, far.id) @@ -63,12 +53,45 @@ func (far *FAR) NewCreateFAR() *ie.IE { return ie.NewCreateFAR(ies...) } -func (far *FAR) NewUpdateFAR() *ie.IE { - ies := make([]*ie.IE, 0) - ies = append(ies, far.id) - ies = append(ies, far.applyAction) - if far.forwardingParameters != nil { - ies = append(ies, far.forwardingParameters) +func (far *FAR) Update(farUpdate api.FARUpdateInterface) error { + // Check FARID + farUpdateId, err := farUpdate.ID() + if err != nil { + return err + } + farId, err := far.ID() + if err != nil { + return err + } + if farId != farUpdateId { + return fmt.Errorf("Wrong FAR ID") + } + + // Update ApplyAction + if aa := farUpdate.ApplyAction(); aa != nil { + far.applyAction = aa } - return ie.NewUpdateFAR(ies...) + + // Update Forwarding Parameters + ForwParam := make([]*ie.IE, 0) + if fp := farUpdate.UpdateForwardingParameters(); fp != nil { + if di, err := fp.DestinationInterface(); err == nil { + ForwParam = append(ForwParam, ie.NewDestinationInterface(di)) + } else if diorg, err := far.forwardingParameters.DestinationInterface(); err == nil { + ForwParam = append(ForwParam, ie.NewDestinationInterface(diorg)) + } + if ni, err := fp.NetworkInstance(); err == nil { + ForwParam = append(ForwParam, ie.NewNetworkInstance(ni)) + } else if niorg, err := far.forwardingParameters.NetworkInstance(); err == nil { + ForwParam = append(ForwParam, ie.NewNetworkInstance(niorg)) + } + if ohc, err := fp.OuterHeaderCreation(); err == nil { + ForwParam = append(ForwParam, ie.NewOuterHeaderCreation(ohc.OuterHeaderCreationDescription, ohc.TEID, ohc.IPv4Address.String(), ohc.IPv6Address.String(), ohc.PortNumber, ohc.CTag, ohc.STag)) + } else if ohcorg, err := far.forwardingParameters.OuterHeaderCreation(); err == nil { + ForwParam = append(ForwParam, ie.NewOuterHeaderCreation(ohcorg.OuterHeaderCreationDescription, ohcorg.TEID, ohcorg.IPv4Address.String(), ohcorg.IPv6Address.String(), ohcorg.PortNumber, ohcorg.CTag, ohcorg.STag)) + } + far.forwardingParameters = ie.NewForwardingParameters(ForwParam...) + } + + return nil } diff --git a/pfcp/far_map.go b/pfcp/far_map.go index 5b8ecdb..27de007 100644 --- a/pfcp/far_map.go +++ b/pfcp/far_map.go @@ -68,41 +68,25 @@ func (m *FARMap) SimulateAdd(far api.FARInterface) error { return nil } -func (m *FARMap) Update(far api.FARInterface) error { +func (m *FARMap) Update(farUpdate api.FARUpdateInterface) error { logrus.Trace("Inside farmap.Update()") // only present fields are replaced - id, err := far.ID() + id, err := farUpdate.ID() if err != nil { return err } m.mu.Lock() defer m.mu.Unlock() - if _, exists := m.farmap[id]; !exists { + if far, exists := m.farmap[id]; !exists { logrus.WithFields(logrus.Fields{"far-id": id, "current_map": m.farmap}).Trace("Updating FAR: this FAR id does not exist") return fmt.Errorf("FAR %d does not exist.", id) } else { logrus.WithFields(logrus.Fields{"far-id": id}).Trace("Updating FAR") - if far.ApplyAction() != nil { - m.farmap[id].SetApplyAction(far.ApplyAction()) - logrus.WithFields(logrus.Fields{"far-id": id}).Trace("Updating FAR Apply Action") - } - // XXX: update fields in forwarding parameters instead of replacing - if fp, err := far.ForwardingParameters(); err == nil { - if fp == nil { - logrus.Warn("Removing forwarding parameters. aborting") - return nil - } - m.farmap[id].SetForwardingParameters(fp) - logrus.WithFields(logrus.Fields{"far-id": id}).Trace("Updating FAR Forwarding Parameters") - } else { - logrus.WithFields(logrus.Fields{"far-id": id}).Trace("Updating FAR but not Forwarding Parameters") - } - - return nil + return far.Update(farUpdate) } } -func (m *FARMap) SimulateUpdate(far api.FARInterface) error { +func (m *FARMap) SimulateUpdate(far api.FARUpdateInterface) error { logrus.Trace("Inside farmap.SimulateUpdate()") id, err := far.ID() if err != nil { @@ -202,39 +186,6 @@ func NewFARMap(fars []*ie.IE) (farmap *FARMap, err error, cause uint8, offending } -func NewFARMapUpdate(fars []*ie.IE) (*FARMap, error, uint8, uint16) { - f := FARMap{ - farmap: make(farmapInternal), - mu: sync.RWMutex{}, - } - for _, far := range fars { - id, err := far.FARID() - if err != nil { - switch err { - case io.ErrUnexpectedEOF: - return nil, err, ie.CauseInvalidLength, ie.FARID - case ie.ErrIENotFound: - return nil, err, ie.CauseMandatoryIEMissing, ie.FARID - default: - return nil, err, ie.CauseMandatoryIEIncorrect, ie.CreateFAR - } - } - var ieaa *ie.IE = nil - aa, err := far.ApplyAction() - if err == nil { - ieaa = ie.NewApplyAction(aa...) - } - var iefp *ie.IE = nil - fp, err := far.UpdateForwardingParameters() - if err == nil { - iefp = ie.NewForwardingParameters(fp...) - } - f.Add(NewFAR(ie.NewFARID(id), ieaa, iefp)) - } - return &f, nil, 0, 0 - -} - func (m *FARMap) IntoCreateFAR() []*ie.IE { m.mu.RLock() defer m.mu.RUnlock() @@ -248,17 +199,3 @@ func (m *FARMap) IntoCreateFAR() []*ie.IE { } return r } - -func (m *FARMap) IntoUpdateFAR() []*ie.IE { - m.mu.RLock() - defer m.mu.RUnlock() - r := make([]*ie.IE, len(m.farmap)) - - // _ is farID, which is different from index - i := 0 - for _, far := range m.farmap { - r[i] = far.NewUpdateFAR() - i++ - } - return r -} diff --git a/pfcp/far_map_update.go b/pfcp/far_map_update.go new file mode 100644 index 0000000..d8b6050 --- /dev/null +++ b/pfcp/far_map_update.go @@ -0,0 +1,94 @@ +// Copyright Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package pfcp_networking + +import ( + "fmt" + "io" + "sync" + + "github.com/nextmn/go-pfcp-networking/pfcp/api" + + "github.com/wmnsk/go-pfcp/ie" +) + +type farmapUpdateInternal = map[api.FARID]api.FARUpdateInterface + +type FARMapUpdate struct { + farmap farmapUpdateInternal + mu sync.RWMutex +} + +func NewFARMapUpdate(fars []*ie.IE) (*FARMapUpdate, error, uint8, uint16) { + f := FARMapUpdate{ + farmap: make(farmapUpdateInternal), + mu: sync.RWMutex{}, + } + for _, far := range fars { + id, err := far.FARID() + if err != nil { + switch err { + case io.ErrUnexpectedEOF: + return nil, err, ie.CauseInvalidLength, ie.FARID + case ie.ErrIENotFound: + return nil, err, ie.CauseMandatoryIEMissing, ie.FARID + default: + return nil, err, ie.CauseMandatoryIEIncorrect, ie.CreateFAR + } + } + var ieaa *ie.IE = nil + aa, err := far.ApplyAction() + if err == nil { + ieaa = ie.NewApplyAction(aa...) + } + var iefp *ie.IE = nil + fp, err := far.UpdateForwardingParameters() + if err == nil { + iefp = ie.NewUpdateForwardingParameters(fp...) + } + f.Add(NewFARUpdate(ie.NewFARID(id), ieaa, iefp)) + } + return &f, nil, 0, 0 + +} + +func (m *FARMapUpdate) Add(far api.FARUpdateInterface) error { + id, err := far.ID() + if err != nil { + return err + } + m.mu.Lock() + defer m.mu.Unlock() + if _, exists := m.farmap[id]; exists { + return fmt.Errorf("FAR %d already exists.", id) + } + m.farmap[id] = far + return nil +} + +func (m *FARMapUpdate) IntoUpdateFAR() []*ie.IE { + m.mu.RLock() + defer m.mu.RUnlock() + r := make([]*ie.IE, len(m.farmap)) + + // _ is farID, which is different from index + i := 0 + for _, far := range m.farmap { + r[i] = far.NewUpdateFAR() + i++ + } + return r +} + +func (m *FARMapUpdate) Foreach(f func(api.FARUpdateInterface) error) error { + for _, far := range m.farmap { + err := f(far) + if err != nil { + return err + } + } + return nil +} diff --git a/pfcp/far_update.go b/pfcp/far_update.go new file mode 100644 index 0000000..73a57ea --- /dev/null +++ b/pfcp/far_update.go @@ -0,0 +1,50 @@ +// Copyright Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package pfcp_networking + +import ( + "github.com/nextmn/go-pfcp-networking/pfcp/api" + + "github.com/wmnsk/go-pfcp/ie" +) + +type FARUpdate struct { + id *ie.IE + applyAction *ie.IE + updateForwardingParameters *ie.IE +} + +func NewFARUpdate(id *ie.IE, applyAction *ie.IE, updateForwardingParameters *ie.IE) *FARUpdate { + return &FARUpdate{ + id: id, + applyAction: applyAction, + updateForwardingParameters: updateForwardingParameters, + } +} + +func (far *FARUpdate) ID() (api.FARID, error) { + return far.id.FARID() +} + +func (far *FARUpdate) ApplyAction() *ie.IE { + return far.applyAction +} + +func (far *FARUpdate) UpdateForwardingParameters() *ie.IE { + return far.updateForwardingParameters +} + +func (far *FARUpdate) NewUpdateFAR() *ie.IE { + ies := make([]*ie.IE, 0) + ies = append(ies, far.id) + if far.applyAction != nil { + ies = append(ies, far.applyAction) + } + if far.updateForwardingParameters != nil { + ies = append(ies, far.updateForwardingParameters) + } + return ie.NewUpdateFAR(ies...) +} diff --git a/pfcp/session.go b/pfcp/session.go index ea25525..83cdb11 100644 --- a/pfcp/session.go +++ b/pfcp/session.go @@ -173,7 +173,7 @@ func (s *PFCPSession) GetFAR(farid api.FARID) (api.FARInterface, error) { } // Add/Update PDRs and FARs to the session -func (s *PFCPSession) AddUpdatePDRsFARs(createpdrs api.PDRMapInterface, createfars api.FARMapInterface, updatepdrs api.PDRMapInterface, updatefars api.FARMapInterface) error { +func (s *PFCPSession) AddUpdatePDRsFARs(createpdrs api.PDRMapInterface, createfars api.FARMapInterface, updatepdrs api.PDRMapInterface, updatefars api.FARMapUpdateInterface) error { // Transactions must be atomic to avoid having a PDR referring to a deleted FAR / not yet created FAR s.atomicMu.Lock() defer s.atomicMu.Unlock() @@ -186,7 +186,7 @@ func (s *PFCPSession) AddUpdatePDRsFARs(createpdrs api.PDRMapInterface, createfa }); err != nil { return err } - if err := updatefars.Foreach(func(far api.FARInterface) error { + if err := updatefars.Foreach(func(far api.FARUpdateInterface) error { return s.far.SimulateUpdate(far) }); err != nil { return err @@ -212,7 +212,7 @@ func (s *PFCPSession) AddUpdatePDRsFARs(createpdrs api.PDRMapInterface, createfa }); err != nil { return err } - if err := updatefars.Foreach(func(far api.FARInterface) error { + if err := updatefars.Foreach(func(far api.FARUpdateInterface) error { return s.far.Update(far) }); err != nil { return err