RlcUmEntityD2D.h Source File

Simu5G: RlcUmEntityD2D.h Source File
Simu5G
RlcUmEntityD2D.h
1//
2// Simu5G
3//
4// Copyright (C) 2012-2021 Giovanni Nardini, Giovanni Stea, Antonio Virdis et al. (University of Pisa)
5// Copyright (C) 2022-2026 Giovanni Nardini, Giovanni Stea et al. (University of Pisa)
6//
7// This file is part of a software released under the license included in file
8// "license.pdf". Please read LICENSE and README files before using it.
9// The above files and the present reference are part of the software itself,
10// and cannot be removed from it.
11//
12
13#ifndef _SIMU5G_RLCUMENTITYD2D_H_
14#define _SIMU5G_RLCUMENTITYD2D_H_
15
16#include <inet/common/ModuleRefByPar.h>
17
18#include "simu5g/stack/d2d/rlc/ID2dRlcUmTxEntity.h"
19#include "simu5g/stack/d2d/rrc/D2DModeController.h"
20#include "simu5g/stack/rlc/um/LteRlcUmTxEntity.h"
21#include "simu5g/stack/rlc/um/NrRlcUmTxEntity.h"
22#include "simu5g/stack/rlc/um/LteRlcUmRxEntity.h"
23#include "simu5g/stack/rlc/um/NrRlcUmRxEntity.h"
24#include "simu5g/stack/rlc/packet/LteRlcNewDataTag_m.h"
25
26namespace simu5g {
27
28using namespace omnetpp;
29
30// =====================================================================
31// TX side
32// =====================================================================
33
52template<class Base>
53class RlcUmTxEntityD2D : public Base, public ID2dRlcUmTxEntity
54{
55 protected:
56 // D2D mode-switch controller of this NIC (absent on non-D2D stacks)
57 inet::ModuleRefByPar<D2DModeController> d2dModeController_;
58
59 // peer this entity is currently registered under at the controller, so that it can
60 // withdraw itself under exactly the key it was filed under (see ~RlcUmTxEntityD2D)
61 MacNodeId registeredPeerId_ = NODEID_NONE;
62
63 // if true, the entity watches for its TX buffer becoming empty
64 bool notifyEmptyBuffer_ = false;
65
66 // if true, incoming SDUs are parked in sduHoldingQueue_ instead of buffered
67 bool holdingDownstreamInPackets_ = false;
68
69 // the SDU holding buffer
70 inet::cPacketQueue sduHoldingQueue_;
71
72 void initialize(int stage) override
73 {
74 Base::initialize(stage);
75 if (stage == inet::INITSTAGE_LOCAL) {
76 d2dModeController_.reference(this, "d2dModeControllerModule", false);
77 WATCH(registeredPeerId_);
78 WATCH(notifyEmptyBuffer_);
79 WATCH(holdingDownstreamInPackets_);
80 WATCH(sduHoldingQueue_);
81 }
82 }
83
84 void setFlowControlInfo(FlowControlInfo *info) override
85 {
86 Base::setFlowControlInfo(info);
87
88 // D2D peer tracking: register with the mode controller now that the peer id
89 // is known, so mode switches can coordinate holding/draining of the buffers
90 // (this used to be done by BearerManagement for every UM entity).
91 if (d2dModeController_) {
92 unregisterFromD2DModeController(); // no-op unless the flow is being re-set
93 registeredPeerId_ = MacNodeId(this->flowControlInfo_->getD2dRxPeerId());
94 d2dModeController_->registerD2DPeerTxEntity(registeredPeerId_, this);
95 }
96 }
97
107 {
108 if (d2dModeController_ && registeredPeerId_ != NODEID_NONE)
109 d2dModeController_->unregisterD2DPeerTxEntity(registeredPeerId_, this);
110 registeredPeerId_ = NODEID_NONE;
111 }
112
113 // park the SDU while the old-mode entity is still draining
114 bool interceptSdu(inet::Packet *pkt) override
115 {
116 if (holdingDownstreamInPackets_) {
117 // do not store in the TX buffer and do not signal the MAC layer
118 EV << NOW << " RlcUmTxEntityD2D::interceptSdu - storing new SDU into the holding buffer" << endl;
119 sduHoldingQueue_.insert(pkt);
120 return true;
121 }
122 return Base::interceptSdu(pkt);
123 }
124
125 // the old-mode entity has drained: let the peer's new-mode entity go ahead
126 void onTxBufferEmptied() override
127 {
128 if (notifyEmptyBuffer_ && this->isTxBufferEmpty()) {
129 notifyEmptyBuffer_ = false;
130 if (d2dModeController_ && this->flowControlInfo_)
131 d2dModeController_->resumeDownstreamInPackets(this->flowControlInfo_->getD2dRxPeerId());
132 }
133 }
134
140 virtual void resetTxNumbering() = 0;
141
142 public:
144
145 void startHoldingDownstreamInPackets() override { holdingDownstreamInPackets_ = true; }
146
147 bool isHoldingDownstreamInPackets() override { return holdingDownstreamInPackets_; }
148
149 bool isEmptyingBuffer() override { return notifyEmptyBuffer_; }
150
152 {
153 EV << NOW << " RlcUmTxEntityD2D::resumeDownstreamInPackets - resume buffering incoming downstream packets of the RLC entity associated with the new mode" << endl;
154
155 holdingDownstreamInPackets_ = false;
156
157 // move all SDUs in the holding buffer to the TX buffer
158 while (!sduHoldingQueue_.isEmpty()) {
159 auto pktRlc = check_and_cast<inet::Packet *>(sduHoldingQueue_.front());
160 sduHoldingQueue_.pop();
161
162 // store the SDU in the TX buffer and notify the MAC (drop on overflow)
163 this->bufferSduAndNotifyMac(pktRlc);
164 }
165 }
166
167 void rlcHandleD2DModeSwitch(bool oldConnection, bool clearBuffer) override
168 {
169 // Clearing the old-mode buffer deletes SDUs owned by THIS entity, and we are
170 // reached by a direct call from the mux; switch context so those deletes run
171 // in the owner's context.
172 Enter_Method_Silent("rlcHandleD2DModeSwitch()");
173
174 if (oldConnection) {
175 if (getNodeTypeById(this->ownerNodeId_) == NODEB) {
176 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - nothing to do on DL leg of IM flow" << endl;
177 return;
178 }
179
180 if (clearBuffer) {
181 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - clear TX buffer of the RLC entity associated with the old mode" << endl;
182 this->clearQueue();
183 }
184 else if (!this->isTxBufferEmpty()) {
185 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - check when the TX buffer of the old mode becomes empty" << endl;
186 notifyEmptyBuffer_ = true;
187 }
188 else {
189 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - TX buffer of the old mode is already empty" << endl;
190 }
191 }
192 else {
193 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - reset numbering of the RLC TX entity corresponding to the new mode" << endl;
195
196 if (!clearBuffer && d2dModeController_ && this->flowControlInfo_ &&
197 d2dModeController_->isEmptyingTxBuffer(this->flowControlInfo_->getD2dRxPeerId())) {
198 // the old-mode entity is still draining: hold incoming SDUs until it finishes
199 EV << NOW << " RlcUmTxEntityD2D::rlcHandleD2DModeSwitch - halt incoming downstream connections of the new mode" << endl;
201 }
202 }
203 }
204};
205
209class LteRlcUmTxEntityD2D : public RlcUmTxEntityD2D<LteRlcUmTxEntity>
210{
211 protected:
212 void resetTxNumbering() override { sno_ = 0; }
213};
214
218class NrRlcUmTxEntityD2D : public RlcUmTxEntityD2D<NrRlcUmTxEntity>
219{
220 protected:
221 void resetTxNumbering() override { sduBuffer->resetTxNext(); }
222};
223
224// =====================================================================
225// RX side
226// =====================================================================
227
236template<class Base>
237class RlcUmRxEntityD2D : public Base, public ID2dRlcUmRxEntity
238{
239 protected:
240 // returns true if this entity serves a D2D_MULTI connection
241 bool isD2DMultiConnection() { return this->flowControlInfo_->getDirection() == D2D_MULTI; }
242
243 // Interned in initialize() rather than registered by a static initializer, so that
244 // linking the D2D package in cannot shift the signal ids the core assigns. See the
245 // "Signals" note in D2dUeMacBase.h.
246 simsignal_t rlcDelayD2DSignal_ = SIMSIGNAL_NULL;
247 simsignal_t rlcThroughputD2DSignal_ = SIMSIGNAL_NULL;
248 simsignal_t rlcPduDelayD2DSignal_ = SIMSIGNAL_NULL;
249 simsignal_t rlcPduThroughputD2DSignal_ = SIMSIGNAL_NULL;
250
251 void initialize(int stage) override
252 {
253 Base::initialize(stage);
254 if (stage == inet::INITSTAGE_LOCAL) {
255 rlcDelayD2DSignal_ = cComponent::registerSignal("rlcDelayD2D");
256 rlcThroughputD2DSignal_ = cComponent::registerSignal("rlcThroughputD2D");
257 rlcPduDelayD2DSignal_ = cComponent::registerSignal("rlcPduDelayD2D");
258 rlcPduThroughputD2DSignal_ = cComponent::registerSignal("rlcPduThroughputD2D");
259 }
260 }
261
267
272 virtual void resetRxNumbering() = 0;
273
274 public:
275 void rlcHandleD2DModeSwitch(bool oldConnection, bool oldMode, bool clearBuffer) override
276 {
277 Enter_Method_Silent("rlcHandleD2DModeSwitch()");
278
279 if (oldConnection) {
280 if (getNodeTypeById(this->ownerNodeId_) == UE && oldMode == IM) {
281 EV << NOW << " RlcUmRxEntityD2D::rlcHandleD2DModeSwitch - nothing to do on DL leg of IM flow" << endl;
282 return;
283 }
284
285 if (clearBuffer) {
286 EV << NOW << " RlcUmRxEntityD2D::rlcHandleD2DModeSwitch - clear RX buffer of the RLC entity associated with the old mode" << endl;
288 }
289 }
290 else {
291 EV << NOW << " RlcUmRxEntityD2D::rlcHandleD2DModeSwitch - handle numbering of the RLC entity associated with the newly selected mode" << endl;
293 }
294 }
295};
296
304class LteRlcUmRxEntityD2D : public RlcUmRxEntityD2D<LteRlcUmRxEntity>
305{
306 protected:
307 // after a mode switch, the first PDU of the new-mode entity is forced in-sequence
308 bool resetFlag_ = false;
309
310 void initialize(int stage) override
311 {
312 RlcUmRxEntityD2D<LteRlcUmRxEntity>::initialize(stage);
313 if (stage == inet::INITSTAGE_LOCAL)
314 WATCH(resetFlag_);
315 }
316
318 void resetRxNumbering() override;
319
320 void onFirstPduEnqueued(unsigned int pduSno) override;
321 bool consumeReassemblyReset(unsigned int pduSno) override;
322 void emitPduStats(Direction dir, double tputSample, simtime_t creationTime) override;
323 void emitSduStats(Direction dir, double tputSample, simtime_t creationTime) override;
324};
325
329class NrRlcUmRxEntityD2D : public RlcUmRxEntityD2D<NrRlcUmRxEntity>
330{
331 protected:
333 void resetRxNumbering() override;
334
335 void emitRxStatistics(bool perPdu, double throughput, simtime_t delay) override;
336};
337
338} //namespace
339
340#endif
What a D2D UM RX entity offers the D2D-aware RLC mux.
Definition ID2dRlcUmTxEntity.h:70
What a D2D UM TX entity offers the D2D mode controller.
Definition ID2dRlcUmTxEntity.h:30
D2D-capable LTE (TS 36.322) RLC UM receiving entity.
Definition RlcUmEntityD2D.h:305
void discardRxBufferForModeSwitch() override
void resetRxNumbering() override
D2D-capable LTE (TS 36.322, FI framing) RLC UM transmitting entity.
Definition RlcUmEntityD2D.h:210
void resetTxNumbering() override
Definition RlcUmEntityD2D.h:212
D2D-capable NR (TS 38.322) RLC UM receiving entity.
Definition RlcUmEntityD2D.h:330
void discardRxBufferForModeSwitch() override
void resetRxNumbering() override
D2D-capable NR (TS 38.322, SO framing) RLC UM transmitting entity.
Definition RlcUmEntityD2D.h:219
void resetTxNumbering() override
Definition RlcUmEntityD2D.h:221
D2D mode-switch machinery for an RLC UM receiving entity.
Definition RlcUmEntityD2D.h:238
void rlcHandleD2DModeSwitch(bool oldConnection, bool oldMode, bool clearBuffer) override
Definition RlcUmEntityD2D.h:275
virtual void discardRxBufferForModeSwitch()=0
virtual void resetRxNumbering()=0
D2D mode-switch machinery for an RLC UM transmitting entity.
Definition RlcUmEntityD2D.h:54
void unregisterFromD2DModeController()
Definition RlcUmEntityD2D.h:106
void resumeDownstreamInPackets() override
Definition RlcUmEntityD2D.h:151
void startHoldingDownstreamInPackets() override
Definition RlcUmEntityD2D.h:145
void rlcHandleD2DModeSwitch(bool oldConnection, bool clearBuffer) override
Definition RlcUmEntityD2D.h:167
virtual void resetTxNumbering()=0
bool isHoldingDownstreamInPackets() override
Definition RlcUmEntityD2D.h:147
bool isEmptyingBuffer() override
Definition RlcUmEntityD2D.h:149
Definition AlertReceiver.h:24
constexpr MacNodeId NODEID_NONE
MAC node ID.
Definition LteTypes.h:54