A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
lte-enb-mac.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Marco Miozzo <marco.miozzo@cttc.es>
19  * Nicola Baldo <nbaldo@cttc.es>
20  */
21 
22 
23 #include <ns3/log.h>
24 #include <ns3/pointer.h>
25 #include <ns3/packet.h>
26 
27 #include "lte-amc.h"
28 #include "lte-control-messages.h"
29 #include "lte-enb-net-device.h"
30 #include "lte-ue-net-device.h"
31 
32 #include <ns3/lte-enb-mac.h>
33 #include <ns3/lte-radio-bearer-tag.h>
34 #include <ns3/lte-ue-phy.h>
35 
36 #include "ns3/lte-mac-sap.h"
37 #include <ns3/lte-common.h>
38 
39 
40 NS_LOG_COMPONENT_DEFINE ("LteEnbMac");
41 
42 namespace ns3 {
43 
44 
45 NS_OBJECT_ENSURE_REGISTERED (LteEnbMac);
46 
47 
48 
49 // //////////////////////////////////////
50 // member SAP forwarders
51 // //////////////////////////////////////
52 
53 
55 {
56 public:
58 
59  // inherited from LteEnbCmacSapProvider
60  virtual void ConfigureMac (uint8_t ulBandwidth, uint8_t dlBandwidth);
61  virtual void AddUe (uint16_t rnti);
62  virtual void AddLc (LcInfo lcinfo, LteMacSapUser* msu);
63  virtual void ReconfigureLc (LcInfo lcinfo);
64  virtual void ReleaseLc (uint16_t rnti, uint8_t lcid);
65  virtual void UeUpdateConfigurationReq (LteUeConfig_t params);
66 
67 private:
69 };
70 
71 
73  : m_mac (mac)
74 {
75 }
76 
77 void
78 EnbMacMemberLteEnbCmacSapProvider::ConfigureMac (uint8_t ulBandwidth, uint8_t dlBandwidth)
79 {
80  m_mac->DoConfigureMac (ulBandwidth, dlBandwidth);
81 }
82 
83 void
85 {
86  m_mac->DoAddUe (rnti);
87 }
88 
89 void
91 {
92  m_mac->DoAddLc (lcinfo, msu);
93 }
94 
95 void
97 {
98  m_mac->DoReconfigureLc (lcinfo);
99 }
100 
101 void
102 EnbMacMemberLteEnbCmacSapProvider::ReleaseLc (uint16_t rnti, uint8_t lcid)
103 {
104  m_mac->DoReleaseLc (rnti, lcid);
105 }
106 
107 void
109 {
111 }
112 
113 
114 
116 {
117 public:
119 
120 
121  virtual void SchedDlConfigInd (const struct SchedDlConfigIndParameters& params);
122  virtual void SchedUlConfigInd (const struct SchedUlConfigIndParameters& params);
123 private:
125 };
126 
127 
129  : m_mac (mac)
130 {
131 }
132 
133 
134 void
136 {
137  m_mac->DoSchedDlConfigInd (params);
138 }
139 
140 
141 
142 void
144 {
145  m_mac->DoSchedUlConfigInd (params);
146 }
147 
148 
149 
151 {
152 public:
154 
155  virtual void CschedCellConfigCnf (const struct CschedCellConfigCnfParameters& params);
156  virtual void CschedUeConfigCnf (const struct CschedUeConfigCnfParameters& params);
157  virtual void CschedLcConfigCnf (const struct CschedLcConfigCnfParameters& params);
158  virtual void CschedLcReleaseCnf (const struct CschedLcReleaseCnfParameters& params);
159  virtual void CschedUeReleaseCnf (const struct CschedUeReleaseCnfParameters& params);
160  virtual void CschedUeConfigUpdateInd (const struct CschedUeConfigUpdateIndParameters& params);
161  virtual void CschedCellConfigUpdateInd (const struct CschedCellConfigUpdateIndParameters& params);
162 
163 private:
165 };
166 
167 
169  : m_mac (mac)
170 {
171 }
172 
173 void
175 {
176  m_mac->DoCschedCellConfigCnf (params);
177 }
178 
179 void
181 {
182  m_mac->DoCschedUeConfigCnf (params);
183 }
184 
185 void
187 {
188  m_mac->DoCschedLcConfigCnf (params);
189 }
190 
191 void
193 {
194  m_mac->DoCschedLcReleaseCnf (params);
195 }
196 
197 void
199 {
200  m_mac->DoCschedUeReleaseCnf (params);
201 }
202 
203 void
205 {
207 }
208 
209 void
211 {
213 }
214 
215 
216 
217 // ---------- PHY-SAP
218 
219 
221 {
222 public:
224 
225  // inherited from LteEnbPhySapUser
226  virtual void ReceivePhyPdu (Ptr<Packet> p);
227  virtual void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
230 
231 private:
233 };
234 
236 {
237 }
238 
239 
240 void
242 {
243  m_mac->DoReceivePhyPdu (p);
244 }
245 
246 void
247 EnbMacMemberLteEnbPhySapUser::SubframeIndication (uint32_t frameNo, uint32_t subframeNo)
248 {
249  m_mac->DoSubframeIndication (frameNo, subframeNo);
250 }
251 
252 void
254 {
256 }
257 
258 void
260 {
261  m_mac->DoUlCqiReport (ulcqi);
262 }
263 
264 
265 // //////////////////////////////////////
266 // generic LteEnbMac methods
267 // //////////////////////////////////////
268 
269 
270 TypeId
272 {
273  static TypeId tid = TypeId ("ns3::LteEnbMac")
274  .SetParent<Object> ()
275  .AddConstructor<LteEnbMac> ()
276  .AddTraceSource ("DlScheduling",
277  "Information regarding DL scheduling.",
279  .AddTraceSource ("UlScheduling",
280  "Information regarding UL scheduling.",
282  ;
283 
284  return tid;
285 }
286 
287 
289 {
290  NS_LOG_FUNCTION (this);
296 }
297 
298 
300 {
301  NS_LOG_FUNCTION (this);
302 }
303 
304 void
306 {
307  NS_LOG_FUNCTION (this);
308  delete m_macSapProvider;
309  delete m_cmacSapProvider;
310  delete m_schedSapUser;
311  delete m_cschedSapUser;
312  delete m_enbPhySapUser;
313 }
314 
315 
316 void
318 {
319  m_schedSapProvider = s;
320 }
321 
324 {
325  return m_schedSapUser;
326 }
327 
328 void
330 {
332 }
333 
336 {
337  return m_cschedSapUser;
338 }
339 
340 
341 
342 void
344 {
345  m_macSapUser = s;
346 }
347 
350 {
351  return m_macSapProvider;
352 }
353 
354 void
356 {
357  m_cmacSapUser = s;
358 }
359 
362 {
363  return m_cmacSapProvider;
364 }
365 
366 void
368 {
370 }
371 
372 
375 {
376  return m_enbPhySapUser;
377 }
378 
379 
380 
381 void
382 LteEnbMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
383 {
384  NS_LOG_FUNCTION (this << " EnbMac - frame " << frameNo << " subframe " << subframeNo);
385 
386  // Store current frame / subframe number
387  m_frameNo = frameNo;
388  m_subframeNo = subframeNo;
389 
390 
391  // --- DOWNLINK ---
392  // Send Dl-CQI info to the scheduler
393  if (m_dlCqiReceived.size () > 0)
394  {
396  dlcqiInfoReq.m_sfnSf = ((0x3FF & frameNo) << 4) | (0xF & subframeNo);
397 
398  int cqiNum = m_dlCqiReceived.size ();
399  if (cqiNum > MAX_CQI_LIST)
400  {
401  cqiNum = MAX_CQI_LIST;
402  }
403  dlcqiInfoReq.m_cqiList.insert (dlcqiInfoReq.m_cqiList.begin (), m_dlCqiReceived.begin (), m_dlCqiReceived.end ());
404  m_dlCqiReceived.erase (m_dlCqiReceived.begin (), m_dlCqiReceived.end ());
405  m_schedSapProvider->SchedDlCqiInfoReq (dlcqiInfoReq);
406  }
407 
408 
409  // Get downlink transmission opportunities
410  uint32_t dlSchedFrameNo = m_frameNo;
411  uint32_t dlSchedSubframeNo = m_subframeNo;
412  // NS_LOG_DEBUG (this << " sfn " << frameNo << " sbfn " << subframeNo);
413  if (dlSchedSubframeNo + m_macChTtiDelay > 10)
414  {
415  dlSchedFrameNo++;
416  dlSchedSubframeNo = (dlSchedSubframeNo + m_macChTtiDelay) % 10;
417  }
418  else
419  {
420  dlSchedSubframeNo = dlSchedSubframeNo + m_macChTtiDelay;
421  }
423  params.m_sfnSf = ((0x3FF & dlSchedFrameNo) << 4) | (0xF & dlSchedSubframeNo);
425 
426 
427  // --- UPLINK ---
428  // Send UL-CQI info to the scheduler
429  std::vector <FfMacSchedSapProvider::SchedUlCqiInfoReqParameters>::iterator itCqi;
430  for (uint16_t i = 0; i < m_ulCqiReceived.size (); i++)
431  {
432  if (subframeNo>1)
433  {
434  m_ulCqiReceived.at (i).m_sfnSf = ((0x3FF & frameNo) << 4) | (0xF & subframeNo);
435  }
436  else
437  {
438  m_ulCqiReceived.at (i).m_sfnSf = ((0x3FF & (frameNo-1)) << 4) | (0xF & 10);
439  }
441  }
442  m_ulCqiReceived.clear ();
443 
444  // Send BSR reports to the scheduler
445  if (m_ulCeReceived.size () > 0)
446  {
448  ulMacReq.m_sfnSf = ((0x3FF & frameNo) << 4) | (0xF & subframeNo);
449  ulMacReq.m_macCeList.insert (ulMacReq.m_macCeList.begin (), m_ulCeReceived.begin (), m_ulCeReceived.end ());
450  m_ulCeReceived.erase (m_ulCeReceived.begin (), m_ulCeReceived.end ());
452  }
453 
454 
455  // Get uplink transmission opportunities
456  uint32_t ulSchedFrameNo = m_frameNo;
457  uint32_t ulSchedSubframeNo = m_subframeNo;
458  // NS_LOG_DEBUG (this << " sfn " << frameNo << " sbfn " << subframeNo);
459  if (ulSchedSubframeNo + (m_macChTtiDelay+UL_PUSCH_TTIS_DELAY) > 10)
460  {
461  ulSchedFrameNo++;
462  ulSchedSubframeNo = (ulSchedSubframeNo + (m_macChTtiDelay+UL_PUSCH_TTIS_DELAY)) % 10;
463  }
464  else
465  {
466  ulSchedSubframeNo = ulSchedSubframeNo + (m_macChTtiDelay+UL_PUSCH_TTIS_DELAY);
467  }
469  ulparams.m_sfnSf = ((0x3FF & ulSchedFrameNo) << 4) | (0xF & ulSchedSubframeNo);
470 
471  std::map <uint16_t,UlInfoListElement_s>::iterator it;
472  for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
473  {
474  ulparams.m_ulInfoList.push_back ((*it).second);
475  }
477 
478 
479 
480 
481  // reset UL info
482  for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
483  {
484  for (uint16_t i = 0; i < (*it).second.m_ulReception.size (); i++)
485  {
486  (*it).second.m_ulReception.at (i) = 0;
487  }
488  (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
489  (*it).second.m_tpc = 0;
490  }
491 }
492 
493 void
495 {
496  NS_LOG_FUNCTION (this << msg);
498  {
499  Ptr<DlCqiLteControlMessage> dlcqi = DynamicCast<DlCqiLteControlMessage> (msg);
501  }
502  else if (msg->GetMessageType () == LteControlMessage::BSR)
503  {
504  Ptr<BsrLteControlMessage> bsr = DynamicCast<BsrLteControlMessage> (msg);
505  ReceiveBsrMessage (bsr->GetBsr ());
506  }
507  else
508  {
509  NS_LOG_LOGIC (this << " LteControlMessage not recognized");
510  }
511 }
512 
513 
514 void
516 {
517  if (ulcqi.m_ulCqi.m_type == UlCqi_s::PUSCH)
518  {
519  NS_LOG_DEBUG (this << " eNB rxed an PUSCH UL-CQI");
520  }
521  // TODO store UL-CQI to send them to scheduler
522  m_ulCqiReceived.push_back (ulcqi);
523 }
524 
525 
526 void
528 {
529  NS_LOG_FUNCTION (this << msg);
530 
531  CqiListElement_s dlcqi = msg->GetDlCqi ();
532  NS_LOG_LOGIC (this << "Enb Received DL-CQI rnti" << dlcqi.m_rnti);
533  m_dlCqiReceived.push_back (dlcqi);
534 
535 }
536 
537 
538 void
540 {
541  NS_LOG_FUNCTION (this);
542 
543  m_ulCeReceived.push_back (bsr);
544 }
545 
546 
547 
548 void
550 {
551  NS_LOG_FUNCTION (this);
552  LteRadioBearerTag tag;
553  p->RemovePacketTag (tag);
554 
555  // store info of the packet received
556 
557  std::map <uint16_t,UlInfoListElement_s>::iterator it;
558 // u_int rnti = tag.GetRnti ();
559 // u_int lcid = tag.GetLcid ();
560  it = m_ulInfoListElements.find (tag.GetRnti ());
561  if (it == m_ulInfoListElements.end ())
562  {
563  // new RNTI
564  UlInfoListElement_s ulinfonew;
565  ulinfonew.m_rnti = tag.GetRnti ();
566  // always allocate full size of ulReception vector, initializing all elements to 0
567  ulinfonew.m_ulReception.assign (MAX_LC_LIST+1, 0);
568  // set the element for the current LCID
569  ulinfonew.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
571  ulinfonew.m_tpc = 0; // Tx power control not implemented at this stage
572  m_ulInfoListElements.insert (std::pair<uint16_t, UlInfoListElement_s > (tag.GetRnti (), ulinfonew));
573 
574  }
575  else
576  {
577  // existing RNTI: we just set the value for the current
578  // LCID. Note that the corresponding element had already been
579  // allocated previously.
580  NS_ASSERT_MSG ((*it).second.m_ulReception.at (tag.GetLcid ()) == 0, "would overwrite previously written ulReception element");
581  (*it).second.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
582  (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
583  }
584 
585 
586 
587  // forward the packet to the correspondent RLC
588  LteFlowId_t flow ( tag.GetRnti (), tag.GetLcid () );
589  std::map <LteFlowId_t, LteMacSapUser* >::iterator it2;
590  it2 = m_rlcAttached.find (flow);
591  NS_ASSERT_MSG (it2 != m_rlcAttached.end (), "UE not attached rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
592  (*it2).second->ReceivePdu (p);
593 
594 }
595 
596 
597 
598 
599 // ////////////////////////////////////////////
600 // CMAC SAP
601 // ////////////////////////////////////////////
602 
603 void
604 LteEnbMac::DoConfigureMac (uint8_t ulBandwidth, uint8_t dlBandwidth)
605 {
606  NS_LOG_FUNCTION (this << " ulBandwidth=" << (uint16_t) ulBandwidth << " dlBandwidth=" << (uint16_t) dlBandwidth);
608  // Configure the subset of parameters used by FfMacScheduler
609  params.m_ulBandwidth = ulBandwidth;
610  params.m_dlBandwidth = dlBandwidth;
612  // ...more parameters can be configured
614 }
615 
616 
617 void
618 LteEnbMac::DoAddUe (uint16_t rnti)
619 {
620  NS_LOG_FUNCTION (this << " rnti=" << rnti);
622  params.m_rnti = rnti;
623  params.m_transmissionMode = 0; // set to default value (SISO) for avoiding random initialization (valgrind error)
625 }
626 
627 
628 void
630 {
631  NS_LOG_FUNCTION (this);
632  std::map <LteFlowId_t, LteMacSapUser* >::iterator it;
633 
634  LteFlowId_t flow (lcinfo.rnti, lcinfo.lcId);
635 
636  it = m_rlcAttached.find (flow);
637  if (it == m_rlcAttached.end ())
638  {
639  m_rlcAttached.insert (std::pair<LteFlowId_t, LteMacSapUser* > (flow, msu));
640  }
641  else
642  {
643  NS_LOG_ERROR ("LC already exists");
644  }
645 
646 
648  params.m_rnti = lcinfo.rnti;
649  params.m_reconfigureFlag = false;
650 
652  lccle.m_logicalChannelIdentity = lcinfo.lcId;
653  lccle.m_logicalChannelGroup = lcinfo.lcGroup;
656  lccle.m_qci = lcinfo.qci;
657  lccle.m_eRabMaximulBitrateUl = lcinfo.mbrUl;
658  lccle.m_eRabMaximulBitrateDl = lcinfo.mbrDl;
659  lccle.m_eRabGuaranteedBitrateUl = lcinfo.gbrUl;
660  lccle.m_eRabGuaranteedBitrateDl = lcinfo.gbrDl;
661  params.m_logicalChannelConfigList.push_back (lccle);
662 
664 }
665 
666 void
668 {
669  NS_FATAL_ERROR ("not implemented");
670 }
671 
672 void
673 LteEnbMac::DoReleaseLc (uint16_t rnti, uint8_t lcid)
674 {
675  NS_FATAL_ERROR ("not implemented");
676 }
677 
678 
679 
680 // ////////////////////////////////////////////
681 // MAC SAP
682 // ////////////////////////////////////////////
683 
684 
685 void
687 {
688  NS_LOG_FUNCTION (this);
689  LteRadioBearerTag tag (params.rnti, params.lcid, params.layer);
690  params.pdu->AddPacketTag (tag);
691 // Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
692 // pb->AddPacket (params.pdu);
693 
695 }
696 
697 void
699 {
700  NS_LOG_FUNCTION (this);
702  req.m_rnti = params.rnti;
703  req.m_logicalChannelIdentity = params.lcid;
708  req.m_rlcStatusPduSize = params.statusPduSize;
710 }
711 
712 
713 
714 // ////////////////////////////////////////////
715 // SCHED SAP
716 // ////////////////////////////////////////////
717 
718 
719 
720 void
722 {
723  NS_LOG_FUNCTION (this);
724  // Create DL PHY PDU
725  Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
726  std::map <LteFlowId_t, LteMacSapUser* >::iterator it;
727 
728  for (unsigned int i = 0; i < ind.m_buildDataList.size (); i++)
729  {
730  for (unsigned int j = 0; j < ind.m_buildDataList.at (i).m_rlcPduList.size (); j++)
731  {
732  for (uint16_t k = 0; k < ind.m_buildDataList.at (i).m_rlcPduList.at (j).size (); k++)
733  {
734  LteFlowId_t flow (ind.m_buildDataList.at (i).m_rnti,
735  ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_logicalChannelIdentity);
736  it = m_rlcAttached.find (flow);
737  NS_ASSERT_MSG (it != m_rlcAttached.end (), "rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
738  NS_LOG_DEBUG (this << " rnti= " << flow.m_rnti << " lcid= " << (uint32_t) flow.m_lcId << " layer= " << k);
739  (*it).second->NotifyTxOpportunity (ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_size, k);
740  }
741  }
742  // send the relative DCI
743  Ptr<DlDciLteControlMessage> msg = Create<DlDciLteControlMessage> ();
744  msg->SetDci (ind.m_buildDataList.at (i).m_dci);
746  }
747 
748  // Fire the trace with the DL information
749  for ( uint32_t i = 0; i < ind.m_buildDataList.size (); i++ )
750  {
751  // Only one TB used
752  if (ind.m_buildDataList.at (i).m_dci.m_tbsSize.size () == 1)
753  {
754  m_dlScheduling (m_frameNo, m_subframeNo, ind.m_buildDataList.at (i).m_dci.m_rnti,
755  ind.m_buildDataList.at (i).m_dci.m_mcs.at (0),
756  ind.m_buildDataList.at (i).m_dci.m_tbsSize.at (0),
757  0, 0
758  );
759 
760  }
761  // Two TBs used
762  else if (ind.m_buildDataList.at (i).m_dci.m_tbsSize.size () == 2)
763  {
764  m_dlScheduling (m_frameNo, m_subframeNo, ind.m_buildDataList.at (i).m_dci.m_rnti,
765  ind.m_buildDataList.at (i).m_dci.m_mcs.at (0),
766  ind.m_buildDataList.at (i).m_dci.m_tbsSize.at (0),
767  ind.m_buildDataList.at (i).m_dci.m_mcs.at (1),
768  ind.m_buildDataList.at (i).m_dci.m_tbsSize.at (1)
769  );
770  }
771  else
772  {
773  NS_FATAL_ERROR ("Found element with more than two transport blocks");
774  }
775  }
776 }
777 
778 
779 void
781 {
782  NS_LOG_FUNCTION (this);
783 
784  for (unsigned int i = 0; i < ind.m_dciList.size (); i++)
785  {
786  // send the correspondent ul dci
787  Ptr<UlDciLteControlMessage> msg = Create<UlDciLteControlMessage> ();
788  msg->SetDci (ind.m_dciList.at (i));
790  }
791 
792  // Fire the trace with the UL information
793  for ( uint32_t i = 0; i < ind.m_dciList.size (); i++ )
794  {
795  m_ulScheduling (m_frameNo, m_subframeNo, ind.m_dciList.at (i).m_rnti,
796  ind.m_dciList.at (i).m_mcs, ind.m_dciList.at (i).m_tbSize);
797  }
798 
799 
800 
801 }
802 
803 
804 
805 
806 // ////////////////////////////////////////////
807 // CSCHED SAP
808 // ////////////////////////////////////////////
809 
810 
811 void
813 {
814  NS_LOG_FUNCTION (this);
815 }
816 
817 void
819 {
820  NS_LOG_FUNCTION (this);
821 }
822 
823 void
825 {
826  NS_LOG_FUNCTION (this);
827  // Call the CSCHED primitive
828  // m_cschedSap->LcConfigCompleted();
829 }
830 
831 void
833 {
834  NS_LOG_FUNCTION (this);
835 }
836 
837 void
839 {
840  NS_LOG_FUNCTION (this);
841 }
842 
843 void
845 {
846  NS_LOG_FUNCTION (this);
847  // propagates to RRC
848  LteUeConfig_t ueConfigUpdate;
849  ueConfigUpdate.m_rnti = params.m_rnti;
850  ueConfigUpdate.m_transmissionMode = params.m_transmissionMode;
851  m_cmacSapUser->RrcConfigurationUpdateInd (ueConfigUpdate);
852 }
853 
854 void
856 {
857  NS_LOG_FUNCTION (this);
858  // propagates to PHY layer
861  // propagates to scheduler
863  req.m_rnti = params.m_rnti;
866 }
867 
868 void
870 {
871  NS_LOG_FUNCTION (this);
872 }
873 
874 
875 } // namespace ns3