Skip to content

Commit c6a3e9d

Browse files
committed
SDAP: QfiContextManager: clean up, rename to DrbTable
- QfiContextManager API cleanup - DrbContext::drbIndex -> drbId (DrbId), remove lcid field - Restructure QfiContextManager with DrbKey primary map, (nodeId,qfi) reverse map, isDefault flag + default DRB accelerators - Rename DrbContext -> DrbConfig - Rename QfiContextManager -> DrbTable, QfiContext.h -> DrbConfig.h
1 parent 5ccb65a commit c6a3e9d

9 files changed

Lines changed: 255 additions & 272 deletions

File tree

src/simu5g/stack/mac/scheduling_modules/QoSAwareScheduler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ namespace simu5g {
2222

2323
/**
2424
* Extends the LTE/NR MAC layer scheduler to support QoS-aware scheduling
25-
* decisions based on QFI (QoS Flow Identifier) contexts. QfiContextManager
25+
* decisions based on QFI (QoS Flow Identifier) contexts. DrbTable
2626
* maintains mappings between QFIs, CIDs, and their associated QoS parameters.
2727
*
2828
* Key Features:
2929
* - Implements a PF-based scheduler that dynamically scores active CIDs using
3030
* QoS weights derived from QFI context (e.g., 5QI, GBR, delay budget, PER,
3131
* priority).
3232
* - Supports per-CID registration of QFIs
33-
* - QfiContextManager can load QFI-DRB configurations from file
33+
* - DrbTable can load QFI-DRB configurations from file
3434
* - Provides flexible QoS weight computation based on service criticality.
3535
* - Enables more realistic traffic differentiation for scenarios involving
3636
* conversational voice, URLLC, video streaming, etc.

src/simu5g/stack/sdap/NrSdap.cc

Lines changed: 41 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ void NrSdap::initialize()
3333
// Load QFI-to-DRB mapping from drbConfig parameter
3434
const cValueArray *arr = check_and_cast_nullable<const cValueArray *>(par("drbConfig").objectValue());
3535
if (arr && arr->size() > 0) {
36-
qfiContextManager_.loadFromJson(arr);
37-
EV << "NrSdap: Loaded " << qfiContextManager_.getDrbMap().size() << " DRB entries from drbConfig" << endl;
38-
for (const auto& [drb, ctx] : qfiContextManager_.getDrbMap())
39-
EV << " DRB " << drb << ": " << ctx << endl;
36+
drbTable_.loadFromJson(arr);
37+
EV << "NrSdap: Loaded " << drbTable_.getDrbMap().size() << " DRB entries from drbConfig" << endl;
38+
for (const auto& [key, ctx] : drbTable_.getDrbMap())
39+
EV << " " << key << ": " << ctx << endl;
4040
}
4141

4242
// Get pointer to reflective QoS table
@@ -49,7 +49,7 @@ void NrSdap::initialize()
4949
throw cRuntimeError("Only UE may use a reflective QoS table");
5050
}
5151

52-
bool NrSdap::requiresSdapHeader(int drbIndex)
52+
bool NrSdap::requiresSdapHeader(const DrbConfig *drb)
5353
{
5454
return par("addSdapHeader").boolValue(); // for now -- should come from RRC config
5555
}
@@ -59,7 +59,7 @@ bool NrSdap::shouldEnableReflectiveQos(int qfi)
5959
return par("useReflectiveQos").boolValue(); // for now -- should come from RRC config
6060
}
6161

62-
const inet::Protocol *NrSdap::getUpperProtocol(const DrbContext *ctx)
62+
const inet::Protocol *NrSdap::getUpperProtocol(const DrbConfig *ctx)
6363
{
6464
// If an explicit upperProtocol is configured on this DRB, use it
6565
if (ctx && !ctx->upperProtocol.empty()) {
@@ -138,44 +138,28 @@ void NrSdap::handleUpperPacket(inet::Packet *pkt)
138138
EV_WARN << "SDAP TX: QfiReq not found on gNB path, defaulting QFI to 0\n";
139139
}
140140

141-
// Lookup DRB index
142-
int drbIndex = 0;
143-
144-
if (isUe) {
145-
// UE side: simple QFI -> drbIndex lookup
146-
int idx = qfiContextManager_.getDrbIndexForQfi(qfi);
147-
if (idx >= 0)
148-
drbIndex = idx;
149-
else
150-
EV_WARN << "SDAP TX: No DRB mapping for QFI=" << (int)qfi << " on UE, using DRB 0\n";
151-
} else {
152-
// gNB side: need dest UE nodeId + QFI -> drbIndex
153-
MacNodeId destUeId = pkt->getTag<FlowControlInfo>()->getDestId();
154-
if (destUeId == NODEID_NONE)
155-
EV_WARN << "SDAP TX: destId not set in FlowControlInfo, using DRB 0\n";
156-
else {
157-
int idx = qfiContextManager_.getDrbIndex(destUeId, qfi);
158-
if (idx >= 0)
159-
drbIndex = idx;
160-
else {
161-
// Fallback: use first DRB configured for this UE
162-
int fallback = qfiContextManager_.getFirstDrbForUe(destUeId);
163-
if (fallback >= 0) {
164-
drbIndex = fallback;
165-
EV_WARN << "SDAP TX: No DRB mapping for ueNodeId=" << destUeId << " QFI=" << (int)qfi
166-
<< ", falling back to first DRB " << drbIndex << " for this UE\n";
167-
} else {
168-
EV_WARN << "SDAP TX: No DRB mapping for ueNodeId=" << destUeId << " QFI=" << (int)qfi
169-
<< ", no DRBs configured for this UE, using DRB 0\n";
170-
}
171-
}
172-
}
141+
// Lookup DRB context: nodeId is NODEID_NONE on UE, destUeId on gNB
142+
MacNodeId nodeId = NODEID_NONE;
143+
if (!isUe) {
144+
nodeId = pkt->getTag<FlowControlInfo>()->getDestId();
145+
if (nodeId == NODEID_NONE)
146+
EV_WARN << "SDAP TX: destId not set in FlowControlInfo\n";
147+
}
148+
149+
const DrbConfig *drb = drbTable_.getDrbForQfi(nodeId, qfi);
150+
if (!drb) {
151+
drb = drbTable_.getDefaultDrb(nodeId);
152+
if (drb)
153+
EV_WARN << "SDAP TX: No DRB mapping for nodeId=" << nodeId << " QFI=" << (int)qfi
154+
<< ", falling back to default DRB " << drb->drbId << "\n";
173155
}
156+
if (!drb)
157+
throw cRuntimeError("SDAP TX: No DRB available for nodeId=%d", (int)num(nodeId));
174158

175-
EV_INFO << "SDAP TX: Selected DRB=" << drbIndex << " for QFI=" << (int)qfi << "\n";
159+
EV_INFO << "SDAP TX: Selected DRB=" << drb->drbId << " for QFI=" << (int)qfi << "\n";
176160

177161
// Check if SDAP header is required for this DRB
178-
if (requiresSdapHeader(drbIndex)) {
162+
if (requiresSdapHeader(drb)) {
179163
// Build SDAP header according to 3GPP TS 37.324
180164
auto sdapHeader = makeShared<NrSdapHeader>();
181165
sdapHeader->setQfi(qfi);
@@ -189,38 +173,38 @@ void NrSdap::handleUpperPacket(inet::Packet *pkt)
189173
<< ", reflectiveQoS = " << (enableReflectiveQos ? "true" : "false") << "\n";
190174
}
191175
else {
192-
EV_INFO << "SDAP TX: No SDAP header required for DRB " << drbIndex << "\n";
176+
EV_INFO << "SDAP TX: No SDAP header required for DRB " << drb->drbId << "\n";
193177
}
194178

195179
// Set DRB ID and RLC type on FlowControlInfo for PDCP/RLC entity creation and routing
196180
auto lteInfo = pkt->getTagForUpdate<FlowControlInfo>();
197-
lteInfo->setDrbId(DrbId(drbIndex));
198-
const DrbContext *ctx = qfiContextManager_.getDrbContext(drbIndex);
199-
if (ctx)
200-
lteInfo->setRlcType(ctx->rlcType);
181+
lteInfo->setDrbId(drb->drbId);
182+
lteInfo->setRlcType(drb->rlcType);
201183

202184
// Establish connection if not yet done for this (drbId, destId) pair
203-
if (establishedConnections_.insert({DrbId(drbIndex), lteInfo->getDestId()}).second)
185+
if (establishedConnections_.insert({drb->drbId, lteInfo->getDestId()}).second)
204186
binder_->establishUnidirectionalDataConnection(lteInfo.get());
205187

206188
// Set protocol tag for outgoing frame to PDCP layer
207189
pkt->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&LteProtocol::sdap);
208190

209-
EV_INFO << "SDAP TX: Forwarding to DRB " << drbIndex << "\n";
191+
EV_INFO << "SDAP TX: Forwarding to DRB " << drb->drbId << "\n";
210192
send(pkt, "pdcpOut");
211193
}
212194

213195
void NrSdap::handleLowerPacket(inet::Packet *pkt)
214196
{
215197
auto lteInfo = pkt->findTag<FlowControlInfo>();
216-
int drbIndex = lteInfo ? num(lteInfo->getDrbId()) : -1;
198+
DrbId drbId = lteInfo ? lteInfo->getDrbId() : DRBID_NONE;
199+
MacNodeId ueId = (!isUe && lteInfo) ? lteInfo->getSourceId() : NODEID_NONE;
200+
const DrbConfig *drb = (drbId != DRBID_NONE) ? drbTable_.getDrb(DrbKey(ueId, drbId)) : nullptr;
217201

218-
EV_INFO << "SDAP RX: Received packet from DRB " << drbIndex << ": " << pkt->peekAtFront() << "\n";
202+
EV_INFO << "SDAP RX: Received packet from DRB " << drbId << ": " << pkt->peekAtFront() << "\n";
219203

220204
int qfi = 0;
221205

222206
// Check if packet has SDAP header (should be at the front according to 3GPP TS 37.324)
223-
if (requiresSdapHeader(drbIndex)) {
207+
if (requiresSdapHeader(drb)) {
224208
// Extract SDAP header from the front of the packet
225209
auto sdapHeader = pkt->removeAtFront<NrSdapHeader>();
226210
qfi = sdapHeader->getQfi();
@@ -242,30 +226,27 @@ void NrSdap::handleLowerPacket(inet::Packet *pkt)
242226
}
243227
}
244228
else {
245-
EV_INFO << "SDAP RX: No SDAP header expected for DRB " << drbIndex << "\n";
229+
EV_INFO << "SDAP RX: No SDAP header expected for DRB " << drbId << "\n";
246230

247231
// For DRBs without SDAP header, derive QFI from DRB context (use first QFI in the list)
248-
const DrbContext* ctx = qfiContextManager_.getDrbContext(drbIndex);
249-
if (ctx && !ctx->qfiList.empty()) {
250-
qfi = ctx->qfiList[0];
232+
if (drb && !drb->qfiList.empty()) {
233+
qfi = drb->qfiList[0];
251234
EV_INFO << "SDAP RX: Using QFI " << qfi << " from DRB context\n";
252235
}
253236
}
254237

255238
// Validate QFI ↔ DRB consistency
256-
const DrbContext* ctxValidate = qfiContextManager_.getDrbContext(drbIndex);
257-
if (ctxValidate) {
258-
if (!contains(ctxValidate->qfiList, (int)qfi))
259-
EV_WARN << "SDAP RX: DRB/QFI mismatch! Received on DRB=" << drbIndex << ", QFI=" << qfi << " not in qfiList\n";
239+
if (drb) {
240+
if (!contains(drb->qfiList, (int)qfi))
241+
EV_WARN << "SDAP RX: DRB/QFI mismatch! Received on DRB=" << drbId << ", QFI=" << qfi << " not in qfiList\n";
260242
}
261243

262244
// Add QoS indication tag for upper layers
263245
auto qosIndTag = pkt->addTagIfAbsent<QfiInd>();
264246
qosIndTag->setQfi(qfi);
265247

266248
// Set protocol tag for upper layer based on PDU session type
267-
const DrbContext* ctxProto = qfiContextManager_.getDrbContext(drbIndex);
268-
const inet::Protocol *upperProto = getUpperProtocol(ctxProto);
249+
const inet::Protocol *upperProto = getUpperProtocol(drb);
269250
pkt->addTagIfAbsent<PacketProtocolTag>()->setProtocol(upperProto);
270251

271252
EV_INFO << "SDAP RX: Forwarding packet with QFI " << qfi << " to upper layer (protocol: " << upperProto->getName() << ")\n";

src/simu5g/stack/sdap/NrSdap.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#include <omnetpp.h>
1616
#include <set>
17-
#include "simu5g/stack/sdap/common/QfiContextManager.h"
17+
#include "simu5g/stack/sdap/common/DrbTable.h"
1818
#include "simu5g/stack/sdap/common/ReflectiveQosTable.h"
1919
#include "simu5g/common/binder/Binder.h"
2020
#include <inet/common/ModuleRefByPar.h>
@@ -44,7 +44,7 @@ namespace simu5g {
4444
class NrSdap : public cSimpleModule
4545
{
4646
protected:
47-
QfiContextManager qfiContextManager_;
47+
DrbTable drbTable_;
4848
inet::ModuleRefByPar<ReflectiveQosTable> reflectiveQosTable;
4949
inet::ModuleRefByPar<Binder> binder_;
5050
bool isUe = true; // Node role: true for UE, false for gNB
@@ -53,17 +53,14 @@ class NrSdap : public cSimpleModule
5353
std::set<std::pair<DrbId, MacNodeId>> establishedConnections_;
5454

5555
protected:
56-
bool requiresSdapHeader(int drbIndex);
56+
bool requiresSdapHeader(const DrbConfig *drb);
5757
bool shouldEnableReflectiveQos(int qfi);
58-
const inet::Protocol *getUpperProtocol(const DrbContext *ctx);
58+
const inet::Protocol *getUpperProtocol(const DrbConfig *ctx);
5959
virtual void initialize() override;
6060
virtual void handleMessage(cMessage *msg) override;
6161
virtual void handleUpperPacket(inet::Packet *pkt);
6262
virtual void handleLowerPacket(inet::Packet *pkt);
6363

64-
public:
65-
int getLcid(int drbIndex) { return qfiContextManager_.getLcid(drbIndex); }
66-
int getDrbIndexForMacCid(MacNodeId ueNodeId, LogicalCid lcid) { return qfiContextManager_.getDrbIndexForMacCid(ueNodeId, lcid); }
6764
};
6865

6966
} //namespace

src/simu5g/stack/sdap/NrSdap.ned

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ package simu5g.stack.sdap;
2525
// Supports all 3GPP PDU session types (IPv4, IPv6, Ethernet, Unstructured)
2626
// via the pduSessionType field in drbConfig.
2727
//
28+
// drbConfig fields:
29+
// - drb (int): DRB identifier (= nrPdcp[]/nrRlc[] array index)
30+
// - ue (int, optional): UE MacNodeId (gNB only; omit on UE side)
31+
// - qfiList (int[]): QFI values mapped to this DRB
32+
// - rlcType (string, optional): RLC mode ("AM", "UM", "TM"); default: "UM"
33+
// - pduSessionType (string, optional): "IPv4", "IPv6", "Ethernet", "Unstructured";
34+
// default: "IPv4"
35+
// - upperProtocol (string, optional): INET protocol name for upper layer dispatch
36+
// (this is normally only needed for "Unstructured" PDU sessions); default:
37+
// derived from pduSessionType
38+
// - isDefault (bool, optional): marks this as the default DRB for the UE;
39+
// if omitted, the first DRB entry per UE (per nodeId) is automatically used
40+
// as default. The default DRB is the fallback when no QFI-to-DRB mapping matches.
41+
//
2842
// Gates:
2943
// - upperLayerIn/upperLayerOut: connects to the upper layer (Ip2Nic or app).
3044
// - pdcpIn/pdcpOut: connects to the PDCP layer.
@@ -34,7 +48,7 @@ simple NrSdap like INrSdap
3448
parameters:
3549
string nodeRole @enum("UE", "gNB"); // Node role: "UE" or "gNB" - determines reflective QoS behavior
3650
string binderModule = default("binder");
37-
object drbConfig = default([]); // JSON array of DRB configurations: [{drb, ue, qfiList, rlcType, pduSessionType, upperProtocol}, ...]; rlcType defaults to UM, pduSessionType defaults to IPv4, upperProtocol defaults based on pduSessionType.
51+
object drbConfig = default([]); // JSON array: [{drb, ue, qfiList, rlcType, pduSessionType, upperProtocol, isDefault}, ...]; see banner comment for details
3852
string reflectiveQosTableModule = default(""); // UE only: path to ReflectiveQosTable module (empty = disabled)
3953
bool addSdapHeader = default(true);
4054
bool useReflectiveQos = default(false); // UE only
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,29 @@
99
// and cannot be removed from it.
1010
///
1111

12-
#ifndef STACK_SDAP_COMMON_QFICONTEXT_H_
13-
#define STACK_SDAP_COMMON_QFICONTEXT_H_
12+
#ifndef STACK_SDAP_COMMON_DRBCONFIG_H_
13+
#define STACK_SDAP_COMMON_DRBCONFIG_H_
1414

1515
#include <vector>
1616
#include "simu5g/common/LteCommon.h"
1717

1818
namespace simu5g {
1919

2020
// Per-DRB configuration entry, built from the drbConfig JSON parameter.
21-
struct DrbContext {
22-
int drbIndex = -1; // global DRB instance index (= nrPdcp[]/nrRlc[] array index)
21+
struct DrbConfig {
22+
DrbId drbId = DRBID_NONE; // DRB identifier (= nrPdcp[]/nrRlc[] array index)
2323
MacNodeId ueNodeId = NODEID_NONE; // NODEID_NONE = "self" (UE side); numeric MacNodeId on gNB
24-
int lcid = -1; // LCID = local DRB index within that UE's DRB set (auto-derived)
24+
bool isDefault = false; // true if this is the default DRB for this UE
2525
std::vector<int> qfiList; // QFIs mapped to this DRB
2626
LteRlcType rlcType = UM; // RLC mode for this DRB (AM, UM, TM)
2727
PduSessionType pduSessionType = IP_V4; // PDU session type (3GPP TS 23.501)
2828
std::string upperProtocol; // INET protocol name for upper layer dispatch (empty = derive from pduSessionType)
2929
};
3030

31-
inline std::ostream& operator<<(std::ostream& os, const DrbContext& ctx) {
32-
os << "ue=" << ctx.ueNodeId << " lcid=" << ctx.lcid << " qfi=[";
31+
inline std::ostream& operator<<(std::ostream& os, const DrbConfig& ctx) {
32+
os << "drbId=" << ctx.drbId << " ue=" << ctx.ueNodeId;
33+
if (ctx.isDefault) os << " DEFAULT";
34+
os << " qfi=[";
3335
for (int i = 0; i < (int)ctx.qfiList.size(); i++) {
3436
if (i) os << ",";
3537
os << ctx.qfiList[i];
@@ -47,4 +49,4 @@ inline std::ostream& operator<<(std::ostream& os, const std::pair<MacNodeId,int>
4749

4850
} // namespace simu5g
4951

50-
#endif /* STACK_SDAP_COMMON_QFICONTEXT_H_ */
52+
#endif /* STACK_SDAP_COMMON_DRBCONFIG_H_ */

0 commit comments

Comments
 (0)