Skip to content

Commit

Permalink
UE ip pool allocation by UPF
Browse files Browse the repository at this point in the history
  • Loading branch information
Badhrinath Pa authored and badhri85 committed Feb 2, 2021
1 parent 44f27a2 commit e6c0bf4
Show file tree
Hide file tree
Showing 14 changed files with 198 additions and 74 deletions.
8 changes: 5 additions & 3 deletions conf/upf.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@

"": "Control plane controller settings",
"cpiface": {
"nb_dst_ip": "172.17.0.1",
"" : "nb_dst_ip: CPHostname",
"hostname": "spgwc"
"enable_ue_ip_alloc": false,
"ue_ip_pool": "10.250.0.0/16",
"nb_dst_ip": "172.17.0.1",
"" : "nb_dst_ip: CPHostname",
"hostname": "spgwc"
},

"": "p4rtc interface settings",
Expand Down
7 changes: 6 additions & 1 deletion pfcpiface/bess.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ func (b *bess) setUpfInfo(u *upf, conf *Conf) {
u.simInfo = simInfo
}

u.ippool_cidr = conf.CPIface.UeIPPool
log.Println("IP pool : ", u.ippool_cidr)
errin := u.ippool.init_pool(u.ippool_cidr)
if errin != nil {
log.Println("ip pool init failed")
}
u.accessIP = ParseIP(conf.AccessIface.IfName, "Access")
u.coreIP = ParseIP(conf.CoreIface.IfName, "Core")
if *n4SrcIPStr != "" {
Expand All @@ -299,7 +305,6 @@ func (b *bess) setUpfInfo(u *upf, conf *Conf) {
}
}
// get bess grpc client
var errin error
log.Println("bessIP ", *bessIP)

b.conn, errin = grpc.Dial(*bessIP, grpc.WithInsecure())
Expand Down
2 changes: 1 addition & 1 deletion pfcpiface/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/p4lang/p4runtime v1.3.0
github.com/prometheus/client_golang v1.9.0
github.com/wmnsk/go-pfcp v0.0.8
github.com/wmnsk/go-pfcp v0.0.9-0.20210129064645-e1b1f34ebd9f
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
google.golang.org/grpc v1.35.0
google.golang.org/protobuf v1.25.0
Expand Down
4 changes: 2 additions & 2 deletions pfcpiface/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/wmnsk/go-pfcp v0.0.8 h1:H/PDw2gvoYmXu3vltuIuJlckytUMpef4fAxl/ij2o64=
github.com/wmnsk/go-pfcp v0.0.8/go.mod h1:Hwc6b/KmDF6tGa5hwhP5UGfKgwnL2CICFs3PgFz5cRE=
github.com/wmnsk/go-pfcp v0.0.9-0.20210129064645-e1b1f34ebd9f h1:eof2jcYxj5zXKwR012IIeZ+odMCUMX/P+Oc163Ec6/s=
github.com/wmnsk/go-pfcp v0.0.9-0.20210129064645-e1b1f34ebd9f/go.mod h1:Hwc6b/KmDF6tGa5hwhP5UGfKgwnL2CICFs3PgFz5cRE=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
Expand Down
55 changes: 55 additions & 0 deletions pfcpiface/ip_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright(c) 2020 Intel Corporation

package main

import (
"errors"
"log"
"net"

"github.com/wmnsk/go-pfcp/ie"
)

type ip_pool struct {
free_pool []string
}

func needAllocIp(ueIPaddr *ie.UEIPAddressFields) bool {
if has2ndBit(ueIPaddr.Flags) && !has5thBit(ueIPaddr.Flags) {
return false
}
return true
}

func (ipp *ip_pool) deallocIPV4(element net.IP) {
ipp.free_pool = append(ipp.free_pool, element.String()) // Simply append to enqueue.
log.Println("Enqueued:", element.String())
}

func (ipp *ip_pool) allocIPV4() (net.IP, error) {
if len(ipp.free_pool) == 0 {
err := errors.New("ip pool empty")
return nil, err
}
element := ipp.free_pool[0] // The first element is the one to be dequeued.
log.Println("Dequeued:", element)
ipp.free_pool = ipp.free_pool[1:] // Slice off the element once it is dequeued.
ipVal := net.ParseIP(element).To4()
return ipVal, nil
}

func (ipp *ip_pool) init_pool(cidr string) error {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return err
}

for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
ipp.free_pool = append(ipp.free_pool, ip.String())
}
// remove network address and broadcast address

ipp.free_pool = ipp.free_pool[1 : len(ipp.free_pool)-1]
return nil
}
19 changes: 11 additions & 8 deletions pfcpiface/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ type SimModeInfo struct {

// CPIfaceInfo : CPIface interface settings
type CPIfaceInfo struct {
DestIP string `json:"nb_dst_ip"`
SrcIP string `json:"nb_src_ip"`
FQDNHost string `json:"hostname"`
EnableUeIPAlloc bool `json:"enable_ue_ip_alloc"`
DestIP string `json:"nb_dst_ip"`
SrcIP string `json:"nb_src_ip"`
FQDNHost string `json:"hostname"`
UeIPPool string `json:"ue_ip_pool"`
}

// IfaceType : Gateway interface struct
Expand Down Expand Up @@ -139,11 +141,12 @@ func main() {
}

upf := &upf{
accessIface: conf.AccessIface.IfName,
coreIface: conf.CoreIface.IfName,
fqdnHost: fqdnh,
maxSessions: conf.MaxSessions,
intf: intf,
accessIface: conf.AccessIface.IfName,
coreIface: conf.CoreIface.IfName,
fqdnHost: fqdnh,
maxSessions: conf.MaxSessions,
intf: intf,
enableUeIPAlloc: conf.CPIface.EnableUeIPAlloc,
}

upf.setUpfInfo(&conf)
Expand Down
26 changes: 19 additions & 7 deletions pfcpiface/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,23 @@ func (pc *PFCPConn) handleAssociationSetupRequest(upf *upf, msg message.Message,

// Build response message
// Timestamp shouldn't be the time message is sent in the real deployment but anyway :D
asres, err := message.NewAssociationSetupResponse(asreq.SequenceNumber,
asresmsg := message.NewAssociationSetupResponse(asreq.SequenceNumber,
ie.NewRecoveryTimeStamp(time.Now()),
ie.NewNodeID(sourceIP, "", ""), /* node id (IPv4) */
ie.NewCause(cause), /* accept it blindly for the time being */
// 0x41 = Spare (0) | Assoc Src Inst (1) | Assoc Net Inst (0) | Tied Range (000) | IPV6 (0) | IPV4 (1)
// = 01000001
ie.NewUserPlaneIPResourceInformation(0x41, 0, upf.accessIP.String(), "", "", ie.SrcInterfaceAccess),
// ie.NewUserPlaneIPResourceInformation(0x41, 0, coreIP, "", "", ie.SrcInterfaceCore),
).Marshal() /* userplane ip resource info */
) /* userplane ip resource info */

if upf.enableUeIPAlloc {
features := make([]uint8, 4)
setUeipFeature(features...)
asresmsg.UPFunctionFeatures =
ie.NewUPFunctionFeatures(features...)
}
asres, err := asresmsg.Marshal()
if err != nil {
log.Fatalln("Unable to create association setup response", err)
}
Expand Down Expand Up @@ -247,7 +255,7 @@ func (pc *PFCPConn) handleSessionEstablishmentRequest(upf *upf, msg message.Mess
session := pc.mgr.sessions[localSEID]
for _, cPDR := range sereq.CreatePDR {
var p pdr
if err := p.parsePDR(cPDR, session.localSEID, pc.mgr.appPFDs); err != nil {
if err := p.parsePDR(cPDR, session.localSEID, pc.mgr.appPFDs, upf); err != nil {
return sendError(err)
}
p.fseidIP = fseidIP
Expand All @@ -270,15 +278,18 @@ func (pc *PFCPConn) handleSessionEstablishmentRequest(upf *upf, msg message.Mess
}

// Build response message
seres, err := message.NewSessionEstablishmentResponse(0, /* MO?? <-- what's this */
seresMsg := message.NewSessionEstablishmentResponse(0, /* MO?? <-- what's this */
0, /* FO <-- what's this? */
session.remoteSEID, /* seid */
sereq.SequenceNumber, /* seq # */
0, /* priority */
ie.NewNodeID(sourceIP, "", ""), /* node id (IPv4) */
ie.NewCause(ie.CauseRequestAccepted), /* accept it blindly for the time being */
ie.NewFSEID(session.localSEID, net.ParseIP(sourceIP), nil, nil),
).Marshal()
)

addPdrInfo(seresMsg, &session)
seres, err := seresMsg.Marshal()
if err != nil {
log.Fatalln("Unable to create session establishment response", err)
}
Expand Down Expand Up @@ -336,7 +347,7 @@ func (pc *PFCPConn) handleSessionModificationRequest(upf *upf, msg message.Messa
addFARs := make([]far, 0, MaxItems)
for _, cPDR := range smreq.CreatePDR {
var p pdr
if err := p.parsePDR(cPDR, localSEID, pc.mgr.appPFDs); err != nil {
if err := p.parsePDR(cPDR, localSEID, pc.mgr.appPFDs, upf); err != nil {
return sendError(err)
}
p.fseidIP = fseidIP
Expand All @@ -357,7 +368,7 @@ func (pc *PFCPConn) handleSessionModificationRequest(upf *upf, msg message.Messa
for _, uPDR := range smreq.UpdatePDR {
var p pdr
var err error
if err = p.parsePDR(uPDR, localSEID, pc.mgr.appPFDs); err != nil {
if err = p.parsePDR(uPDR, localSEID, pc.mgr.appPFDs, upf); err != nil {
return sendError(err)
}
err = session.UpdatePDR(p)
Expand Down Expand Up @@ -477,6 +488,7 @@ func (pc *PFCPConn) handleSessionDeletionRequest(upf *upf, msg message.Message,
return sendError(errors.New("Write to FastPath failed"))
}

releaseAllocatedIPs(upf, &session)
/* delete sessionRecord */
delete(pc.mgr.sessions, localSEID)

Expand Down
37 changes: 26 additions & 11 deletions pfcpiface/parse-pdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ type pdr struct {
dstPortMask uint16
protoMask uint8

precedence uint32
pdrID uint32
fseID uint32
fseidIP uint32
ctrID uint32
farID uint32
needDecap uint8
precedence uint32
pdrID uint32
fseID uint32
fseidIP uint32
ctrID uint32
farID uint32
needDecap uint8
allocIpFlag bool
}

func (p *pdr) printPDR() {
Expand All @@ -62,10 +63,11 @@ func (p *pdr) printPDR() {
log.Println("ctrID:", p.ctrID)
log.Println("farID:", p.farID)
log.Println("needDecap:", p.needDecap)
log.Println("allocIpFlag:", p.allocIpFlag)
log.Println("--------------------------------------------")
}

func (p *pdr) parsePDI(pdiIEs []*ie.IE, appPFDs map[string]appPFD) error {
func (p *pdr) parsePDI(pdiIEs []*ie.IE, appPFDs map[string]appPFD, upf *upf) error {
var ueIP4 net.IP

for _, pdiIE := range pdiIEs {
Expand All @@ -77,7 +79,20 @@ func (p *pdr) parsePDI(pdiIEs []*ie.IE, appPFDs map[string]appPFD) error {
continue
}

ueIP4 = ueIPaddr.IPv4Address
if needAllocIp(ueIPaddr) {
/* alloc IPV6 if CHV6 is enabled : TBD */
log.Println("UPF should alloc UE IP. CHV4 flag set")
ueIP4, err = upf.ippool.allocIPV4()
if err != nil {
log.Println("failed to allocate UE IP")
return err
}
p.allocIpFlag = true
log.Println("ueipv4 : ", ueIP4.String())
} else {
log.Println("CP has allocated UE IP.")
ueIP4 = ueIPaddr.IPv4Address
}
case ie.SourceInterface:
srcIface, err := pdiIE.SourceInterface()
if err != nil {
Expand Down Expand Up @@ -212,7 +227,7 @@ func (p *pdr) parsePDI(pdiIEs []*ie.IE, appPFDs map[string]appPFD) error {
return nil
}

func (p *pdr) parsePDR(ie1 *ie.IE, seid uint64, appPFDs map[string]appPFD) error {
func (p *pdr) parsePDR(ie1 *ie.IE, seid uint64, appPFDs map[string]appPFD, upf *upf) error {
/* reset outerHeaderRemoval to begin with */
outerHeaderRemoval := uint8(0)

Expand All @@ -239,7 +254,7 @@ func (p *pdr) parsePDR(ie1 *ie.IE, seid uint64, appPFDs map[string]appPFD) error
outerHeaderRemoval = 1
}

err = p.parsePDI(pdi, appPFDs)
err = p.parsePDI(pdi, appPFDs, upf)
if err != nil && err != errBadFilterDesc {
return err
}
Expand Down
35 changes: 35 additions & 0 deletions pfcpiface/session-pdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,43 @@ package main

import (
"errors"
"github.com/wmnsk/go-pfcp/ie"
"github.com/wmnsk/go-pfcp/message"
"log"
"net"
)

// Release allocated IPs
func releaseAllocatedIPs(upf *upf, session *PFCPSession) {
log.Println("release allocated IPs")
for _, pdr := range session.pdrs {
if (pdr.allocIpFlag) && (pdr.srcIface == core) {
log.Println("pdrID : ", pdr.pdrID)
var ueIP net.IP = int2ip(pdr.dstIP)
log.Println("ueIP : ", ueIP.String())
upf.ippool.deallocIPV4(ueIP)
}
}
}

func addPdrInfo(msg *message.SessionEstablishmentResponse,
session *PFCPSession) {
log.Println("Add PDRs with UPF alloc IPs to Establishment response")
for _, pdr := range session.pdrs {
if (pdr.allocIpFlag) && (pdr.srcIface == core) {
log.Println("pdrID : ", pdr.pdrID)
var flags uint8 = 0x02
var ueIP net.IP = int2ip(pdr.dstIP)
log.Println("ueIP : ", ueIP.String())
msg.CreatedPDR = append(msg.CreatedPDR,
ie.NewCreatedPDR(
ie.NewPDRID(uint16(pdr.pdrID)),
ie.NewUEIPAddress(flags, ueIP.String(), "", 0, 0),
))
}
}
}

// CreatePDR appends pdr to existing list of PDRs in the session
func (s *PFCPSession) CreatePDR(p pdr) {
s.pdrs = append(s.pdrs, p)
Expand Down
21 changes: 12 additions & 9 deletions pfcpiface/upf.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import (
)

type upf struct {
accessIface string
coreIface string
accessIP net.IP
coreIP net.IP
n4SrcIP net.IP
fqdnHost string
maxSessions uint32
simInfo *SimModeInfo
intf fastPath
enableUeIPAlloc bool
accessIface string
coreIface string
ippool_cidr string
accessIP net.IP
coreIP net.IP
n4SrcIP net.IP
fqdnHost string
maxSessions uint32
simInfo *SimModeInfo
intf fastPath
ippool ip_pool
}

// to be replaced with go-pfcp structs
Expand Down

0 comments on commit e6c0bf4

Please sign in to comment.