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
105
106 if (!m_txBuffer.empty())
107 {
109 (Simulator::Now() - m_txBuffer.begin()->m_waitingSince).GetMilliSeconds();
110 }
111 NS_LOG_DEBUG("head of line delay in MS:" << headOfLineDelayInMs);
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>();
169
170 // Build Data field
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)
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
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
222 firstSegment->RemovePacketTag(oldTag);
223 newSegment->RemovePacketTag(newTag);
224 if (oldTag.GetStatus() == LteRlcSduStatusTag::FULL_SDU)
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
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
254 if (newTag.GetStatus() == LteRlcSduStatusTag::FIRST_SEGMENT)
255 {
257 }
258 else if (newTag.GetStatus() == LteRlcSduStatusTag::MIDDLE_SEGMENT)
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
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
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;
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
355 rlcHeader.SetSequenceNumber(m_sequenceNumber++);
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);
366 if ((tag.GetStatus() == LteRlcSduStatusTag::FULL_SDU) ||
367 (tag.GetStatus() == LteRlcSduStatusTag::FIRST_SEGMENT))
368 {
370 }
371 else
372 {
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--;
395 if ((tag.GetStatus() == LteRlcSduStatusTag::FULL_SDU) ||
396 (tag.GetStatus() == LteRlcSduStatusTag::LAST_SEGMENT))
397 {
399 }
400 else
401 {
403 }
404
405 rlcHeader.SetFramingInfo(framingInfo);
406
407 NS_LOG_LOGIC("RLC header: " << rlcHeader);
408 packet->AddHeader(rlcHeader);
409
410 // Sender timestamp
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
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
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
493 seqNumber.SetModulusBase(m_vrUh - m_windowSize);
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
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;
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
616 seqNumber.SetModulusBase(m_vrUh - m_windowSize);
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{
634 packet->RemoveHeader(rlcHeader);
635 uint8_t framingInfo = rlcHeader.GetFramingInfo();
636 SequenceNumber10 currSeqNumber = rlcHeader.GetSequenceNumber();
637 bool expectedSnLost;
638
640 {
641 expectedSnLost = true;
642 NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
643 << ". Current SN = " << currSeqNumber);
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 */
814 m_keepS0->AddAtEnd(m_sdusBuffer.front());
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 {
836 m_keepS0->AddAtEnd(m_sdusBuffer.front());
837 m_sdusBuffer.pop_front();
838 }
839 else // m_sdusBuffer.size () > 1
840 {
841 /**
842 * Deliver (Kept)S0 + SN
843 */
844 m_keepS0->AddAtEnd(m_sdusBuffer.front());
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
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
1209
1210 while (m_rxBuffer.find(newVrUr.GetValue()) != m_rxBuffer.end())
1211 {
1212 newVrUr++;
1213 }
1215 m_vrUr = newVrUr;
1216 NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
1217
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
AttributeValue implementation for Boolean.
Definition boolean.h:26
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.
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...
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
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:66
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition lte-rlc-tag.h:25
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
AttributeValue implementation for Time.
Definition nstime.h:1431
a unique identifier for an interface.
Definition type-id.h:49
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
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
#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:1356
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1432
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
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.
Parameters for LteMacSapUser::NotifyTxOpportunity.
Definition lte-mac-sap.h:94
Store an incoming (from layer above us) PDU, waiting to transmit it.
Definition lte-rlc-um.h:96
std::ofstream queueSize