A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lte-rlc-um.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Manuel Requena <manuel.requena@cttc.es>
7 */
8
9#include "lte-rlc-um.h"
10
11#include "lte-rlc-header.h"
13#include "lte-rlc-tag.h"
14
15#include "ns3/log.h"
16#include "ns3/simulator.h"
17
18namespace ns3
19{
20
21NS_LOG_COMPONENT_DEFINE("LteRlcUm");
22
24
26 : m_maxTxBufferSize(10 * 1024),
27 m_txBufferSize(0),
28 m_sequenceNumber(0),
29 m_vrUr(0),
30 m_vrUx(0),
31 m_vrUh(0),
32 m_windowSize(512),
33 m_expectedSeqNumber(0)
34{
35 NS_LOG_FUNCTION(this);
37}
38
43
46{
47 static TypeId tid =
48 TypeId("ns3::LteRlcUm")
50 .SetGroupName("Lte")
51 .AddConstructor<LteRlcUm>()
52 .AddAttribute("MaxTxBufferSize",
53 "Maximum Size of the Transmission Buffer (in Bytes)",
54 UintegerValue(10 * 1024),
57 .AddAttribute("ReorderingTimer",
58 "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
62 .AddAttribute(
63 "EnablePdcpDiscarding",
64 "Whether to use the PDCP discarding, i.e., perform discarding at the moment "
65 "of passing the PDCP SDU to RLC)",
66 BooleanValue(true),
69 .AddAttribute("DiscardTimerMs",
70 "Discard timer in milliseconds to be used to discard packets. "
71 "If set to 0 then packet delay budget will be used as the discard "
72 "timer value, otherwise it will be used this value.",
76 return tid;
77}
78
79void
88
89/**
90 * RLC SAP
91 */
92
93void
95{
96 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
97 if (m_txBufferSize + p->GetSize() <= m_maxTxBufferSize)
98 {
100 {
101 // discart the packet
102 uint32_t headOfLineDelayInMs = 0;
103 uint32_t discardTimerMs =
105
106 if (!m_txBuffer.empty())
107 {
108 headOfLineDelayInMs =
109 (Simulator::Now() - m_txBuffer.begin()->m_waitingSince).GetMilliSeconds();
110 }
111 NS_LOG_DEBUG("head of line delay in MS:" << headOfLineDelayInMs);
112 if (headOfLineDelayInMs > discardTimerMs)
113 {
114 NS_LOG_INFO("Tx HOL is higher than this packet can allow. RLC SDU discarded");
115 NS_LOG_DEBUG("headOfLineDelayInMs = " << headOfLineDelayInMs);
116 NS_LOG_DEBUG("m_packetDelayBudgetMs = " << m_packetDelayBudgetMs);
117 NS_LOG_DEBUG("packet size = " << p->GetSize());
118 m_txDropTrace(p);
119 }
120 }
121
122 /** Store PDCP PDU */
125 p->AddPacketTag(tag);
126 NS_LOG_INFO("Adding RLC SDU to Tx Buffer after adding LteRlcSduStatusTag: FULL_SDU");
127 m_txBuffer.emplace_back(p, Simulator::Now());
128 m_txBufferSize += p->GetSize();
129 NS_LOG_LOGIC("NumOfBuffers = " << m_txBuffer.size());
130 NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
131 }
132 else
133 {
134 // Discard full RLC SDU
135 NS_LOG_INFO("Tx Buffer is full. RLC SDU discarded");
136 NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
137 NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
138 NS_LOG_LOGIC("packet size = " << p->GetSize());
139 m_txDropTrace(p);
140 }
141
142 /** Report Buffer Status */
145}
146
147/**
148 * MAC SAP
149 */
150
151void
153{
154 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
155 NS_LOG_INFO("RLC layer is preparing data for the following Tx opportunity of "
156 << txOpParams.bytes << " bytes for RNTI=" << m_rnti << ", LCID=" << (uint32_t)m_lcid
157 << ", CCID=" << (uint32_t)txOpParams.componentCarrierId << ", HARQ ID="
158 << (uint32_t)txOpParams.harqId << ", MIMO Layer=" << (uint32_t)txOpParams.layer);
159
160 if (txOpParams.bytes <= 2)
161 {
162 // Stingy MAC: Header fix part is 2 bytes, we need more bytes for the data
163 NS_LOG_INFO("TX opportunity too small - Only " << txOpParams.bytes << " bytes");
164 return;
165 }
166
167 Ptr<Packet> packet = Create<Packet>();
168 LteRlcHeader rlcHeader;
169
170 // Build Data field
171 uint32_t nextSegmentSize = txOpParams.bytes - 2;
172 uint32_t nextSegmentId = 1;
173 uint32_t dataFieldAddedSize = 0;
174 std::vector<Ptr<Packet>> dataField;
175
176 // Remove the first packet from the transmission buffer.
177 // If only a segment of the packet is taken, then the remaining is given back later
178 if (m_txBuffer.empty())
179 {
180 NS_LOG_LOGIC("No data pending");
181 return;
182 }
183
184 Ptr<Packet> firstSegment = m_txBuffer.begin()->m_pdu->Copy();
185 Time firstSegmentTime = m_txBuffer.begin()->m_waitingSince;
186
187 NS_LOG_LOGIC("SDUs in TxBuffer = " << m_txBuffer.size());
188 NS_LOG_LOGIC("First SDU buffer = " << firstSegment);
189 NS_LOG_LOGIC("First SDU size = " << firstSegment->GetSize());
190 NS_LOG_LOGIC("Next segment size = " << nextSegmentSize);
191 NS_LOG_LOGIC("Remove SDU from TxBuffer");
192 m_txBufferSize -= firstSegment->GetSize();
193 NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
194 m_txBuffer.erase(m_txBuffer.begin());
195
196 while (firstSegment && (firstSegment->GetSize() > 0) && (nextSegmentSize > 0))
197 {
198 NS_LOG_LOGIC("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
199 NS_LOG_LOGIC(" firstSegment size = " << firstSegment->GetSize());
200 NS_LOG_LOGIC(" nextSegmentSize = " << nextSegmentSize);
201 if ((firstSegment->GetSize() > nextSegmentSize) ||
202 // Segment larger than 2047 octets can only be mapped to the end of the Data field
203 (firstSegment->GetSize() > 2047))
204 {
205 // Take the minimum size, due to the 2047-bytes 3GPP exception
206 // This exception is due to the length of the LI field (just 11 bits)
207 uint32_t currSegmentSize = std::min(firstSegment->GetSize(), nextSegmentSize);
208
209 NS_LOG_LOGIC(" IF ( firstSegment > nextSegmentSize ||");
210 NS_LOG_LOGIC(" firstSegment > 2047 )");
211
212 // Segment txBuffer.FirstBuffer and
213 // Give back the remaining segment to the transmission buffer
214 Ptr<Packet> newSegment = firstSegment->CreateFragment(0, currSegmentSize);
215 NS_LOG_LOGIC(" newSegment size = " << newSegment->GetSize());
216
217 // Status tag of the new and remaining segments
218 // Note: This is the only place where a PDU is segmented and
219 // therefore its status can change
220 LteRlcSduStatusTag oldTag;
221 LteRlcSduStatusTag newTag;
222 firstSegment->RemovePacketTag(oldTag);
223 newSegment->RemovePacketTag(newTag);
225 {
228 }
229 else if (oldTag.GetStatus() == LteRlcSduStatusTag::LAST_SEGMENT)
230 {
232 // oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
233 }
234
235 // Give back the remaining segment to the transmission buffer
236 firstSegment->RemoveAtStart(currSegmentSize);
238 " firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize());
239 if (firstSegment->GetSize() > 0)
240 {
241 firstSegment->AddPacketTag(oldTag);
242
243 m_txBuffer.insert(m_txBuffer.begin(), TxPdu(firstSegment, firstSegmentTime));
244 m_txBufferSize += m_txBuffer.begin()->m_pdu->GetSize();
245
246 NS_LOG_LOGIC(" TX buffer: Give back the remaining segment");
247 NS_LOG_LOGIC(" TX buffers = " << m_txBuffer.size());
248 NS_LOG_LOGIC(" Front buffer size = " << m_txBuffer.begin()->m_pdu->GetSize());
249 NS_LOG_LOGIC(" txBufferSize = " << m_txBufferSize);
250 }
251 else
252 {
253 // Whole segment was taken, so adjust tag
255 {
257 }
259 {
261 }
262 }
263 // Segment is completely taken or
264 // the remaining segment is given back to the transmission buffer
265 firstSegment = nullptr;
266
267 // Put status tag once it has been adjusted
268 newSegment->AddPacketTag(newTag);
269
270 // Add Segment to Data field
271 dataFieldAddedSize = newSegment->GetSize();
272 dataField.push_back(newSegment);
273 newSegment = nullptr;
274
275 // ExtensionBit (Next_Segment - 1) = 0
277
278 // no LengthIndicator for the last one
279
280 nextSegmentSize -= dataFieldAddedSize;
281 nextSegmentId++;
282
283 // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
284
285 // (NO more segments) → exit
286 // break;
287 }
288 else if ((nextSegmentSize - firstSegment->GetSize() <= 2) || m_txBuffer.empty())
289 {
291 " IF nextSegmentSize - firstSegment->GetSize () <= 2 || txBuffer.size == 0");
292 // Add txBuffer.FirstBuffer to DataField
293 dataFieldAddedSize = firstSegment->GetSize();
294 dataField.push_back(firstSegment);
295 firstSegment = nullptr;
296
297 // ExtensionBit (Next_Segment - 1) = 0
299
300 // no LengthIndicator for the last one
301
302 nextSegmentSize -= dataFieldAddedSize;
303 nextSegmentId++;
304
305 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txBuffer.size());
306 if (!m_txBuffer.empty())
307 {
308 NS_LOG_LOGIC(" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
310 " First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize());
311 }
312 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
313
314 // nextSegmentSize <= 2 (only if txBuffer is not empty)
315
316 // (NO more segments) → exit
317 // break;
318 }
319 else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
320 {
321 NS_LOG_LOGIC(" IF firstSegment < NextSegmentSize && txBuffer.size > 0");
322 // Add txBuffer.FirstBuffer to DataField
323 dataFieldAddedSize = firstSegment->GetSize();
324 dataField.push_back(firstSegment);
325
326 // ExtensionBit (Next_Segment - 1) = 1
328
329 // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
330 rlcHeader.PushLengthIndicator(firstSegment->GetSize());
331
332 nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
333 nextSegmentId++;
334
335 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txBuffer.size());
336 if (!m_txBuffer.empty())
337 {
338 NS_LOG_LOGIC(" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
340 " First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize());
341 }
342 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
343 NS_LOG_LOGIC(" Remove SDU from TxBuffer");
344
345 // (more segments)
346 firstSegment = m_txBuffer.begin()->m_pdu->Copy();
347 firstSegmentTime = m_txBuffer.begin()->m_waitingSince;
348 m_txBufferSize -= firstSegment->GetSize();
349 m_txBuffer.pop_front();
350 NS_LOG_LOGIC(" txBufferSize = " << m_txBufferSize);
351 }
352 }
353
354 // Build RLC header
356
357 // Build RLC PDU with DataField and Header
358 auto it = dataField.begin();
359
360 uint8_t framingInfo = 0;
361
362 // FIRST SEGMENT
364 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
365 (*it)->PeekPacketTag(tag);
368 {
369 framingInfo |= LteRlcHeader::FIRST_BYTE;
370 }
371 else
372 {
373 framingInfo |= LteRlcHeader::NO_FIRST_BYTE;
374 }
375
376 while (it < dataField.end())
377 {
378 NS_LOG_LOGIC("Adding SDU/segment to packet, length = " << (*it)->GetSize());
379
380 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
381 (*it)->RemovePacketTag(tag);
382 if (packet->GetSize() > 0)
383 {
384 packet->AddAtEnd(*it);
385 }
386 else
387 {
388 packet = (*it);
389 }
390 it++;
391 }
392
393 // LAST SEGMENT (Note: There could be only one and be the first one)
394 it--;
397 {
398 framingInfo |= LteRlcHeader::LAST_BYTE;
399 }
400 else
401 {
402 framingInfo |= LteRlcHeader::NO_LAST_BYTE;
403 }
404
405 rlcHeader.SetFramingInfo(framingInfo);
406
407 NS_LOG_LOGIC("RLC header: " << rlcHeader);
408 packet->AddHeader(rlcHeader);
409
410 // Sender timestamp
411 RlcTag rlcTag(Simulator::Now());
412 packet->AddByteTag(rlcTag, 1, rlcHeader.GetSerializedSize());
413 m_txPdu(m_rnti, m_lcid, packet->GetSize());
414
415 // Send RLC PDU to MAC layer
417 params.pdu = packet;
418 params.rnti = m_rnti;
419 params.lcid = m_lcid;
420 params.layer = txOpParams.layer;
421 params.harqProcessId = txOpParams.harqId;
422 params.componentCarrierId = txOpParams.componentCarrierId;
423
424 NS_LOG_INFO("Forward RLC PDU to MAC Layer");
426
427 if (!m_txBuffer.empty())
428 {
431 }
432}
433
434void
439
440void
442{
443 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << rxPduParams.p->GetSize());
444
445 // Receiver timestamp
446 RlcTag rlcTag;
447 Time delay;
448
449 bool ret = rxPduParams.p->FindFirstMatchingByteTag(rlcTag);
450 NS_ASSERT_MSG(ret, "RlcTag is missing");
451
452 delay = Simulator::Now() - rlcTag.GetSenderTimestamp();
453 m_rxPdu(m_rnti, m_lcid, rxPduParams.p->GetSize(), delay.GetNanoSeconds());
454
455 // 5.1.2.2 Receive operations
456
457 // Get RLC header parameters
458 LteRlcHeader rlcHeader;
459 rxPduParams.p->PeekHeader(rlcHeader);
460 NS_LOG_LOGIC("RLC header: " << rlcHeader);
461 SequenceNumber10 seqNumber = rlcHeader.GetSequenceNumber();
462
463 // 5.1.2.2.1 General
464 // The receiving UM RLC entity shall maintain a reordering window according to state variable
465 // VR(UH) as follows:
466 // - a SN falls within the reordering window if (VR(UH) - UM_Window_Size) <= SN < VR(UH);
467 // - a SN falls outside of the reordering window otherwise.
468 // When receiving an UMD PDU from lower layer, the receiving UM RLC entity shall:
469 // - either discard the received UMD PDU or place it in the reception buffer (see sub
470 // clause 5.1.2.2.2);
471 // - if the received UMD PDU was placed in the reception buffer:
472 // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop
473 // t-Reordering as needed (see sub clause 5.1.2.2.3); When t-Reordering expires, the receiving
474 // UM RLC entity shall:
475 // - update state variables, reassemble and deliver RLC SDUs to upper layer and start
476 // t-Reordering as needed (see sub clause 5.1.2.2.4).
477
478 // 5.1.2.2.2 Actions when an UMD PDU is received from lower layer
479 // When an UMD PDU with SN = x is received from lower layer, the receiving UM RLC entity shall:
480 // - if VR(UR) < x < VR(UH) and the UMD PDU with SN = x has been received before; or
481 // - if (VR(UH) - UM_Window_Size) <= x < VR(UR):
482 // - discard the received UMD PDU;
483 // - else:
484 // - place the received UMD PDU in the reception buffer.
485
486 NS_LOG_LOGIC("VR(UR) = " << m_vrUr);
487 NS_LOG_LOGIC("VR(UX) = " << m_vrUx);
488 NS_LOG_LOGIC("VR(UH) = " << m_vrUh);
489 NS_LOG_LOGIC("SN = " << seqNumber);
490
494
495 if (((m_vrUr < seqNumber) && (seqNumber < m_vrUh) &&
496 (m_rxBuffer.count(seqNumber.GetValue()) > 0)) ||
497 (((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUr)))
498 {
499 NS_LOG_LOGIC("PDU discarded");
500 rxPduParams.p = nullptr;
501 return;
502 }
503 else
504 {
505 NS_LOG_LOGIC("Place PDU in the reception buffer");
506 m_rxBuffer[seqNumber.GetValue()] = rxPduParams.p;
507 }
508
509 // 5.1.2.2.3 Actions when an UMD PDU is placed in the reception buffer
510 // When an UMD PDU with SN = x is placed in the reception buffer, the receiving UM RLC entity
511 // shall:
512
513 // - if x falls outside of the reordering window:
514 // - update VR(UH) to x + 1;
515 // - reassemble RLC SDUs from any UMD PDUs with SN that falls outside of the reordering
516 // window, remove
517 // RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in
518 // ascending order of the RLC SN if not delivered before;
519 // - if VR(UR) falls outside of the reordering window:
520 // - set VR(UR) to (VR(UH) - UM_Window_Size);
521
522 if (!IsInsideReorderingWindow(seqNumber))
523 {
524 NS_LOG_LOGIC("SN is outside the reordering window");
525
526 m_vrUh = seqNumber + 1;
527 NS_LOG_LOGIC("New VR(UH) = " << m_vrUh);
528
530
532 {
534 NS_LOG_LOGIC("VR(UR) is outside the reordering window");
535 NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
536 }
537 }
538
539 // - if the reception buffer contains an UMD PDU with SN = VR(UR):
540 // - update VR(UR) to the SN of the first UMD PDU with SN > current VR(UR) that has not been
541 // received;
542 // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when
543 // doing
544 // so and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN
545 // if not delivered before;
546
547 if (m_rxBuffer.count(m_vrUr.GetValue()) > 0)
548 {
549 NS_LOG_LOGIC("Reception buffer contains SN = " << m_vrUr);
550
551 uint16_t newVrUr;
552 SequenceNumber10 oldVrUr = m_vrUr;
553
554 auto it = m_rxBuffer.find(m_vrUr.GetValue());
555 newVrUr = (it->first) + 1;
556 while (m_rxBuffer.count(newVrUr) > 0)
557 {
558 newVrUr++;
559 }
560 m_vrUr = newVrUr;
561 NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
562
564 }
565
566 // m_vrUh can change previously, set new modulus base
567 // for the t-Reordering timer-related comparisons
571
572 // - if t-Reordering is running:
573 // - if VR(UX) <= VR(UR); or
574 // - if VR(UX) falls outside of the reordering window and VR(UX) is not equal to VR(UH)::
575 // - stop and reset t-Reordering;
577 {
578 NS_LOG_LOGIC("Reordering timer is running");
579
580 if ((m_vrUx <= m_vrUr) || ((!IsInsideReorderingWindow(m_vrUx)) && (m_vrUx != m_vrUh)))
581 {
582 NS_LOG_LOGIC("Stop reordering timer");
584 }
585 }
586
587 // - if t-Reordering is not running (includes the case when t-Reordering is stopped due to
588 // actions above):
589 // - if VR(UH) > VR(UR):
590 // - start t-Reordering;
591 // - set VR(UX) to VR(UH).
593 {
594 NS_LOG_LOGIC("Reordering timer is not running");
595
596 if (m_vrUh > m_vrUr)
597 {
598 NS_LOG_LOGIC("VR(UH) > VR(UR)");
599 NS_LOG_LOGIC("Start reordering timer");
602 m_vrUx = m_vrUh;
603 NS_LOG_LOGIC("New VR(UX) = " << m_vrUx);
604 }
605 }
606}
607
608bool
610{
611 NS_LOG_FUNCTION(this << seqNumber);
612 NS_LOG_LOGIC("Reordering Window: " << m_vrUh << " - " << m_windowSize << " <= " << seqNumber
613 << " < " << m_vrUh);
614
617
618 if (((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUh))
619 {
620 NS_LOG_LOGIC(seqNumber << " is INSIDE the reordering window");
621 return true;
622 }
623 else
624 {
625 NS_LOG_LOGIC(seqNumber << " is OUTSIDE the reordering window");
626 return false;
627 }
628}
629
630void
632{
633 LteRlcHeader rlcHeader;
634 packet->RemoveHeader(rlcHeader);
635 uint8_t framingInfo = rlcHeader.GetFramingInfo();
636 SequenceNumber10 currSeqNumber = rlcHeader.GetSequenceNumber();
637 bool expectedSnLost;
638
639 if (currSeqNumber != m_expectedSeqNumber)
640 {
641 expectedSnLost = true;
642 NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
643 << ". Current SN = " << currSeqNumber);
644 m_expectedSeqNumber = currSeqNumber + 1;
645 }
646 else
647 {
648 expectedSnLost = false;
649 NS_LOG_LOGIC("No losses. Expected SN = " << m_expectedSeqNumber
650 << ". Current SN = " << currSeqNumber);
652 }
653
654 // Build list of SDUs
655 uint8_t extensionBit;
656 uint16_t lengthIndicator;
657 do
658 {
659 extensionBit = rlcHeader.PopExtensionBit();
660 NS_LOG_LOGIC("E = " << (uint16_t)extensionBit);
661
662 if (extensionBit == 0)
663 {
664 m_sdusBuffer.push_back(packet);
665 }
666 else // extensionBit == 1
667 {
668 lengthIndicator = rlcHeader.PopLengthIndicator();
669 NS_LOG_LOGIC("LI = " << lengthIndicator);
670
671 // Check if there is enough data in the packet
672 if (lengthIndicator >= packet->GetSize())
673 {
674 NS_LOG_LOGIC("INTERNAL ERROR: Not enough data in the packet ("
675 << packet->GetSize() << "). Needed LI=" << lengthIndicator);
676 }
677
678 // Split packet in two fragments
679 Ptr<Packet> data_field = packet->CreateFragment(0, lengthIndicator);
680 packet->RemoveAtStart(lengthIndicator);
681
682 m_sdusBuffer.push_back(data_field);
683 }
684 } while (extensionBit == 1);
685
686 // Current reassembling state
688 {
689 NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
690 }
692 {
693 NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
694 }
695 else
696 {
697 NS_LOG_LOGIC("Reassembling State = Unknown state");
698 }
699
700 // Received framing Info
701 NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
702
703 // Reassemble the list of SDUs (when there is no losses)
704 if (!expectedSnLost)
705 {
706 switch (m_reassemblingState)
707 {
708 case WAITING_S0_FULL:
709 switch (framingInfo)
710 {
713
714 /**
715 * Deliver one or multiple PDUs
716 */
717 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
718 {
720 }
721 m_sdusBuffer.clear();
722 break;
723
726
727 /**
728 * Deliver full PDUs
729 */
730 while (m_sdusBuffer.size() > 1)
731 {
733 m_sdusBuffer.pop_front();
734 }
735
736 /**
737 * Keep S0
738 */
739 m_keepS0 = m_sdusBuffer.front();
740 m_sdusBuffer.pop_front();
741 break;
742
745
746 /**
747 * Discard SI or SN
748 */
749 m_sdusBuffer.pop_front();
750
751 /**
752 * Deliver zero, one or multiple PDUs
753 */
754 while (!m_sdusBuffer.empty())
755 {
757 m_sdusBuffer.pop_front();
758 }
759 break;
760
762 if (m_sdusBuffer.size() == 1)
763 {
765 }
766 else
767 {
769 }
770
771 /**
772 * Discard SI or SN
773 */
774 m_sdusBuffer.pop_front();
775
776 if (!m_sdusBuffer.empty())
777 {
778 /**
779 * Deliver zero, one or multiple PDUs
780 */
781 while (m_sdusBuffer.size() > 1)
782 {
784 m_sdusBuffer.pop_front();
785 }
786
787 /**
788 * Keep S0
789 */
790 m_keepS0 = m_sdusBuffer.front();
791 m_sdusBuffer.pop_front();
792 }
793 break;
794
795 default:
796 /**
797 * ERROR: Transition not possible
798 */
800 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
801 break;
802 }
803 break;
804
805 case WAITING_SI_SF:
806 switch (framingInfo)
807 {
810
811 /**
812 * Deliver (Kept)S0 + SN
813 */
815 m_sdusBuffer.pop_front();
817
818 /**
819 * Deliver zero, one or multiple PDUs
820 */
821 while (!m_sdusBuffer.empty())
822 {
824 m_sdusBuffer.pop_front();
825 }
826 break;
827
830
831 /**
832 * Keep SI
833 */
834 if (m_sdusBuffer.size() == 1)
835 {
837 m_sdusBuffer.pop_front();
838 }
839 else // m_sdusBuffer.size () > 1
840 {
841 /**
842 * Deliver (Kept)S0 + SN
843 */
845 m_sdusBuffer.pop_front();
847
848 /**
849 * Deliver zero, one or multiple PDUs
850 */
851 while (m_sdusBuffer.size() > 1)
852 {
854 m_sdusBuffer.pop_front();
855 }
856
857 /**
858 * Keep S0
859 */
860 m_keepS0 = m_sdusBuffer.front();
861 m_sdusBuffer.pop_front();
862 }
863 break;
864
867 default:
868 /**
869 * ERROR: Transition not possible
870 */
872 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
873 break;
874 }
875 break;
876
877 default:
879 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
880 break;
881 }
882 }
883 else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the
884 // expected one)
885 {
886 switch (m_reassemblingState)
887 {
888 case WAITING_S0_FULL:
889 switch (framingInfo)
890 {
893
894 /**
895 * Deliver one or multiple PDUs
896 */
897 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
898 {
900 }
901 m_sdusBuffer.clear();
902 break;
903
906
907 /**
908 * Deliver full PDUs
909 */
910 while (m_sdusBuffer.size() > 1)
911 {
913 m_sdusBuffer.pop_front();
914 }
915
916 /**
917 * Keep S0
918 */
919 m_keepS0 = m_sdusBuffer.front();
920 m_sdusBuffer.pop_front();
921 break;
922
925
926 /**
927 * Discard SN
928 */
929 m_sdusBuffer.pop_front();
930
931 /**
932 * Deliver zero, one or multiple PDUs
933 */
934 while (!m_sdusBuffer.empty())
935 {
937 m_sdusBuffer.pop_front();
938 }
939 break;
940
942 if (m_sdusBuffer.size() == 1)
943 {
945 }
946 else
947 {
949 }
950
951 /**
952 * Discard SI or SN
953 */
954 m_sdusBuffer.pop_front();
955
956 if (!m_sdusBuffer.empty())
957 {
958 /**
959 * Deliver zero, one or multiple PDUs
960 */
961 while (m_sdusBuffer.size() > 1)
962 {
964 m_sdusBuffer.pop_front();
965 }
966
967 /**
968 * Keep S0
969 */
970 m_keepS0 = m_sdusBuffer.front();
971 m_sdusBuffer.pop_front();
972 }
973 break;
974
975 default:
976 /**
977 * ERROR: Transition not possible
978 */
980 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
981 break;
982 }
983 break;
984
985 case WAITING_SI_SF:
986 switch (framingInfo)
987 {
990
991 /**
992 * Discard S0
993 */
994 m_keepS0 = nullptr;
995
996 /**
997 * Deliver one or multiple PDUs
998 */
999 while (!m_sdusBuffer.empty())
1000 {
1002 m_sdusBuffer.pop_front();
1003 }
1004 break;
1005
1008
1009 /**
1010 * Discard S0
1011 */
1012 m_keepS0 = nullptr;
1013
1014 /**
1015 * Deliver zero, one or multiple PDUs
1016 */
1017 while (m_sdusBuffer.size() > 1)
1018 {
1020 m_sdusBuffer.pop_front();
1021 }
1022
1023 /**
1024 * Keep S0
1025 */
1026 m_keepS0 = m_sdusBuffer.front();
1027 m_sdusBuffer.pop_front();
1028
1029 break;
1030
1033
1034 /**
1035 * Discard S0
1036 */
1037 m_keepS0 = nullptr;
1038
1039 /**
1040 * Discard SI or SN
1041 */
1042 m_sdusBuffer.pop_front();
1043
1044 /**
1045 * Deliver zero, one or multiple PDUs
1046 */
1047 while (!m_sdusBuffer.empty())
1048 {
1050 m_sdusBuffer.pop_front();
1051 }
1052 break;
1053
1055 if (m_sdusBuffer.size() == 1)
1056 {
1058 }
1059 else
1060 {
1062 }
1063
1064 /**
1065 * Discard S0
1066 */
1067 m_keepS0 = nullptr;
1068
1069 /**
1070 * Discard SI or SN
1071 */
1072 m_sdusBuffer.pop_front();
1073
1074 if (!m_sdusBuffer.empty())
1075 {
1076 /**
1077 * Deliver zero, one or multiple PDUs
1078 */
1079 while (m_sdusBuffer.size() > 1)
1080 {
1082 m_sdusBuffer.pop_front();
1083 }
1084
1085 /**
1086 * Keep S0
1087 */
1088 m_keepS0 = m_sdusBuffer.front();
1089 m_sdusBuffer.pop_front();
1090 }
1091 break;
1092
1093 default:
1094 /**
1095 * ERROR: Transition not possible
1096 */
1098 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1099 break;
1100 }
1101 break;
1102
1103 default:
1105 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1106 break;
1107 }
1108 }
1109}
1110
1111void
1113{
1114 NS_LOG_LOGIC("Reassemble Outside Window");
1115
1116 auto it = m_rxBuffer.begin();
1117
1118 while ((it != m_rxBuffer.end()) && !IsInsideReorderingWindow(SequenceNumber10(it->first)))
1119 {
1120 NS_LOG_LOGIC("SN = " << it->first);
1121
1122 // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1123 ReassembleAndDeliver(it->second);
1124
1125 auto it_tmp = it;
1126 ++it;
1127 m_rxBuffer.erase(it_tmp);
1128 }
1129
1130 if (it != m_rxBuffer.end())
1131 {
1132 NS_LOG_LOGIC("(SN = " << it->first << ") is inside the reordering window");
1133 }
1134}
1135
1136void
1138{
1139 NS_LOG_LOGIC("Reassemble SN between " << lowSeqNumber << " and " << highSeqNumber);
1140
1141 SequenceNumber10 reassembleSn = lowSeqNumber;
1142 NS_LOG_LOGIC("reassembleSN = " << reassembleSn);
1143 NS_LOG_LOGIC("highSeqNumber = " << highSeqNumber);
1144 while (reassembleSn < highSeqNumber)
1145 {
1146 NS_LOG_LOGIC("reassembleSn < highSeqNumber");
1147 auto it = m_rxBuffer.find(reassembleSn.GetValue());
1148 NS_LOG_LOGIC("it->first = " << it->first);
1149 NS_LOG_LOGIC("it->second = " << it->second);
1150 if (it != m_rxBuffer.end())
1151 {
1152 NS_LOG_LOGIC("SN = " << it->first);
1153
1154 // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1155 ReassembleAndDeliver(it->second);
1156
1157 m_rxBuffer.erase(it);
1158 }
1159
1160 reassembleSn++;
1161 }
1162}
1163
1164void
1166{
1167 Time holDelay(0);
1168 uint32_t queueSize = 0;
1169
1170 if (!m_txBuffer.empty())
1171 {
1172 holDelay = Simulator::Now() - m_txBuffer.front().m_waitingSince;
1173
1174 queueSize =
1175 m_txBufferSize + 2 * m_txBuffer.size(); // Data in tx queue + estimated headers size
1176 }
1177
1179 r.rnti = m_rnti;
1180 r.lcid = m_lcid;
1182 r.txQueueHolDelay = holDelay.GetMilliSeconds();
1183 r.retxQueueSize = 0;
1184 r.retxQueueHolDelay = 0;
1185 r.statusPduSize = 0;
1186
1187 NS_LOG_LOGIC("Send ReportBufferStatus = " << r.txQueueSize << ", " << r.txQueueHolDelay);
1189}
1190
1191void
1193{
1195 NS_LOG_LOGIC("Reordering timer has expired");
1196
1197 // 5.1.2.2.4 Actions when t-Reordering expires
1198 // When t-Reordering expires, the receiving UM RLC entity shall:
1199 // - update VR(UR) to the SN of the first UMD PDU with SN >= VR(UX) that has not been received;
1200 // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when
1201 // doing so
1202 // and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not
1203 // delivered before;
1204 // - if VR(UH) > VR(UR):
1205 // - start t-Reordering;
1206 // - set VR(UX) to VR(UH).
1207
1208 SequenceNumber10 newVrUr = m_vrUx;
1209
1210 while (m_rxBuffer.find(newVrUr.GetValue()) != m_rxBuffer.end())
1211 {
1212 newVrUr++;
1213 }
1214 SequenceNumber10 oldVrUr = m_vrUr;
1215 m_vrUr = newVrUr;
1216 NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
1217
1218 ReassembleSnInterval(oldVrUr, m_vrUr);
1219
1220 if (m_vrUh > m_vrUr)
1221 {
1222 NS_LOG_LOGIC("Start reordering timer");
1225 m_vrUx = m_vrUh;
1226 NS_LOG_LOGIC("New VR(UX) = " << m_vrUx);
1227 }
1228}
1229
1230void
1232{
1233 NS_LOG_LOGIC("RBS Timer expires");
1234
1235 if (!m_txBuffer.empty())
1236 {
1239 }
1240}
1241
1242} // namespace ns3
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
virtual void TransmitPdu(TransmitPduParameters params)=0
send an RLC PDU to the MAC for transmission.
virtual void ReportBufferStatus(ReportBufferStatusParameters params)=0
Report the RLC buffer status to the MAC.
The packet header for the Radio Link Control (RLC) protocol packets.
uint32_t GetSerializedSize() const override
void PushExtensionBit(uint8_t extensionBit)
Push extension bit.
SequenceNumber10 GetSequenceNumber() const
Get sequence number.
void SetSequenceNumber(SequenceNumber10 sequenceNumber)
Set sequence number.
void SetFramingInfo(uint8_t framingInfo)
Set framing info.
uint8_t PopExtensionBit()
Pop extension bit.
uint16_t PopLengthIndicator()
Pop length indicator.
uint8_t GetFramingInfo() const
Get framing info.
void PushLengthIndicator(uint16_t lengthIndicator)
Push length indicator.
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE,...
Definition lte-rlc.h:38
LteRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition lte-rlc.h:137
uint8_t m_lcid
LCID.
Definition lte-rlc.h:162
TracedCallback< Ptr< const Packet > > m_txDropTrace
The trace source fired when the RLC drops a packet before transmission.
Definition lte-rlc.h:178
uint16_t m_rnti
RNTI.
Definition lte-rlc.h:161
TracedCallback< uint16_t, uint8_t, uint32_t, uint64_t > m_rxPdu
Used to inform of a PDU reception from the MAC SAP user.
Definition lte-rlc.h:173
void DoDispose() override
Destructor implementation.
Definition lte-rlc.cc:115
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition lte-rlc.h:159
uint16_t m_packetDelayBudgetMs
the packet delay budget in ms of the corresponding logical channel
Definition lte-rlc.h:163
TracedCallback< uint16_t, uint8_t, uint32_t > m_txPdu
Used to inform of a PDU delivery to the MAC SAP provider.
Definition lte-rlc.h:169
virtual void ReceivePdcpPdu(Ptr< Packet > p)=0
Called by the RLC entity to notify the PDCP entity of the reception of a new PDCP PDU.
This class implements a tag that carries the status of a RLC SDU for the fragmentation process Status...
uint8_t GetStatus() const
Get status function.
void SetStatus(uint8_t status)
Set status function.
LTE RLC Unacknowledged Mode (UM), see 3GPP TS 36.322.
Definition lte-rlc-um.h:27
SequenceNumber10 m_vrUr
VR(UR)
Definition lte-rlc-um.h:125
Ptr< Packet > m_keepS0
keep S0
Definition lte-rlc-um.h:155
void ReassembleAndDeliver(Ptr< Packet > packet)
Reassemble and deliver function.
void DoReportBufferStatus()
Report buffer status.
uint32_t m_txBufferSize
transmit buffer size
Definition lte-rlc-um.h:90
static TypeId GetTypeId()
Get the type ID.
Definition lte-rlc-um.cc:45
void ReassembleOutsideWindow()
Reassemble outside window.
void DoDispose() override
Destructor implementation.
Definition lte-rlc-um.cc:80
void ExpireReorderingTimer()
Expire reordering timer.
Time m_reorderingTimerValue
Timers.
Definition lte-rlc-um.h:137
~LteRlcUm() override
Definition lte-rlc-um.cc:39
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition lte-rlc-um.h:160
ReassemblingState_t m_reassemblingState
reassembling state
Definition lte-rlc-um.h:154
void ReassembleSnInterval(SequenceNumber10 lowSeqNumber, SequenceNumber10 highSeqNumber)
Reassemble SN interval function.
void ExpireRbsTimer()
Expire RBS timer.
EventId m_rbsTimer
RBS timer.
Definition lte-rlc-um.h:139
void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams) override
MAC SAP.
SequenceNumber10 m_vrUx
VR(UX)
Definition lte-rlc-um.h:126
uint16_t m_windowSize
Constants.
Definition lte-rlc-um.h:132
std::map< uint16_t, Ptr< Packet > > m_rxBuffer
Reception buffer.
Definition lte-rlc-um.h:115
uint32_t m_discardTimerMs
the discard timer value in milliseconds
Definition lte-rlc-um.h:142
void DoNotifyHarqDeliveryFailure() override
Notify HARQ delivery failure.
SequenceNumber10 m_vrUh
VR(UH)
Definition lte-rlc-um.h:127
void DoTransmitPdcpPdu(Ptr< Packet > p) override
RLC SAP.
Definition lte-rlc-um.cc:94
void DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams) override
Receive PDU function.
uint32_t m_maxTxBufferSize
maximum transmit buffer status
Definition lte-rlc-um.h:89
std::deque< TxPdu > m_txBuffer
Transmission buffer.
Definition lte-rlc-um.h:114
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet.
Definition lte-rlc-um.h:118
EventId m_reorderingTimer
reordering timer
Definition lte-rlc-um.h:138
bool IsInsideReorderingWindow(SequenceNumber10 seqNumber)
Is inside reordering window function.
SequenceNumber10 m_sequenceNumber
State variables.
Definition lte-rlc-um.h:123
bool m_enablePdcpDiscarding
whether to use the PDCP discarding (perform discarding at the moment of passing the PDCP SDU to RLC)
Definition lte-rlc-um.h:140
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition packet.cc:343
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition packet.h:850
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition packet.cc:932
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition packet.cc:294
Smart pointer class similar to boost::intrusive_ptr.
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition lte-rlc-tag.h:25
Time GetSenderTimestamp() const
Get the instant when the RLC delivers the PDU to the MAC SAP provider.
Definition lte-rlc-tag.h:53
SequenceNumber10 class.
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
void SetModulusBase(SequenceNumber10 modulusBase)
Set modulus base.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:397
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
Parameters for LteMacSapProvider::ReportBufferStatus.
Definition lte-mac-sap.h:58
uint32_t txQueueSize
the current size of the RLC transmission queue
Definition lte-mac-sap.h:61
uint16_t retxQueueHolDelay
the Head Of Line delay of the retransmission queue
Definition lte-mac-sap.h:64
uint16_t txQueueHolDelay
the Head Of Line delay of the transmission queue
Definition lte-mac-sap.h:62
uint32_t retxQueueSize
the current size of the RLC retransmission queue in bytes
Definition lte-mac-sap.h:63
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition lte-mac-sap.h:60
uint16_t rnti
the C-RNTI identifying the UE
Definition lte-mac-sap.h:59
uint16_t statusPduSize
the current size of the pending STATUS RLC PDU message in bytes
Definition lte-mac-sap.h:66
Parameters for LteMacSapProvider::TransmitPdu.
Definition lte-mac-sap.h:34
Parameters for LteMacSapUser::ReceivePdu.
Ptr< Packet > p
the RLC PDU to be received
Parameters for LteMacSapUser::NotifyTxOpportunity.
Definition lte-mac-sap.h:94
uint32_t bytes
the number of bytes to transmit
uint8_t componentCarrierId
the component carrier id
uint8_t layer
the layer of transmission (MIMO)
Store an incoming (from layer above us) PDU, waiting to transmit it.
Definition lte-rlc-um.h:96
std::ofstream queueSize