Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Remove internal application and release ID if not used by any… #595

Merged
merged 1 commit into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 51 additions & 113 deletions pfcpiface/up4.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,7 @@ var (
p4RtcServerPort = flag.String("p4RtcServerPort", "", "P4 Server port")
)

// internalAppReference <F-SEID (UE session); PDR-ID> pair that
// uniquely identifies application filter among different PDR IEs of the same UE session.
type internalAppReference struct {
fseid uint64
pdrID uint32
}

type internalApp struct {
id uint8
// usedBy keeps track of <F-SEID (UE session); PDR-ID> pairs using this application filter.
usedBy set.Set
}

type up4ApplicationFilter struct {
type application struct {
appIP uint32
appL4Port portRange
appProto uint8
Expand Down Expand Up @@ -133,8 +120,7 @@ type UP4 struct {
tunnelPeerMu sync.Mutex
tunnelPeerIDs map[tunnelParams]tunnelPeer
tunnelPeerIDsPool []uint8
applicationMu sync.Mutex
applicationIDs map[up4ApplicationFilter]internalApp
applicationIDs map[application]uint8
applicationIDsPool []uint8

// meters stores the mapping from <F-SEID; QER ID> -> P4 Meter Cell ID.
Expand All @@ -156,25 +142,6 @@ type UP4 struct {
endMarkerChan chan []byte
}

func toUP4ApplicationFilter(p pdr) up4ApplicationFilter {
var appFilter up4ApplicationFilter
if p.IsUplink() {
appFilter = up4ApplicationFilter{
appIP: p.appFilter.dstIP,
appL4Port: p.appFilter.dstPortRange,
}
} else if p.IsDownlink() {
appFilter = up4ApplicationFilter{
appIP: p.appFilter.srcIP,
appL4Port: p.appFilter.srcPortRange,
}
}

appFilter.appProto = p.appFilter.proto

return appFilter
}

func (m meter) String() string {
return fmt.Sprintf("Meter(type=%d, uplinkCellID=%d, downlinkCellID=%d)",
m.meterType, m.uplinkCellID, m.downlinkCellID)
Expand Down Expand Up @@ -379,7 +346,7 @@ func (up4 *UP4) initTunnelPeerIDs() {
}

func (up4 *UP4) initApplicationIDs() {
up4.applicationIDs = make(map[up4ApplicationFilter]internalApp)
up4.applicationIDs = make(map[application]uint8)
// a simple queue storing available application IDs
// 0 is reserved;
up4.applicationIDsPool = make([]uint8, 0, maxApplicationIDs)
Expand Down Expand Up @@ -785,7 +752,7 @@ func (up4 *UP4) removeGTPTunnelPeer(far far) {
}

// Returns error if we reach maximum supported Application IDs.
func (up4 *UP4) unsafeAllocateInternalApplicationID() (uint8, error) {
func (up4 *UP4) allocateInternalApplicationID(app application) (uint8, error) {
if len(up4.applicationIDsPool) == 0 {
return 0, ErrOperationFailedWithReason("allocate Application ID",
"no free application IDs available")
Expand All @@ -795,83 +762,53 @@ func (up4 *UP4) unsafeAllocateInternalApplicationID() (uint8, error) {
allocated := up4.applicationIDsPool[0]
up4.applicationIDsPool = up4.applicationIDsPool[1:]

return allocated, nil
}
up4.applicationIDs[app] = allocated

func (up4 *UP4) unsafeReleaseInternalApplicationID(appFilter up4ApplicationFilter) {
allocated, exists := up4.applicationIDs[appFilter]
if exists {
up4.applicationIDsPool = append(up4.applicationIDsPool, allocated.id)
delete(up4.applicationIDs, appFilter)
}
return allocated, nil
}

func (up4 *UP4) addInternalApplicationIDAndGetP4rtEntry(pdr pdr) (*p4.TableEntry, uint8, error) {
up4.applicationMu.Lock()
defer up4.applicationMu.Unlock()

appFilter := toUP4ApplicationFilter(pdr)
if up4Application, exists := up4.applicationIDs[appFilter]; exists {
// application already exists, increment 'usedBy'.
// since we use Set usedBy will not be incremented if
// application was already created for this UE session + PDR ID.
up4Application.usedBy.Add(internalAppReference{
pdr.fseID, pdr.pdrID,
})

return nil, up4Application.id, nil
}

newAppID, err := up4.unsafeAllocateInternalApplicationID()
if err != nil {
return nil, 0, err
}

up4Application := internalApp{
id: newAppID,
usedBy: set.NewSet(internalAppReference{
pdr.fseID, pdr.pdrID,
}),
// FIXME: SDFAB-960
//nolint:unused
func (up4 *UP4) releaseInternalApplicationID(appFilter applicationFilter) {
app := application{
appIP: appFilter.srcIP,
appL4Port: appFilter.srcPortRange,
appProto: appFilter.proto,
}

applicationsEntry, err := up4.p4RtTranslator.BuildApplicationsTableEntry(pdr, up4.conf.SliceID, newAppID)
if err != nil {
up4.unsafeReleaseInternalApplicationID(appFilter)
return nil, 0, ErrOperationFailedWithReason("build P4rt table entry for Applications table", err.Error())
allocated, exists := up4.applicationIDs[app]
if exists {
delete(up4.applicationIDs, app)
up4.applicationIDsPool = append(up4.applicationIDsPool, allocated)
}

up4.applicationIDs[appFilter] = up4Application

return applicationsEntry, up4Application.id, nil
}

func (up4 *UP4) removeInternalApplicationIDAndGetP4rtEntry(pdr pdr) (*p4.TableEntry, uint8) {
up4.applicationMu.Lock()
defer up4.applicationMu.Unlock()

appFilter := toUP4ApplicationFilter(pdr)

internalApp, exists := up4.applicationIDs[appFilter]
if !exists {
return nil, 0
func (up4 *UP4) getOrAllocateInternalApplicationID(pdr pdr) (uint8, error) {
var app application
if pdr.IsUplink() {
app = application{
appIP: pdr.appFilter.dstIP,
appL4Port: pdr.appFilter.dstPortRange,
}
} else if pdr.IsDownlink() {
app = application{
appIP: pdr.appFilter.srcIP,
appL4Port: pdr.appFilter.srcPortRange,
}
}

internalApp.usedBy.Remove(internalAppReference{
pdr.fseID, pdr.pdrID,
})
app.appProto = pdr.appFilter.proto

if internalApp.usedBy.Cardinality() != 0 {
return nil, internalApp.id
if allocated, exists := up4.applicationIDs[app]; exists {
return allocated, nil
}

applicationsEntry, err := up4.p4RtTranslator.BuildApplicationsTableEntry(pdr, up4.conf.SliceID, internalApp.id)
newAppID, err := up4.allocateInternalApplicationID(app)
if err != nil {
return nil, internalApp.id
return 0, err
}

up4.unsafeReleaseInternalApplicationID(appFilter)

return applicationsEntry, internalApp.id
return newAppID, nil
}

func (up4 *UP4) allocateAppMeterCellID() (uint32, error) {
Expand Down Expand Up @@ -1315,26 +1252,27 @@ func (up4 *UP4) modifyUP4ForwardingConfiguration(pdrs []pdr, allFARs []far, qers
pdr.ueAddress = ueAddr
}

var applicationsEntry *p4.TableEntry

// as a default value is installed if no application filtering rule exists
var applicationID uint8 = DefaultApplicationID

if !pdr.IsAppFilterEmpty() {
if methodType != p4.Update_DELETE {
if entry, appID, err := up4.addInternalApplicationIDAndGetP4rtEntry(pdr); err == nil {
if entry != nil {
entriesToApply = append(entriesToApply, entry)
}

applicationID = appID
}
} else {
entry, appID := up4.removeInternalApplicationIDAndGetP4rtEntry(pdr)
if entry != nil {
entriesToApply = append(entriesToApply, entry)
}
applicationID, err = up4.getOrAllocateInternalApplicationID(pdr)
if err != nil {
pdrLog.Error("failed to get or allocate internal application ID")
return err
}
}

applicationID = appID
// TODO: the same app filter can be simultaneously used by another UE session. We cannot remove it.
// We should come up with a way to check if an app filter is still in use.
if applicationID != 0 && methodType != p4.Update_DELETE {
applicationsEntry, err = up4.p4RtTranslator.BuildApplicationsTableEntry(pdr, up4.conf.SliceID, applicationID)
if err != nil {
return ErrOperationFailedWithReason("build P4rt table entry for Applications table", err.Error())
}

entriesToApply = append(entriesToApply, applicationsEntry)
}

var appMeter = meter{meterTypeApplication, 0, 0}
Expand Down
49 changes: 39 additions & 10 deletions test/integration/basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/omec-project/pfcpsim/pkg/pfcpsim/session"
"github.com/omec-project/upf-epc/test/integration/providers"
"github.com/stretchr/testify/require"
"github.com/wmnsk/go-pfcp/ie"
)
Expand Down Expand Up @@ -40,7 +41,9 @@ func TestUPFBasedUeIPAllocation(t *testing.T) {
expected: p4RtValues{
// first IP address from pool configured in ue_ip_alloc.json
ueAddress: "10.250.0.1",
tc: 3,
// no application filtering rule expected
appID: 0,
tc: 3,
},
desc: "UPF-based UE IP allocation",
}
Expand Down Expand Up @@ -87,7 +90,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 3,
appID: 1,
tc: 3,
},
desc: "APPLICATION FILTERING permit out udp from any 80-80 to assigned",
},
Expand All @@ -111,7 +115,10 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 100,
},
},
tc: 3,
// FIXME: there is a dependency on previous test because pfcpiface doesn't clear application IDs properly
// See SDFAB-960
appID: 2,
tc: 3,
},
desc: "APPLICATION FILTERING permit out udp from 192.168.1.1/32 to assigned 80-100",
},
Expand All @@ -128,7 +135,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
},
expected: p4RtValues{
// no application filtering rule expected
tc: 3,
appID: 0,
tc: 3,
},
desc: "APPLICATION FILTERING ALLOW_ALL",
},
Expand Down Expand Up @@ -160,7 +168,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 3,
appID: 1,
tc: 3,
},
desc: "QER_METERING - 1 session QER, 2 app QERs",
},
Expand Down Expand Up @@ -192,7 +201,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 3,
appID: 1,
tc: 3,
},
desc: "QER_METERING - session QER only",
},
Expand Down Expand Up @@ -224,7 +234,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 2,
appID: 1,
tc: 2,
},
desc: "QER_METERING - TC for QFI",
},
Expand Down Expand Up @@ -257,7 +268,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 2,
appID: 1,
tc: 2,
},
desc: "QER UL gating",
},
Expand Down Expand Up @@ -290,7 +302,8 @@ func TestSingleUEAttachAndDetach(t *testing.T) {
80, 80,
},
},
tc: 2,
appID: 1,
tc: 2,
},
desc: "QER DL gating",
},
Expand Down Expand Up @@ -327,7 +340,8 @@ func TestUEBuffering(t *testing.T) {
80, 80,
},
},
tc: 3,
appID: 1,
tc: 3,
},
}

Expand Down Expand Up @@ -500,4 +514,19 @@ func testUEDetach(t *testing.T, testcase *testCase) {
func testUEAttachDetach(t *testing.T, testcase *testCase) {
testUEAttach(t, testcase)
testUEDetach(t, testcase)

if isDatapathUP4() {
// clear Applications table
// FIXME: Temporary solution. They should be cleared by pfcpiface, see SDFAB-960
p4rtClient, _ := providers.ConnectP4rt("127.0.0.1:50001", TimeBasedElectionId())
defer func() {
providers.DisconnectP4rt()
// give pfcpiface time to become master controller again
time.Sleep(3 * time.Second)
}()
entries, _ := p4rtClient.ReadTableEntryWildcard("PreQosPipe.applications")
for _, entry := range entries {
p4rtClient.DeleteTableEntry(entry)
}
}
}
1 change: 1 addition & 0 deletions test/integration/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ type appFilter struct {
type p4RtValues struct {
tc uint8
ueAddress string
appID uint8
appFilter appFilter

pdrs []*ie.IE
Expand Down
Loading