Skip to content

Commit

Permalink
feat: add F-TEID allocation support (#840)
Browse files Browse the repository at this point in the history
* feat: add f-teid allocation support

Signed-off-by: Guillaume Belanger <[email protected]>

* chore: uses else if instead of else and then if

Signed-off-by: Guillaume Belanger <[email protected]>

---------

Signed-off-by: Guillaume Belanger <[email protected]>
  • Loading branch information
gruyaume authored Nov 28, 2024
1 parent 391b1fc commit a4170a9
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 19 deletions.
1 change: 1 addition & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ sudo
tc
TCP
tcpdump
TEID
TRex
UDP
UE
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.5.1-dev
2.0.0
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/omec-project/upf-epc

go 1.21
go 1.23

require (
github.com/Showmax/go-fqdn v1.0.0
Expand Down
75 changes: 75 additions & 0 deletions pfcpiface/fteid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Canonical Ltd.

package pfcpiface

import (
"errors"
"math"
"sync"
)

const (
minValue = 1
maxValue = math.MaxUint32
)

type FTEIDGenerator struct {
lock sync.Mutex
offset uint32
usedMap map[uint32]bool
}

func NewFTEIDGenerator() *FTEIDGenerator {
return &FTEIDGenerator{
offset: 0,
usedMap: make(map[uint32]bool),
}
}

// Allocate and return an id in range [minValue, maxValue]
func (idGenerator *FTEIDGenerator) Allocate() (uint32, error) {
idGenerator.lock.Lock()
defer idGenerator.lock.Unlock()

offsetBegin := idGenerator.offset
for {
if _, ok := idGenerator.usedMap[idGenerator.offset]; ok {
idGenerator.updateOffset()

if idGenerator.offset == offsetBegin {
return 0, errors.New("no available value range to allocate id")
}
} else {
break
}
}
idGenerator.usedMap[idGenerator.offset] = true
id := idGenerator.offset + minValue
idGenerator.updateOffset()
return id, nil
}

func (idGenerator *FTEIDGenerator) FreeID(id uint32) {
if id < minValue {
return
}
idGenerator.lock.Lock()
defer idGenerator.lock.Unlock()
delete(idGenerator.usedMap, id-minValue)
}

func (idGenerator *FTEIDGenerator) IsAllocated(id uint32) bool {
if id < minValue {
return false
}
idGenerator.lock.Lock()
defer idGenerator.lock.Unlock()
_, ok := idGenerator.usedMap[id-minValue]
return ok
}

func (idGenerator *FTEIDGenerator) updateOffset() {
idGenerator.offset++
idGenerator.offset = idGenerator.offset % maxValue
}
39 changes: 39 additions & 0 deletions pfcpiface/fteid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Canonical Ltd.

package pfcpiface_test

import (
"testing"

"github.com/omec-project/upf-epc/pfcpiface"
)

func TestFTEIDAllocate(t *testing.T) {
fteidGenerator := pfcpiface.NewFTEIDGenerator()

fteid, err := fteidGenerator.Allocate()
if err != nil {
t.Errorf("FTEID allocation failed: %v", err)
}
if fteid < 1 {
t.Errorf("FTEID allocation failed, value is too small: %v", fteid)
}
if !fteidGenerator.IsAllocated(fteid) {
t.Errorf("FTEID was not allocated")
}
}

func TestFTEIDFree(t *testing.T) {
fteidGenerator := pfcpiface.NewFTEIDGenerator()
fteid, err := fteidGenerator.Allocate()
if err != nil {
t.Errorf("FTEID allocation failed: %v", err)
}

fteidGenerator.FreeID(fteid)

if fteidGenerator.IsAllocated(fteid) {
t.Errorf("FTEID was not freed")
}
}
2 changes: 2 additions & 0 deletions pfcpiface/messages_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ func (pConn *PFCPConn) associationIEs() []*ie.IE {
setUeipFeature(features...)
}

setFTUPFeature(features...)

if upf.enableEndMarker {
setEndMarkerFeature(features...)
}
Expand Down
16 changes: 14 additions & 2 deletions pfcpiface/messages_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ func (pConn *PFCPConn) handleSessionEstablishmentRequest(msg message.Message) (m
return errProcessReply(err, ie.CauseRequestRejected)
}

if p.UPAllocateFteid {
var fteid uint32
fteid, err = pConn.upf.fteidGenerator.Allocate()
if err != nil {
return errProcessReply(err, ie.CauseNoResourcesAvailable)
}
p.tunnelTEID = fteid
p.tunnelTEIDMask = 0xFFFFFFFF
p.tunnelIP4Dst = ip2int(upf.accessIP)
p.tunnelIP4DstMask = 0xFFFFFFFF
}

p.fseidIP = fseidIP
session.CreatePDR(p)
addPDRs = append(addPDRs, p)
Expand Down Expand Up @@ -164,8 +176,7 @@ func (pConn *PFCPConn) handleSessionEstablishmentRequest(msg message.Message) (m
ie.NewCause(ie.CauseRequestAccepted), /* accept it blindly for the time being */
localFSEID,
)

addPdrInfo(seres, &session)
addPdrInfo(seres, addPDRs)

return seres, nil
}
Expand Down Expand Up @@ -231,6 +242,7 @@ func (pConn *PFCPConn) handleSessionModificationRequest(msg message.Message) (me
session.CreatePDR(p)
addPDRs = append(addPDRs, p)
}
logger.PfcpLog.Debugln("PDRs added:", addPDRs)

for _, cFAR := range smreq.CreateFAR {
var f far
Expand Down
18 changes: 10 additions & 8 deletions pfcpiface/parse_pdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,11 @@ type applicationFilter struct {
}

type pdr struct {
srcIface uint8
tunnelIP4Dst uint32
tunnelTEID uint32
ueAddress uint32
UPAllocateFteid bool
srcIface uint8
tunnelIP4Dst uint32
tunnelTEID uint32
ueAddress uint32

srcIfaceMask uint8
tunnelIP4DstMask uint32
Expand Down Expand Up @@ -390,13 +391,14 @@ func (p *pdr) parseFTEID(teidIE *ie.IE) error {
}

teid := fteid.TEID
tunnelIPv4Address := fteid.IPv4Address

if teid != 0 {
if fteid.HasCh() {
p.UPAllocateFteid = true
} else if teid != 0 {
p.tunnelTEID = teid
p.tunnelTEIDMask = 0xFFFFFFFF
p.tunnelIP4Dst = ip2int(tunnelIPv4Address)
p.tunnelIP4Dst = ip2int(fteid.IPv4Address)
p.tunnelIP4DstMask = 0xFFFFFFFF

}

return nil
Expand Down
19 changes: 12 additions & 7 deletions pfcpiface/session_pdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,28 @@ func releaseAllocatedIPs(ippool *IPPool, session *PFCPSession) error {
return ippool.DeallocIP(session.localSEID)
}
}

return nil
}

func addPdrInfo(msg *message.SessionEstablishmentResponse,
session *PFCPSession) {
func addPdrInfo(msg *message.SessionEstablishmentResponse, pdrs []pdr) {
logger.PfcpLog.Infoln("add PDRs with UPF alloc IPs to Establishment response")

for _, pdr := range session.pdrs {
logger.PfcpLog.Infoln("PDRs:", pdrs)
for _, pdr := range pdrs {
logger.PfcpLog.Infoln("pdrID:", pdr.pdrID)
if pdr.UPAllocateFteid {
logger.PfcpLog.Infoln("adding PDR with tunnel TEID:", pdr.tunnelTEID)
msg.CreatedPDR = append(msg.CreatedPDR,
ie.NewCreatedPDR(
ie.NewPDRID(uint16(pdr.pdrID)),
ie.NewFTEID(0x01, pdr.tunnelTEID, int2ip(pdr.tunnelIP4Dst), nil, 0),
))
}
if (pdr.allocIPFlag) && (pdr.srcIface == core) {
logger.PfcpLog.Debugln("pdrID:", pdr.pdrID)

var (
flags uint8 = 0x02
ueIP net.IP = int2ip(pdr.ueAddress)
)

logger.PfcpLog.Debugln("ueIP:", ueIP.String())
msg.CreatedPDR = append(msg.CreatedPDR,
ie.NewCreatedPDR(
Expand Down
2 changes: 2 additions & 0 deletions pfcpiface/upf.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type upf struct {
reportNotifyChan chan uint64
sliceInfo *SliceInfo
readTimeout time.Duration
fteidGenerator *FTEIDGenerator

datapath
maxReqRetries uint8
Expand Down Expand Up @@ -129,6 +130,7 @@ func NewUPF(conf *Conf, fp datapath) *upf {
maxReqRetries: conf.MaxReqRetries,
enableHBTimer: conf.EnableHBTimer,
readTimeout: time.Second * time.Duration(conf.ReadTimeout),
fteidGenerator: NewFTEIDGenerator(),
n4addr: conf.N4Addr,
}

Expand Down
7 changes: 7 additions & 0 deletions pfcpiface/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func setUeipFeature(features ...uint8) {
}
}

// Set the 5th bit of the first octet to 1.
func setFTUPFeature(features ...uint8) {
if len(features) >= 1 {
features[0] = features[0] | 0x10
}
}

func setEndMarkerFeature(features ...uint8) {
if len(features) >= 2 {
features[1] = features[1] | 0x01
Expand Down
25 changes: 25 additions & 0 deletions pfcpiface/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package pfcpiface

import (
"github.com/stretchr/testify/require"
"github.com/wmnsk/go-pfcp/ie"

"net"
"reflect"
Expand Down Expand Up @@ -91,3 +92,27 @@ func TestGetSliceTcMeterIndex(t *testing.T) {
)
}
}

func TestSetUeipFeature(t *testing.T) {
features := make([]uint8, 4)

setUeipFeature(features...)

ie := ie.NewUPFunctionFeatures(features...)
hasUeIPAlloc := ie.HasUEIP()
if !hasUeIPAlloc {
t.Errorf("Expected UEIPAlloc to be set")
}
}

func TestSetFTUPFeature(t *testing.T) {
features := make([]uint8, 4)

setFTUPFeature(features...)

ie := ie.NewUPFunctionFeatures(features...)
hasFTUP := ie.HasFTUP()
if !hasFTUP {
t.Errorf("Expected FTUP to be set")
}
}

0 comments on commit a4170a9

Please sign in to comment.