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

[SDFAB-1110] Add support for application filter #54

Merged
merged 22 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from 18 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
14 changes: 7 additions & 7 deletions api/pfcpsim.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/pfcpsim.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ message CreateSessionRequest {
int32 baseID = 2;
string nodeBAddress = 3;
string ueAddressPool = 4;
string sdfFilter = 5;
string appFilter = 5;
int32 qfi = 6; // Should be uint8
bool gateClosed = 7;
bool gateClosed = 7; // If set, the application QERs will have the Gate status to closed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't gateClosed in conflict with appFilter now? What if we define gateClosed = true and appFilter = allow ? Which one have a precedence?

Copy link
Contributor Author

@EmanueleGallone EmanueleGallone Mar 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I removed the gate status flag. The only way to set the gate status is now by using the app-filter flag

}

message ModifySessionRequest {
Expand Down
6 changes: 3 additions & 3 deletions internal/pfcpctl/commands/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
log "github.com/sirupsen/logrus"
)

type associate struct {}
type disassociate struct {}
type associate struct{}
type disassociate struct{}
type configureRemoteAddresses struct {
RemotePeerAddress string `short:"r" long:"remote-peer-addr" default:"" description:"The remote PFCP agent address."`
RemotePeerAddress string `short:"r" long:"remote-peer-addr" default:"" description:"The remote PFCP agent address."`
N3InterfaceAddress string `short:"n" long:"n3-addr" default:"" description:"The IPv4 address of the UPF's N3 interface"`
}

Expand Down
28 changes: 14 additions & 14 deletions internal/pfcpctl/commands/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ import (
)

type commonArgs struct {
Count int `short:"c" long:"count" default:"1" description:"The number of sessions to create"`
BaseID int `short:"i" long:"baseID" default:"1" description:"The base ID to use"`
UePool string `short:"u" long:"ue-pool" default:"17.0.0.0/24" description:"The UE pool address"`
GnBAddress string `short:"g" long:"gnb-addr" description:"The (g/e)nodeB address"`
SDFfilter string `short:"s" long:"sdf-filter" description:"The SDF Filter to use"`
QFI uint8 `short:"q" long:"qfi" description:"The QFI value for QERs. Max value 64."`
GateClosed bool `short:"t" long:"gate-closed" description:"If set, the application QER gate status will be CLOSED"`
Count int `short:"c" long:"count" default:"1" description:"The number of sessions to create"`
BaseID int `short:"i" long:"baseID" default:"1" description:"The base ID to use"`
UePool string `short:"u" long:"ue-pool" default:"17.0.0.0/24" description:"The UE pool address"`
GnBAddress string `short:"g" long:"gnb-addr" description:"The UE pool address"`
AppFilterString string `short:"a" long:"app-filter" description:"Specify an application filter. Format: '<Protocol>:<IP>/<SubnetMask>:<Port>-<Port>:<action>' . e.g. 'udp:10.0.0.0/8:80-88:allow'"`
QFI uint8 `short:"q" long:"qfi" description:"The QFI value for QERs. Max value 64."`
GateClosed bool `short:"t" long:"gate-closed" description:"If set, the QER gate status will be CLOSED"`
}

type sessionCreate struct {
Args struct{
Args struct {
commonArgs
}
}

type sessionModify struct {
Args struct {
commonArgs
BufferFlag bool `short:"b" long:"buffer" description:"If set, downlink FARs will have the buffer flag set to true"`
BufferFlag bool `short:"b" long:"buffer" description:"If set, downlink FARs will have the buffer flag set to true"`
NotifyCPFlag bool `short:"n" long:"notifycp" description:"If set, downlink FARs will have the notify CP flag set to true"`
}
}

type sessionDelete struct {
Args struct{
Count int `short:"c" long:"count" default:"1" description:"The number of sessions to create"`
Args struct {
Count int `short:"c" long:"count" default:"1" description:"The number of sessions to create"`
BaseID int `short:"i" long:"baseID" default:"1" description:"The base ID to use"`
}
}
Expand Down Expand Up @@ -65,9 +65,9 @@ func (s *sessionCreate) Execute(args []string) error {
BaseID: int32(s.Args.BaseID),
NodeBAddress: s.Args.GnBAddress,
UeAddressPool: s.Args.UePool,
SdfFilter: s.Args.SDFfilter,
Qfi: int32(s.Args.QFI),
GateClosed: s.Args.GateClosed,
AppFilter: s.Args.AppFilterString,
Qfi: int32(s.Args.QFI),
GateClosed: s.Args.GateClosed,
})

if err != nil {
Expand Down
56 changes: 56 additions & 0 deletions internal/pfcpsim/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
package pfcpsim

import (
"fmt"
"net"
"strconv"
"strings"

"github.com/omec-project/pfcpsim/pkg/pfcpsim"
"github.com/wmnsk/go-pfcp/ie"
)

const sdfFilterFormat = "permit out %v from %v to assigned %v-%v"

func connectPFCPSim() error {
if sim == nil {
localAddr, err := getLocalAddress(interfaceName)
Expand Down Expand Up @@ -71,3 +77,53 @@ func getLocalAddress(interfaceName string) (net.IP, error) {

return nil, pfcpsim.NewNoValidInterfaceError()
}

// parseAppFilter parses an application filter. Returns a tuple formed by a formatted SDF filter
// and a uint8 representing the Application QER gate status. Returns error if fail occurs while validating the filter string.
func parseAppFilter(filter string) (string, uint8, error) {
EmanueleGallone marked this conversation as resolved.
Show resolved Hide resolved
result := strings.Split(filter, ":")
if len(result) != 4 {
return "", 0, pfcpsim.NewInvalidFormatError("Parser was not able to generate the correct number of arguments." +
" Please make sure to use the right format")
}

proto, ipNetAddr, portRange, action := result[0], result[1], result[2], result[3]

if !(proto == "ip" || proto == "udp" || proto == "tcp") {
return "", 0, pfcpsim.NewInvalidFormatError("Unsupported or unknown protocol.")
}

_, _, err := net.ParseCIDR(ipNetAddr)
if err != nil {
return "", 0, pfcpsim.NewInvalidFormatError("IP and subnet mask.", err)
}

portList := strings.Split(portRange, "-")
if !(len(portList) == 2) {
return "", 0, pfcpsim.NewInvalidFormatError("Port range. Please make sure to use dash '-' to separate the two ports")
}

lowerPort, err := strconv.Atoi(portList[0])
if err != nil {
return "", 0, pfcpsim.NewInvalidFormatError("Port range.", err)
}

upperPort, err := strconv.Atoi(portList[1])
if err != nil {
return "", 0, pfcpsim.NewInvalidFormatError("Port range.", err)
}

if lowerPort > upperPort {
return "", 0, pfcpsim.NewInvalidFormatError("Port range. Lower port is greater than upper port")
}

if !(action == "allow" || action == "deny") {
return "", 0, pfcpsim.NewInvalidFormatError("Action. Please make sure to use 'allow' or 'deny'")
}

if action == "allow" {
return fmt.Sprintf(sdfFilterFormat, proto, ipNetAddr, lowerPort, upperPort), ie.GateStatusOpen, nil
}

return fmt.Sprintf(sdfFilterFormat, proto, ipNetAddr, lowerPort, upperPort), ie.GateStatusClosed, nil
}
17 changes: 11 additions & 6 deletions internal/pfcpsim/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ func (P pfcpSimService) CreateSession(ctx context.Context, request *pb.CreateSes
var SDFFilter = ""
var qfi, gateStatus uint8 = 0, ieLib.GateStatusOpen

if request.AppFilter != "" {
SDFFilter, gateStatus, err = parseAppFilter(request.AppFilter)
if err != nil {
return &pb.Response{}, status.Error(codes.Aborted, err.Error())
}

log.Infof("Successfully parsed application filter. SDF Filter: %v", SDFFilter)
}

if request.GateClosed {
gateStatus = ieLib.GateStatusClosed
}
Expand All @@ -135,10 +144,6 @@ func (P pfcpSimService) CreateSession(ctx context.Context, request *pb.CreateSes
qfi = uint8(request.Qfi)
}

if request.SdfFilter != "" {
SDFFilter = request.SdfFilter
}

for i := baseID; i < (count*2 + baseID); i = i + 2 {
// using variables to ease comprehension on how rules are linked together
uplinkTEID := uint32(i)
Expand All @@ -150,7 +155,7 @@ func (P pfcpSimService) CreateSession(ctx context.Context, request *pb.CreateSes
downlinkFarID := uint32(i + 1)

uplinkPdrID := uint16(i)
dowlinkPdrID := uint16(i + 1)
downlinkPdrID := uint16(i + 1)

sessQerID := uint32(i + 3)

Expand All @@ -174,7 +179,7 @@ func (P pfcpSimService) CreateSession(ctx context.Context, request *pb.CreateSes

// DownlinkPDR
session.NewPDRBuilder().
WithID(dowlinkPdrID).
WithID(downlinkPdrID).
WithMethod(session.Create).
WithPrecedence(100).
WithUEAddress(ueAddress.String()).
Expand Down
7 changes: 7 additions & 0 deletions pkg/pfcpsim/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ func NewNotEnoughSessionsError(err ...error) *pfcpSimError {
}
}

func NewInvalidFormatError(what string, err ...error) *pfcpSimError {
return &pfcpSimError{
message: fmt.Sprintf("Invalid format: %v", what),
error: err,
}
}

func NewNoValidInterfaceError(err ...error) *pfcpSimError {
return &pfcpSimError{
message: "No valid interface found",
Expand Down