From 269f611907e414188252348e6478d3aa6bf14ca3 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Fri, 21 Jun 2024 12:47:00 +0000 Subject: [PATCH] ethface+ndndpdk-upf: separate ulQFI and dlQFI --- Makefile | 2 +- cmd/ndndpdk-upf/sess.go | 65 ++++++++++++++++++++++++++++------- cmd/ndndpdk-upf/upfconfig.go | 5 +-- csrc/ethface/locator.c | 6 ++-- csrc/ethface/locator.h | 3 +- iface/ethface/gtp.go | 15 +++++--- iface/ethface/locator_test.go | 24 +++++++------ iface/ethface/tap_test.go | 6 ++-- 8 files changed, 89 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 607fb3f9..b462d666 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ build/bpf.done: build/build.ninja bpf/**/*.c csrc/strategyapi/* csrc/fib/enum.h touch $@ .PHONY: cmds -cmds: build/share/bash_autocomplete build/bin/ndndpdk-ctrl build/bin/ndndpdk-godemo build/bin/ndndpdk-hrlog2histogram build/bin/ndndpdk-jrproxy build/bin/ndndpdk-svc +cmds: build/share/bash_autocomplete build/bin/ndndpdk-ctrl build/bin/ndndpdk-godemo build/bin/ndndpdk-hrlog2histogram build/bin/ndndpdk-jrproxy build/bin/ndndpdk-svc build/bin/ndndpdk-upf build/bin/%: cmd/%/* godeps GOBIN=$$(realpath build/bin) mk/go.sh install ./cmd/$* diff --git a/cmd/ndndpdk-upf/sess.go b/cmd/ndndpdk-upf/sess.go index d46b36eb..2ea41365 100644 --- a/cmd/ndndpdk-upf/sess.go +++ b/cmd/ndndpdk-upf/sess.go @@ -12,14 +12,26 @@ import ( "go.uber.org/zap" ) +const ( + sessHaveUlTEID = 1 << iota + sessHaveDlTEID + sessHaveUlQFI + sessHaveDlQFI + sessHaveDlQERID + sessHavePeer + sessHaveUeIP + sessHaveAll = 0b1111111 +) + var pfcpSessTable = make(map[uint64]*pfcpSess) type pfcpSess struct { cpSEID, upSEID uint64 ulTEID, dlTEID uint32 - qfi uint8 + ulQFI, dlQFI uint8 + dlQERID uint32 peer, ueIP netip.Addr - have uint8 + have uint32 FaceID string } @@ -27,7 +39,7 @@ func (sess pfcpSess) decorateLogEntry(logger *zap.Logger) *zap.Logger { return logger.With(zap.Uint64("cp-seid", sess.cpSEID), zap.Uint64("up-seid", sess.upSEID)) } -func (sess *pfcpSess) HandleCreate(ctx context.Context, logEntry *zap.Logger, pdrs, fars []*ie.IE) { +func (sess *pfcpSess) HandleCreate(ctx context.Context, logEntry *zap.Logger, pdrs, fars, qers []*ie.IE) { logEntry = sess.decorateLogEntry(logEntry) for i, pdr := range pdrs { @@ -40,12 +52,17 @@ func (sess *pfcpSess) HandleCreate(ctx context.Context, logEntry *zap.Logger, pd logEntry.Info("createFAR error", zap.Int("index", i), zap.Error(e)) } } - if sess.have != 0b111 { - logEntry.Debug("waiting for more updates", zap.Uint8("have", sess.have)) + for i, qer := range qers { + if e := sess.createQER(qer); e != nil { + logEntry.Info("createQER error", zap.Int("index", i), zap.Error(e)) + } + } + if sess.have != sessHaveAll { + logEntry.Debug("waiting for more updates", zap.Uint32("have", sess.have)) return } - loc, e := upfCfg.MakeLocator(sess.ulTEID, sess.dlTEID, sess.qfi, sess.peer, sess.ueIP) + loc, e := upfCfg.MakeLocator(sess.ulTEID, sess.ulQFI, sess.dlTEID, sess.dlQFI, sess.peer, sess.ueIP) if e != nil { logEntry.Warn("cannot construct locator", zap.Error(e)) return @@ -97,8 +114,8 @@ func (sess *pfcpSess) createPDRAccess(pdr *ie.IE) error { return fmt.Errorf("QFI: %w", e) } - sess.ulTEID, sess.qfi = fTEID.TEID, qfi - sess.have |= 0b001 + sess.ulTEID, sess.ulQFI = fTEID.TEID, qfi + sess.have |= sessHaveUlTEID | sessHaveUlQFI return nil } @@ -114,7 +131,14 @@ func (sess *pfcpSess) createPDRCore(pdr *ie.IE) error { } sess.ueIP = ip - sess.have |= 0b010 + sess.have |= sessHaveUeIP + + sess.dlQERID, e = pdr.QERID() + if e != nil { + return fmt.Errorf("QERID: %w", e) + } + sess.have |= sessHaveDlQERID + return nil } @@ -149,7 +173,24 @@ func (sess *pfcpSess) createFARAccess(far *ie.IE) error { sess.dlTEID = ohc.TEID sess.peer, _ = netip.AddrFromSlice(ohc.IPv4Address) - sess.have |= 0b100 + sess.have |= sessHaveDlTEID | sessHavePeer + return nil +} + +func (sess *pfcpSess) createQER(qer *ie.IE) error { + qerID, e := qer.QERID() + if e != nil { + return fmt.Errorf("QERID: %w", e) + } + if sess.have&sessHaveDlQERID == 0 || qerID != sess.dlQERID { + return nil + } + + sess.dlQFI, e = qer.QFI() + if e != nil { + return fmt.Errorf("QFI: %w", e) + } + sess.have |= sessHaveDlQFI return nil } @@ -182,7 +223,7 @@ func handleSessEstab(ctx context.Context, logEntry *zap.Logger, req *message.Ses } pfcpSessTable[sess.upSEID] = sess - sess.HandleCreate(ctx, logEntry, req.CreatePDR, req.CreateFAR) + sess.HandleCreate(ctx, logEntry, req.CreatePDR, req.CreateFAR, req.CreateQER) return message.NewSessionEstablishmentResponse( 0, 0, sess.cpSEID, req.SequenceNumber, 0, upfCfg.UpfNodeID, @@ -200,7 +241,7 @@ func handleSessMod(ctx context.Context, logEntry *zap.Logger, req *message.Sessi ), nil } - sess.HandleCreate(ctx, logEntry, req.CreatePDR, req.CreateFAR) + sess.HandleCreate(ctx, logEntry, req.CreatePDR, req.CreateFAR, req.CreateQER) return message.NewSessionModificationResponse( 0, 0, sess.cpSEID, req.SequenceNumber, 0, ie.NewCause(ie.CauseRequestAccepted), diff --git a/cmd/ndndpdk-upf/upfconfig.go b/cmd/ndndpdk-upf/upfconfig.go index 3f1ae68a..8051a930 100644 --- a/cmd/ndndpdk-upf/upfconfig.go +++ b/cmd/ndndpdk-upf/upfconfig.go @@ -106,14 +106,15 @@ func (cfg *UpfConfig) ProcessFlags(c *cli.Context) error { return nil } -func (cfg UpfConfig) MakeLocator(ulTEID, dlTEID uint32, qfi uint8, peer, ueIP netip.Addr) (loc map[string]any, e error) { +func (cfg UpfConfig) MakeLocator(ulTEID uint32, ulQFI uint8, dlTEID uint32, dlQFI uint8, peer, ueIP netip.Addr) (loc map[string]any, e error) { loc = map[string]any{ "scheme": "gtp", "local": cfg.upfMAC, "localIP": cfg.upfIP, "ulTEID": ulTEID, + "ulQFI": ulQFI, "dlTEID": dlTEID, - "qfi": qfi, + "dlQFI": dlQFI, "innerLocalIP": cfg.dnIP, "innerRemoteIP": ueIP, } diff --git a/csrc/ethface/locator.c b/csrc/ethface/locator.c index 6ed1c3d0..2c71bd72 100644 --- a/csrc/ethface/locator.c +++ b/csrc/ethface/locator.c @@ -270,7 +270,7 @@ EthRxMatch_Prepare(EthRxMatch* match, const EthLocator* loc) { break; } case 'G': { - match->len += PutGtpHdr(BUF_TAIL, true, loc->ulTEID, loc->qfi); + match->len += PutGtpHdr(BUF_TAIL, true, loc->ulTEID, loc->ulQFI); match->len += PutIpv4Hdr(BUF_TAIL, loc->innerLocalIP, loc->innerRemoteIP); match->len += PutUdpHdr(BUF_TAIL, UDPPortNDN, UDPPortNDN); match->f = MatchGtp; @@ -326,7 +326,7 @@ EthXdpLocator_Prepare(EthXdpLocator* xl, const EthLocator* loc) { } case 'G': { xl->teid = rte_cpu_to_be_32(loc->ulTEID); - xl->qfi = loc->qfi; + xl->qfi = loc->ulQFI; break; } } @@ -548,7 +548,7 @@ EthTxHdr_Prepare(EthTxHdr* hdr, const EthLocator* loc, bool hasChecksumOffloads) break; } case 'G': { - hdr->len += PutGtpHdr(BUF_TAIL, false, loc->dlTEID, loc->qfi); + hdr->len += PutGtpHdr(BUF_TAIL, false, loc->dlTEID, loc->dlQFI); hdr->len += PutIpv4Hdr(BUF_TAIL, loc->innerLocalIP, loc->innerRemoteIP); hdr->len += PutUdpHdr(BUF_TAIL, UDPPortNDN, UDPPortNDN); break; diff --git a/csrc/ethface/locator.h b/csrc/ethface/locator.h index c0903804..a8a306d4 100644 --- a/csrc/ethface/locator.h +++ b/csrc/ethface/locator.h @@ -32,7 +32,8 @@ typedef struct EthLocator { uint32_t dlTEID; uint8_t innerLocalIP[16]; uint8_t innerRemoteIP[16]; - uint8_t qfi; + uint8_t ulQFI; + uint8_t dlQFI; bool isGtp; } EthLocator; diff --git a/iface/ethface/gtp.go b/iface/ethface/gtp.go index 11911e48..490996bb 100644 --- a/iface/ethface/gtp.go +++ b/iface/ethface/gtp.go @@ -25,13 +25,17 @@ type GtpLocator struct { // This must fit in 32 bits. UlTEID int `json:"ulTEID"` + // UlQFI is the uplink/incoming QoS flow identifier. + // This must fit in 6 bits. + UlQFI int `json:"ulQFI"` + // DlTEID is the downlink/outgoing tunnel endpoint identifier. // This must fit in 32 bits. DlTEID int `json:"dlTEID"` - // QFI is the QoS flow identifier. + // DlQFI is the downlink/outgoing QoS flow identifier. // This must fit in 6 bits. - QFI int `json:"qfi"` + DlQFI int `json:"dlQFI"` // InnerLocalIP is the inner local IPv4 address. InnerLocalIP netip.Addr `json:"innerLocalIP"` @@ -55,9 +59,11 @@ func (loc GtpLocator) Validate() error { switch { case loc.UlTEID < 0, loc.UlTEID > math.MaxUint32: return ErrTEID + case loc.UlQFI < 0, loc.UlQFI > 0b111111: + return ErrQFI case loc.DlTEID < 0, loc.DlTEID > math.MaxUint32: return ErrTEID - case loc.QFI < 0, loc.QFI > 0b111111: + case loc.DlQFI < 0, loc.DlQFI > 0b111111: return ErrQFI case !local.Is4(), local.IsMulticast(), !remote.Is4(), remote.IsMulticast(): return ErrUnicastIP @@ -73,8 +79,9 @@ func (loc GtpLocator) EthLocatorC() (locC ethport.LocatorC) { locC.RemoteUDP = ethport.UDPPortGTP locC.IsGtp = true locC.UlTEID = uint32(loc.UlTEID) + locC.UlQFI = uint8(loc.UlQFI) locC.DlTEID = uint32(loc.DlTEID) - locC.Qfi = uint8(loc.QFI) + locC.DlQFI = uint8(loc.DlQFI) locC.InnerLocalIP = loc.InnerLocalIP.As16() locC.InnerRemoteIP = loc.InnerRemoteIP.As16() return diff --git a/iface/ethface/locator_test.go b/iface/ethface/locator_test.go index 59940724..c7166f59 100644 --- a/iface/ethface/locator_test.go +++ b/iface/ethface/locator_test.go @@ -100,16 +100,16 @@ func TestLocatorCoexist(t *testing.T) { const innerIP = `,"innerLocalIP":"192.168.60.3","innerRemoteIP":"192.168.60.4"` conflict( // same ulTEID - `{"scheme":"gtp","ulTEID":268435464,"dlTEID":536870920,"qfi":1`+innerIP+ipA+etherA, - `{"scheme":"gtp","ulTEID":268435464,"dlTEID":536870921,"qfi":2`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435464,"ulQFI":1,"dlTEID":536870920,"dlQFI":1`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435464,"ulQFI":2,"dlTEID":536870921,"dlQFI":2`+innerIP+ipA+etherA, ) conflict( // same dlTEID - `{"scheme":"gtp","ulTEID":268435464,"dlTEID":536870920,"qfi":1`+innerIP+ipA+etherA, - `{"scheme":"gtp","ulTEID":268435465,"dlTEID":536870920,"qfi":2`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435464,"ulQFI":1,"dlTEID":536870920,"dlQFI":1`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435465,"ulQFI":2,"dlTEID":536870920,"dlQFI":2`+innerIP+ipA+etherA, ) coexist( // different ulTEID and dlTEID - `{"scheme":"gtp","ulTEID":268435464,"dlTEID":536870920,"qfi":1`+innerIP+ipA+etherA, - `{"scheme":"gtp","ulTEID":268435465,"dlTEID":536870921,"qfi":1`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435464,"ulQFI":1,"dlTEID":536870920,"dlQFI":1`+innerIP+ipA+etherA, + `{"scheme":"gtp","ulTEID":268435465,"ulQFI":1,"dlTEID":536870921,"dlQFI":1`+innerIP+ipA+etherA, ) // mixed schemes @@ -130,7 +130,7 @@ func TestLocatorCoexist(t *testing.T) { `{"scheme":"vxlan","vxlan":1`+innerA+ipA+etherA) conflict( // "udpe" with "gtp", same localUDP and remoteUDP `{"scheme":"udpe","localUDP":2152,"remoteUDP":2152`+ipA+etherA, - `{"scheme":"gtp","ulTEID":268435464,"dlTEID": 536870920,"qfi":1`+innerIP+ipA+etherA) + `{"scheme":"gtp","ulTEID":268435464,"ulQFI":1,"dlTEID": 536870920,"dlQFI":1`+innerIP+ipA+etherA) } func TestLocatorRxMatch(t *testing.T) { @@ -207,8 +207,9 @@ func TestLocatorRxMatch(t *testing.T) { "localIP": "192.168.37.1", "remoteIP": "192.168.37.2", "ulTEID": 268435464, + "ulQFI": 1, "dlTEID": 536870920, - "qfi": 1, + "dlQFI": 11, "innerLocalIP": "192.168.60.3", "innerRemoteIP": "192.168.60.4" }`) @@ -388,7 +389,7 @@ func TestLocatorRxMatch(t *testing.T) { &layers.Ethernet{SrcMAC: mac2, DstMAC: mac1, EthernetType: layers.EthernetTypeIPv4}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: ip42, DstIP: ip41}, &layers.UDP{SrcPort: 2152, DstPort: 2152}, - >Pv1UTPDU{TEID: 0x10000008, PDUType: 1, QFI: 2}, + >Pv1UTPDU{TEID: 0x10000008, PDUType: 1, QFI: 11}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: ip44, DstIP: ip43}, &layers.UDP{SrcPort: 6363, DstPort: 6363}, ) @@ -496,8 +497,9 @@ func TestLocatorTxHdr(t *testing.T) { "localIP": "192.168.37.1", "remoteIP": "192.168.37.2", "ulTEID": 268435464, + "ulQFI": 1, "dlTEID": 536870920, - "qfi": 1, + "dlQFI": 11, "innerLocalIP": "192.168.60.3", "innerRemoteIP": "192.168.60.4" }`, layers.LayerTypeEthernet, layers.LayerTypeIPv4, layers.LayerTypeUDP, layers.LayerTypeGTPv1U, layers.LayerTypeIPv4, layers.LayerTypeUDP) @@ -509,6 +511,6 @@ func TestLocatorTxHdr(t *testing.T) { if assert.Len(gtpGTP.GTPExtensionHeaders, 1) { gtpPSC := gtpGTP.GTPExtensionHeaders[0] assert.EqualValues(0x85, gtpPSC.Type) - assert.Equal([]byte{0x00, 0x01}, gtpPSC.Content) + assert.Equal([]byte{0x00, 0x0B}, gtpPSC.Content) } } diff --git a/iface/ethface/tap_test.go b/iface/ethface/tap_test.go index a3af8337..af309e85 100644 --- a/iface/ethface/tap_test.go +++ b/iface/ethface/tap_test.go @@ -91,7 +91,7 @@ func testPortTAP(t testing.TB, makeNetifConfig func(ifname string) ethnetif.Conf locGTP8.IPLocator = locUDP4.IPLocator locGTP8.VLAN = 0 locGTP8.UlTEID, locGTP8.DlTEID = 0x10000008, 0x20000008 - locGTP8.QFI = 2 + locGTP8.UlQFI, locGTP8.DlQFI = 2, 12 locGTP8.InnerLocalIP = netip.MustParseAddr("192.168.60.3") locGTP8.InnerRemoteIP = netip.MustParseAddr("192.168.60.4") faceGTP8 := addFace(locGTP8) @@ -208,7 +208,7 @@ func testPortTAP(t testing.TB, makeNetifConfig func(ifname string) ethnetif.Conf &layers.Ethernet{SrcMAC: locGTP8.Remote.HardwareAddr, DstMAC: locGTP8.Local.HardwareAddr, EthernetType: layers.EthernetTypeIPv4}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: net.IP(locGTP8.RemoteIP.AsSlice()), DstIP: net.IP(locGTP8.LocalIP.AsSlice())}, &layers.UDP{SrcPort: 2152, DstPort: 2152}, - >Pv1UTPDU{TEID: uint32(locGTP8.UlTEID), PDUType: 1, QFI: uint8(locGTP8.QFI)}, + >Pv1UTPDU{TEID: uint32(locGTP8.UlTEID), PDUType: 1, QFI: uint8(locGTP8.UlQFI)}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: net.IP(locGTP8.InnerRemoteIP.AsSlice()), DstIP: net.IP(locGTP8.InnerLocalIP.AsSlice())}, &layers.UDP{SrcPort: 6363, DstPort: 6363}, makeRxFrame("GTP8", i), @@ -220,7 +220,7 @@ func testPortTAP(t testing.TB, makeNetifConfig func(ifname string) ethnetif.Conf &layers.Ethernet{SrcMAC: locGTP9.Remote.HardwareAddr, DstMAC: locGTP9.Local.HardwareAddr, EthernetType: layers.EthernetTypeIPv4}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: net.IP(locGTP9.RemoteIP.AsSlice()), DstIP: net.IP(locGTP9.LocalIP.AsSlice())}, &layers.UDP{SrcPort: 2152, DstPort: 2152}, - >Pv1UTPDU{TEID: uint32(locGTP9.UlTEID), PDUType: 1, QFI: uint8(locGTP9.QFI)}, + >Pv1UTPDU{TEID: uint32(locGTP9.UlTEID), PDUType: 1, QFI: uint8(locGTP9.UlQFI)}, &layers.IPv4{Version: 4, TTL: 64, Protocol: layers.IPProtocolUDP, SrcIP: net.IP(locGTP9.InnerRemoteIP.AsSlice()), DstIP: net.IP(locGTP9.InnerLocalIP.AsSlice())}, &layers.UDP{SrcPort: 6363, DstPort: 6363}, makeRxFrame("GTP9", i),