diff options
author | Jordan Augé <jordan.auge+fdio@email.com> | 2017-02-24 14:58:01 +0100 |
---|---|---|
committer | Jordan Augé <jordan.auge+fdio@cisco.com> | 2017-02-24 18:36:29 +0000 |
commit | 85a341d645b57b7cd88a26ed2ea0a314704240ea (patch) | |
tree | bdda2b35003aae20103a796f86daced160b8a730 /emu-radio/lte-emulator/extensions | |
parent | 9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff) |
Initial commit: vICN
Change-Id: I7ce66c4e84a6a1921c63442f858b49e083adc7a7
Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Diffstat (limited to 'emu-radio/lte-emulator/extensions')
7 files changed, 2932 insertions, 0 deletions
diff --git a/emu-radio/lte-emulator/extensions/README.md b/emu-radio/lte-emulator/extensions/README.md new file mode 100644 index 00000000..7663ba08 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/README.md @@ -0,0 +1,18 @@ +The extensions are basically either some rewriting or some inheriting +of existing classes in ns3 such that the emulation of lte channel in ns3 +can be enabled. + +some of the original lte helper and lte network device implementation +does not support the integration with tap devices defined in ns3. So some +critical extensions or modifications of those imlementations must be done +in order to enable lte channel emulation in ns3. + +To avoid making changes directly on the ns3 codebase, which may lead to needs +of recompiling ns3 library and other packages depending on ns3, here all the +modifications or extensions are implemented by rewriting or inheriting of existing +ns3 class. These extensions shall be linked with lte emulator program and +ns3 library such that those critical modifications can take into play when running +lte emulator program. + +Since all those modifications are for purpose of enabling integration lte network +with tap device in ns3, all the extension files/classes have "tap" in their namings. diff --git a/emu-radio/lte-emulator/extensions/lte-tap-helper.cc b/emu-radio/lte-emulator/extensions/lte-tap-helper.cc new file mode 100644 index 00000000..15d35b3a --- /dev/null +++ b/emu-radio/lte-emulator/extensions/lte-tap-helper.cc @@ -0,0 +1,1350 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lte-tap-helper.h" +#include <ns3/string.h> +#include <ns3/log.h> +#include <ns3/abort.h> +#include <ns3/pointer.h> +#include <ns3/lte-enb-rrc.h> +#include <ns3/epc-ue-nas.h> +#include <ns3/epc-enb-application.h> +#include <ns3/lte-ue-rrc.h> +#include <ns3/lte-ue-mac.h> +#include <ns3/lte-enb-mac.h> +#include <ns3/lte-enb-net-device.h> +#include <ns3/lte-enb-phy.h> +#include <ns3/lte-ue-phy.h> +#include <ns3/lte-spectrum-phy.h> +#include <ns3/lte-chunk-processor.h> +#include <ns3/multi-model-spectrum-channel.h> +#include <ns3/friis-spectrum-propagation-loss.h> +#include <ns3/trace-fading-loss-model.h> +#include <ns3/isotropic-antenna-model.h> +#include <ns3/lte-enb-net-device.h> +#include <ns3/lte-ue-net-device.h> +#include <ns3/ff-mac-scheduler.h> +#include <ns3/lte-ffr-algorithm.h> +#include <ns3/lte-handover-algorithm.h> +#include <ns3/lte-anr.h> +#include <ns3/lte-rlc.h> +#include <ns3/lte-rlc-um.h> +#include <ns3/lte-rlc-am.h> +#include <ns3/epc-enb-s1-sap.h> +#include <ns3/lte-rrc-protocol-ideal.h> +#include <ns3/lte-rrc-protocol-real.h> +#include <ns3/mac-stats-calculator.h> +#include <ns3/phy-stats-calculator.h> +#include <ns3/phy-tx-stats-calculator.h> +#include <ns3/phy-rx-stats-calculator.h> +#include <ns3/epc-helper.h> +#include <iostream> +#include <ns3/buildings-propagation-loss-model.h> +#include <ns3/lte-spectrum-value-helper.h> +#include <ns3/epc-x2.h> + +#include "lte-tap-ue-net-device.h" +#define ALPHA 0.999 + +/** + * \brief this file has been modified from that of lte-helper.cpp in ns3 lte module to support emulation of lte channel + */ + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("LteTapHelper"); + +NS_OBJECT_ENSURE_REGISTERED (LteTapHelper); + +LteTapHelper::LteTapHelper (void) + : m_fadingStreamsAssigned (false), + m_imsiCounter (0), + m_cellIdCounter (0) +{ + NS_LOG_FUNCTION (this); + m_enbNetDeviceFactory.SetTypeId (LteEnbNetDevice::GetTypeId ()); + m_enbAntennaModelFactory.SetTypeId (IsotropicAntennaModel::GetTypeId ()); + m_ueNetDeviceFactory.SetTypeId (LteTapUeNetDevice::GetTypeId ()); + m_ueAntennaModelFactory.SetTypeId (IsotropicAntennaModel::GetTypeId ()); + m_channelFactory.SetTypeId (MultiModelSpectrumChannel::GetTypeId ()); +} + +void +LteTapHelper::DoInitialize (void) +{ + NS_LOG_FUNCTION (this); + m_downlinkChannel = m_channelFactory.Create<SpectrumChannel> (); + m_uplinkChannel = m_channelFactory.Create<SpectrumChannel> (); + + m_downlinkPathlossModel = m_dlPathlossModelFactory.Create (); + Ptr<SpectrumPropagationLossModel> dlSplm = m_downlinkPathlossModel->GetObject<SpectrumPropagationLossModel> (); + if (dlSplm != 0) + { + NS_LOG_LOGIC (this << " using a SpectrumPropagationLossModel in DL"); + m_downlinkChannel->AddSpectrumPropagationLossModel (dlSplm); + } + else + { + NS_LOG_LOGIC (this << " using a PropagationLossModel in DL"); + Ptr<PropagationLossModel> dlPlm = m_downlinkPathlossModel->GetObject<PropagationLossModel> (); + NS_ASSERT_MSG (dlPlm != 0, " " << m_downlinkPathlossModel << " is neither PropagationLossModel nor SpectrumPropagationLossModel"); + m_downlinkChannel->AddPropagationLossModel (dlPlm); + } + + m_uplinkPathlossModel = m_ulPathlossModelFactory.Create (); + Ptr<SpectrumPropagationLossModel> ulSplm = m_uplinkPathlossModel->GetObject<SpectrumPropagationLossModel> (); + if (ulSplm != 0) + { + NS_LOG_LOGIC (this << " using a SpectrumPropagationLossModel in UL"); + m_uplinkChannel->AddSpectrumPropagationLossModel (ulSplm); + } + else + { + NS_LOG_LOGIC (this << " using a PropagationLossModel in UL"); + Ptr<PropagationLossModel> ulPlm = m_uplinkPathlossModel->GetObject<PropagationLossModel> (); + NS_ASSERT_MSG (ulPlm != 0, " " << m_uplinkPathlossModel << " is neither PropagationLossModel nor SpectrumPropagationLossModel"); + m_uplinkChannel->AddPropagationLossModel (ulPlm); + } + if (!m_fadingModelType.empty ()) + { + m_fadingModule = m_fadingModelFactory.Create<SpectrumPropagationLossModel> (); + m_fadingModule->Initialize (); + m_downlinkChannel->AddSpectrumPropagationLossModel (m_fadingModule); + m_uplinkChannel->AddSpectrumPropagationLossModel (m_fadingModule); + } + m_phyStats = CreateObject<PhyStatsCalculator> (); + m_phyTxStats = CreateObject<PhyTxStatsCalculator> (); + m_phyRxStats = CreateObject<PhyRxStatsCalculator> (); + m_macStats = CreateObject<MacStatsCalculator> (); + Object::DoInitialize (); + +} + +LteTapHelper::~LteTapHelper (void) +{ + NS_LOG_FUNCTION (this); +} + +TypeId LteTapHelper::GetTypeId (void) +{ + static TypeId + tid = + TypeId ("ns3::LteTapHelper") + .SetParent<Object> () + .AddConstructor<LteTapHelper> () + .AddAttribute ("Scheduler", + "The type of scheduler to be used for eNBs. " + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::FfMacScheduler.", + StringValue ("ns3::PfFfMacScheduler"), + MakeStringAccessor (&LteTapHelper::SetSchedulerType, + &LteTapHelper::GetSchedulerType), + MakeStringChecker ()) + .AddAttribute ("FfrAlgorithm", + "The type of FFR algorithm to be used for eNBs. " + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::LteFfrAlgorithm.", + StringValue ("ns3::LteFrNoOpAlgorithm"), + MakeStringAccessor (&LteTapHelper::SetFfrAlgorithmType, + &LteTapHelper::GetFfrAlgorithmType), + MakeStringChecker ()) + .AddAttribute ("HandoverAlgorithm", + "The type of handover algorithm to be used for eNBs. " + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::LteHandoverAlgorithm.", + StringValue ("ns3::NoOpHandoverAlgorithm"), + MakeStringAccessor (&LteTapHelper::SetHandoverAlgorithmType, + &LteTapHelper::GetHandoverAlgorithmType), + MakeStringChecker ()) + .AddAttribute ("PathlossModel", + "The type of pathloss model to be used. " + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::PropagationLossModel.", + StringValue ("ns3::FriisPropagationLossModel"), + MakeStringAccessor (&LteTapHelper::SetPathlossModelType), + MakeStringChecker ()) + .AddAttribute ("FadingModel", + "The type of fading model to be used." + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::SpectrumPropagationLossModel." + "If the type is set to an empty string, no fading model is used.", + StringValue (""), + MakeStringAccessor (&LteTapHelper::SetFadingModel), + MakeStringChecker ()) + .AddAttribute ("UseIdealRrc", + "If true, LteRrcProtocolIdeal will be used for RRC signaling. " + "If false, LteRrcProtocolReal will be used.", + BooleanValue (true), + MakeBooleanAccessor (&LteTapHelper::m_useIdealRrc), + MakeBooleanChecker ()) + .AddAttribute ("AnrEnabled", + "Activate or deactivate Automatic Neighbour Relation function", + BooleanValue (true), + MakeBooleanAccessor (&LteTapHelper::m_isAnrEnabled), + MakeBooleanChecker ()) + .AddAttribute ("UsePdschForCqiGeneration", + "If true, DL-CQI will be calculated from PDCCH as signal and PDSCH as interference " + "If false, DL-CQI will be calculated from PDCCH as signal and PDCCH as interference ", + BooleanValue (true), + MakeBooleanAccessor (&LteTapHelper::m_usePdschForCqiGeneration), + MakeBooleanChecker ()) + ; + return tid; +} + +void +LteTapHelper::DoDispose () +{ + NS_LOG_FUNCTION (this); + m_downlinkChannel = 0; + m_uplinkChannel = 0; + Object::DoDispose (); +} + + +void +LteTapHelper::SetEpcHelper (Ptr<EpcHelper> h) +{ + NS_LOG_FUNCTION (this << h); + m_epcHelper = h; +} + +void +LteTapHelper::SetSchedulerType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_schedulerFactory = ObjectFactory (); + m_schedulerFactory.SetTypeId (type); +} + +std::string +LteTapHelper::GetSchedulerType () const +{ + return m_schedulerFactory.GetTypeId ().GetName (); +} + +void +LteTapHelper::SetSchedulerAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this << n); + m_schedulerFactory.Set (n, v); +} + +std::string +LteTapHelper::GetFfrAlgorithmType () const +{ + return m_ffrAlgorithmFactory.GetTypeId ().GetName (); +} + +void +LteTapHelper::SetFfrAlgorithmType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_ffrAlgorithmFactory = ObjectFactory (); + m_ffrAlgorithmFactory.SetTypeId (type); +} + +void +LteTapHelper::SetFfrAlgorithmAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this << n); + m_ffrAlgorithmFactory.Set (n, v); +} + +std::string +LteTapHelper::GetHandoverAlgorithmType () const +{ + return m_handoverAlgorithmFactory.GetTypeId ().GetName (); +} + +void +LteTapHelper::SetHandoverAlgorithmType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_handoverAlgorithmFactory = ObjectFactory (); + m_handoverAlgorithmFactory.SetTypeId (type); +} + +void +LteTapHelper::SetHandoverAlgorithmAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this << n); + m_handoverAlgorithmFactory.Set (n, v); +} + + +void +LteTapHelper::SetPathlossModelType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_dlPathlossModelFactory = ObjectFactory (); + m_dlPathlossModelFactory.SetTypeId (type); + m_ulPathlossModelFactory = ObjectFactory (); + m_ulPathlossModelFactory.SetTypeId (type); +} + +void +LteTapHelper::SetPathlossModelAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this << n); + m_dlPathlossModelFactory.Set (n, v); + m_ulPathlossModelFactory.Set (n, v); +} + +void +LteTapHelper::SetEnbDeviceAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this); + m_enbNetDeviceFactory.Set (n, v); +} + + +void +LteTapHelper::SetEnbAntennaModelType (std::string type) +{ + NS_LOG_FUNCTION (this); + m_enbAntennaModelFactory.SetTypeId (type); +} + +void +LteTapHelper::SetEnbAntennaModelAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this); + m_enbAntennaModelFactory.Set (n, v); +} + +void +LteTapHelper::SetUeDeviceAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this); + m_ueNetDeviceFactory.Set (n, v); +} + +void +LteTapHelper::SetUeAntennaModelType (std::string type) +{ + NS_LOG_FUNCTION (this); + m_ueAntennaModelFactory.SetTypeId (type); +} + +void +LteTapHelper::SetUeAntennaModelAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this); + m_ueAntennaModelFactory.Set (n, v); +} + +void +LteTapHelper::SetFadingModel (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_fadingModelType = type; + if (!type.empty ()) + { + m_fadingModelFactory = ObjectFactory (); + m_fadingModelFactory.SetTypeId (type); + } +} + +void +LteTapHelper::SetFadingModelAttribute (std::string n, const AttributeValue &v) +{ + m_fadingModelFactory.Set (n, v); +} + +void +LteTapHelper::SetSpectrumChannelType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_channelFactory.SetTypeId (type); +} + +void +LteTapHelper::SetSpectrumChannelAttribute (std::string n, const AttributeValue &v) +{ + m_channelFactory.Set (n, v); +} + + +NetDeviceContainer +LteTapHelper::InstallEnbDevice (NodeContainer c) +{ + NS_LOG_FUNCTION (this); + Initialize (); // will run DoInitialize () if necessary + NetDeviceContainer devices; + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + Ptr<Node> node = *i; + Ptr<NetDevice> device = InstallSingleEnbDevice (node); + devices.Add (device); + } + return devices; +} + +NetDeviceContainer +LteTapHelper::InstallUeDevice (NodeContainer c) +{ + NS_LOG_FUNCTION (this); + NetDeviceContainer devices; + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + Ptr<Node> node = *i; + Ptr<NetDevice> device = InstallSingleUeDevice (node); + devices.Add (device); + } + return devices; +} + + +Ptr<NetDevice> +LteTapHelper::InstallSingleEnbDevice (Ptr<Node> n) +{ + + NS_ABORT_MSG_IF (m_cellIdCounter == 65535, "max num eNBs exceeded"); + uint16_t cellId = ++m_cellIdCounter; + + Ptr<LteSpectrumPhy> dlPhy = CreateObject<LteSpectrumPhy> (); + Ptr<LteSpectrumPhy> ulPhy = CreateObject<LteSpectrumPhy> (); + + Ptr<LteEnbPhy> phy = CreateObject<LteEnbPhy> (dlPhy, ulPhy); + + Ptr<LteHarqPhy> harq = Create<LteHarqPhy> (); + dlPhy->SetHarqPhyModule (harq); + ulPhy->SetHarqPhyModule (harq); + phy->SetHarqPhyModule (harq); + + Ptr<LteChunkProcessor> pCtrl = Create<LteChunkProcessor> (); + pCtrl->AddCallback (MakeCallback (&LteEnbPhy::GenerateCtrlCqiReport, phy)); + ulPhy->AddCtrlSinrChunkProcessor (pCtrl); // for evaluating SRS UL-CQI + + Ptr<LteChunkProcessor> pData = Create<LteChunkProcessor> (); + pData->AddCallback (MakeCallback (&LteEnbPhy::GenerateDataCqiReport, phy)); + pData->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, ulPhy)); + ulPhy->AddDataSinrChunkProcessor (pData); // for evaluating PUSCH UL-CQI + + Ptr<LteChunkProcessor> pInterf = Create<LteChunkProcessor> (); + pInterf->AddCallback (MakeCallback (&LteEnbPhy::ReportInterference, phy)); + ulPhy->AddInterferenceDataChunkProcessor (pInterf); // for interference power tracing + + dlPhy->SetChannel (m_downlinkChannel); + ulPhy->SetChannel (m_uplinkChannel); + + Ptr<MobilityModel> mm = n->GetObject<MobilityModel> (); + NS_ASSERT_MSG (mm, "MobilityModel needs to be set on node before calling LteTapHelper::InstallUeDevice ()"); + dlPhy->SetMobility (mm); + ulPhy->SetMobility (mm); + + Ptr<AntennaModel> antenna = (m_enbAntennaModelFactory.Create ())->GetObject<AntennaModel> (); + NS_ASSERT_MSG (antenna, "error in creating the AntennaModel object"); + dlPhy->SetAntenna (antenna); + ulPhy->SetAntenna (antenna); + + Ptr<LteEnbMac> mac = CreateObject<LteEnbMac> (); + Ptr<FfMacScheduler> sched = m_schedulerFactory.Create<FfMacScheduler> (); + Ptr<LteFfrAlgorithm> ffrAlgorithm = m_ffrAlgorithmFactory.Create<LteFfrAlgorithm> (); + Ptr<LteHandoverAlgorithm> handoverAlgorithm = m_handoverAlgorithmFactory.Create<LteHandoverAlgorithm> (); + Ptr<LteEnbRrc> rrc = CreateObject<LteEnbRrc> (); + + if (m_useIdealRrc) + { + Ptr<LteEnbRrcProtocolIdeal> rrcProtocol = CreateObject<LteEnbRrcProtocolIdeal> (); + rrcProtocol->SetLteEnbRrcSapProvider (rrc->GetLteEnbRrcSapProvider ()); + rrc->SetLteEnbRrcSapUser (rrcProtocol->GetLteEnbRrcSapUser ()); + rrc->AggregateObject (rrcProtocol); + rrcProtocol->SetCellId (cellId); + } + else + { + Ptr<LteEnbRrcProtocolReal> rrcProtocol = CreateObject<LteEnbRrcProtocolReal> (); + rrcProtocol->SetLteEnbRrcSapProvider (rrc->GetLteEnbRrcSapProvider ()); + rrc->SetLteEnbRrcSapUser (rrcProtocol->GetLteEnbRrcSapUser ()); + rrc->AggregateObject (rrcProtocol); + rrcProtocol->SetCellId (cellId); + } + + if (m_epcHelper != 0) + { + EnumValue epsBearerToRlcMapping; + rrc->GetAttribute ("EpsBearerToRlcMapping", epsBearerToRlcMapping); + // it does not make sense to use RLC/SM when also using the EPC + if (epsBearerToRlcMapping.Get () == LteEnbRrc::RLC_SM_ALWAYS) + { + rrc->SetAttribute ("EpsBearerToRlcMapping", EnumValue (LteEnbRrc::RLC_UM_ALWAYS)); + } + } + + rrc->SetLteEnbCmacSapProvider (mac->GetLteEnbCmacSapProvider ()); + mac->SetLteEnbCmacSapUser (rrc->GetLteEnbCmacSapUser ()); + rrc->SetLteMacSapProvider (mac->GetLteMacSapProvider ()); + + rrc->SetLteHandoverManagementSapProvider (handoverAlgorithm->GetLteHandoverManagementSapProvider ()); + handoverAlgorithm->SetLteHandoverManagementSapUser (rrc->GetLteHandoverManagementSapUser ()); + + mac->SetFfMacSchedSapProvider (sched->GetFfMacSchedSapProvider ()); + mac->SetFfMacCschedSapProvider (sched->GetFfMacCschedSapProvider ()); + + sched->SetFfMacSchedSapUser (mac->GetFfMacSchedSapUser ()); + sched->SetFfMacCschedSapUser (mac->GetFfMacCschedSapUser ()); + + phy->SetLteEnbPhySapUser (mac->GetLteEnbPhySapUser ()); + mac->SetLteEnbPhySapProvider (phy->GetLteEnbPhySapProvider ()); + + phy->SetLteEnbCphySapUser (rrc->GetLteEnbCphySapUser ()); + rrc->SetLteEnbCphySapProvider (phy->GetLteEnbCphySapProvider ()); + + //FFR SAP + sched->SetLteFfrSapProvider (ffrAlgorithm->GetLteFfrSapProvider ()); + ffrAlgorithm->SetLteFfrSapUser (sched->GetLteFfrSapUser ()); + + rrc->SetLteFfrRrcSapProvider (ffrAlgorithm->GetLteFfrRrcSapProvider ()); + ffrAlgorithm->SetLteFfrRrcSapUser (rrc->GetLteFfrRrcSapUser ()); + //FFR SAP END + + Ptr<LteEnbNetDevice> dev = m_enbNetDeviceFactory.Create<LteEnbNetDevice> (); + dev->SetNode (n); + dev->SetAttribute ("CellId", UintegerValue (cellId)); + dev->SetAttribute ("LteEnbPhy", PointerValue (phy)); + dev->SetAttribute ("LteEnbMac", PointerValue (mac)); + dev->SetAttribute ("FfMacScheduler", PointerValue (sched)); + dev->SetAttribute ("LteEnbRrc", PointerValue (rrc)); + dev->SetAttribute ("LteHandoverAlgorithm", PointerValue (handoverAlgorithm)); + dev->SetAttribute ("LteFfrAlgorithm", PointerValue (ffrAlgorithm)); + + if (m_isAnrEnabled) + { + Ptr<LteAnr> anr = CreateObject<LteAnr> (cellId); + rrc->SetLteAnrSapProvider (anr->GetLteAnrSapProvider ()); + anr->SetLteAnrSapUser (rrc->GetLteAnrSapUser ()); + dev->SetAttribute ("LteAnr", PointerValue (anr)); + } + + phy->SetDevice (dev); + dlPhy->SetDevice (dev); + ulPhy->SetDevice (dev); + + n->AddDevice (dev); + ulPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteEnbPhy::PhyPduReceived, phy)); + ulPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteEnbPhy::ReceiveLteControlMessageList, phy)); + ulPhy->SetLtePhyUlHarqFeedbackCallback (MakeCallback (&LteEnbPhy::ReceiveLteUlHarqFeedback, phy)); + rrc->SetForwardUpCallback (MakeCallback (&LteEnbNetDevice::Receive, dev)); + + NS_LOG_LOGIC ("set the propagation model frequencies"); + double dlFreq = LteSpectrumValueHelper::GetCarrierFrequency (dev->GetDlEarfcn ()); + NS_LOG_LOGIC ("DL freq: " << dlFreq); + bool dlFreqOk = m_downlinkPathlossModel->SetAttributeFailSafe ("Frequency", DoubleValue (dlFreq)); + if (!dlFreqOk) + { + NS_LOG_WARN ("DL propagation model does not have a Frequency attribute"); + } + double ulFreq = LteSpectrumValueHelper::GetCarrierFrequency (dev->GetUlEarfcn ()); + NS_LOG_LOGIC ("UL freq: " << ulFreq); + bool ulFreqOk = m_uplinkPathlossModel->SetAttributeFailSafe ("Frequency", DoubleValue (ulFreq)); + if (!ulFreqOk) + { + NS_LOG_WARN ("UL propagation model does not have a Frequency attribute"); + } + + dev->Initialize (); + + m_uplinkChannel->AddRx (ulPhy); + + if (m_epcHelper != 0) + { + NS_LOG_INFO ("adding this eNB to the EPC"); + m_epcHelper->AddEnb (n, dev, dev->GetCellId ()); + Ptr<EpcEnbApplication> enbApp = n->GetApplication (0)->GetObject<EpcEnbApplication> (); + NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication"); + + // S1 SAPs + rrc->SetS1SapProvider (enbApp->GetS1SapProvider ()); + enbApp->SetS1SapUser (rrc->GetS1SapUser ()); + + // X2 SAPs + Ptr<EpcX2> x2 = n->GetObject<EpcX2> (); + x2->SetEpcX2SapUser (rrc->GetEpcX2SapUser ()); + rrc->SetEpcX2SapProvider (x2->GetEpcX2SapProvider ()); + } + + return dev; +} + +Ptr<NetDevice> +LteTapHelper::InstallSingleUeDevice (Ptr<Node> n) +{ + NS_LOG_FUNCTION (this); + Ptr<LteSpectrumPhy> dlPhy = CreateObject<LteSpectrumPhy> (); + Ptr<LteSpectrumPhy> ulPhy = CreateObject<LteSpectrumPhy> (); + + Ptr<LteUePhy> phy = CreateObject<LteUePhy> (dlPhy, ulPhy); + + Ptr<LteHarqPhy> harq = Create<LteHarqPhy> (); + dlPhy->SetHarqPhyModule (harq); + ulPhy->SetHarqPhyModule (harq); + phy->SetHarqPhyModule (harq); + + Ptr<LteChunkProcessor> pRs = Create<LteChunkProcessor> (); + pRs->AddCallback (MakeCallback (&LteUePhy::ReportRsReceivedPower, phy)); + dlPhy->AddRsPowerChunkProcessor (pRs); + + Ptr<LteChunkProcessor> pInterf = Create<LteChunkProcessor> (); + pInterf->AddCallback (MakeCallback (&LteUePhy::ReportInterference, phy)); + dlPhy->AddInterferenceCtrlChunkProcessor (pInterf); // for RSRQ evaluation of UE Measurements + + Ptr<LteChunkProcessor> pCtrl = Create<LteChunkProcessor> (); + pCtrl->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, dlPhy)); + dlPhy->AddCtrlSinrChunkProcessor (pCtrl); + + Ptr<LteChunkProcessor> pData = Create<LteChunkProcessor> (); + pData->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, dlPhy)); + dlPhy->AddDataSinrChunkProcessor (pData); + + if (m_usePdschForCqiGeneration) + { + // CQI calculation based on PDCCH for signal and PDSCH for interference + pCtrl->AddCallback (MakeCallback (&LteUePhy::GenerateMixedCqiReport, phy)); + Ptr<LteChunkProcessor> pDataInterf = Create<LteChunkProcessor> (); + pDataInterf->AddCallback (MakeCallback (&LteUePhy::ReportDataInterference, phy)); + dlPhy->AddInterferenceDataChunkProcessor (pDataInterf); + } + else + { + // CQI calculation based on PDCCH for both signal and interference + pCtrl->AddCallback (MakeCallback (&LteUePhy::GenerateCtrlCqiReport, phy)); + } + + + + dlPhy->SetChannel (m_downlinkChannel); + ulPhy->SetChannel (m_uplinkChannel); + + Ptr<MobilityModel> mm = n->GetObject<MobilityModel> (); + NS_ASSERT_MSG (mm, "MobilityModel needs to be set on node before calling LteTapHelper::InstallUeDevice ()"); + dlPhy->SetMobility (mm); + ulPhy->SetMobility (mm); + + Ptr<AntennaModel> antenna = (m_ueAntennaModelFactory.Create ())->GetObject<AntennaModel> (); + NS_ASSERT_MSG (antenna, "error in creating the AntennaModel object"); + dlPhy->SetAntenna (antenna); + ulPhy->SetAntenna (antenna); + + Ptr<LteUeMac> mac = CreateObject<LteUeMac> (); + Ptr<LteUeRrc> rrc = CreateObject<LteUeRrc> (); + + if (m_useIdealRrc) + { + Ptr<LteUeRrcProtocolIdeal> rrcProtocol = CreateObject<LteUeRrcProtocolIdeal> (); + rrcProtocol->SetUeRrc (rrc); + rrc->AggregateObject (rrcProtocol); + rrcProtocol->SetLteUeRrcSapProvider (rrc->GetLteUeRrcSapProvider ()); + rrc->SetLteUeRrcSapUser (rrcProtocol->GetLteUeRrcSapUser ()); + } + else + { + Ptr<LteUeRrcProtocolReal> rrcProtocol = CreateObject<LteUeRrcProtocolReal> (); + rrcProtocol->SetUeRrc (rrc); + rrc->AggregateObject (rrcProtocol); + rrcProtocol->SetLteUeRrcSapProvider (rrc->GetLteUeRrcSapProvider ()); + rrc->SetLteUeRrcSapUser (rrcProtocol->GetLteUeRrcSapUser ()); + } + + if (m_epcHelper != 0) + { + rrc->SetUseRlcSm (false); + } + Ptr<EpcUeNas> nas = CreateObject<EpcUeNas> (); + + nas->SetAsSapProvider (rrc->GetAsSapProvider ()); + rrc->SetAsSapUser (nas->GetAsSapUser ()); + + rrc->SetLteUeCmacSapProvider (mac->GetLteUeCmacSapProvider ()); + mac->SetLteUeCmacSapUser (rrc->GetLteUeCmacSapUser ()); + rrc->SetLteMacSapProvider (mac->GetLteMacSapProvider ()); + + phy->SetLteUePhySapUser (mac->GetLteUePhySapUser ()); + mac->SetLteUePhySapProvider (phy->GetLteUePhySapProvider ()); + + phy->SetLteUeCphySapUser (rrc->GetLteUeCphySapUser ()); + rrc->SetLteUeCphySapProvider (phy->GetLteUeCphySapProvider ()); + + NS_ABORT_MSG_IF (m_imsiCounter >= 0xFFFFFFFF, "max num UEs exceeded"); + uint64_t imsi = ++m_imsiCounter; + + Ptr<LteTapUeNetDevice> dev = m_ueNetDeviceFactory.Create<LteTapUeNetDevice> (); + dev->SetNode (n); + dev->SetAttribute ("Imsi", UintegerValue (imsi)); + dev->SetAttribute ("LteUePhy", PointerValue (phy)); + dev->SetAttribute ("LteUeMac", PointerValue (mac)); + dev->SetAttribute ("LteUeRrc", PointerValue (rrc)); + dev->SetAttribute ("EpcUeNas", PointerValue (nas)); + + phy->SetDevice (dev); + dlPhy->SetDevice (dev); + ulPhy->SetDevice (dev); + nas->SetDevice (dev); + + n->AddDevice (dev); + dlPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteUePhy::PhyPduReceived, phy)); + dlPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteUePhy::ReceiveLteControlMessageList, phy)); + dlPhy->SetLtePhyRxPssCallback (MakeCallback (&LteUePhy::ReceivePss, phy)); + dlPhy->SetLtePhyDlHarqFeedbackCallback (MakeCallback (&LteUePhy::ReceiveLteDlHarqFeedback, phy)); + nas->SetForwardUpCallback (MakeCallback (&LteTapUeNetDevice::Receive, dev)); + + if (m_epcHelper != 0) + { + m_epcHelper->AddUe (dev, dev->GetImsi ()); + } + + dev->Initialize (); + + return dev; +} + + +void +LteTapHelper::Attach (NetDeviceContainer ueDevices) +{ + NS_LOG_FUNCTION (this); + for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) + { + Attach (*i); + } +} + +void +LteTapHelper::Attach (Ptr<NetDevice> ueDevice) +{ + NS_LOG_FUNCTION (this); + + if (m_epcHelper == 0) + { + NS_FATAL_ERROR ("This function is not valid without properly configured EPC"); + } + + Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> (); + if (ueLteDevice == 0) + { + NS_FATAL_ERROR ("The passed NetDevice must be an LteUeNetDevice"); + } + + // initiate cell selection + Ptr<EpcUeNas> ueNas = ueLteDevice->GetNas (); + NS_ASSERT (ueNas != 0); + uint16_t dlEarfcn = ueLteDevice->GetDlEarfcn (); + ueNas->StartCellSelection (dlEarfcn); + + // instruct UE to immediately enter CONNECTED mode after camping + ueNas->Connect (); + + // activate default EPS bearer + m_epcHelper->ActivateEpsBearer (ueDevice, ueLteDevice->GetImsi (), + EpcTft::Default (), + EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT)); +} + +void +LteTapHelper::Attach (NetDeviceContainer ueDevices, Ptr<NetDevice> enbDevice) +{ + NS_LOG_FUNCTION (this); + for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) + { + Attach (*i, enbDevice); + } +} + +void +LteTapHelper::Attach (Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice) +{ + NS_LOG_FUNCTION (this); + //enbRrc->SetCellId (enbDevice->GetObject<LteEnbNetDevice> ()->GetCellId ()); + + Ptr<LteTapUeNetDevice> ueLteDevice = ueDevice->GetObject<LteTapUeNetDevice> (); + Ptr<LteEnbNetDevice> enbLteDevice = enbDevice->GetObject<LteEnbNetDevice> (); + + Ptr<EpcUeNas> ueNas = ueLteDevice->GetNas (); + ueNas->Connect (enbLteDevice->GetCellId (), enbLteDevice->GetDlEarfcn ()); + + if (m_epcHelper != 0) + { + // activate default EPS bearer + m_epcHelper->ActivateEpsBearer (ueDevice, ueLteDevice->GetImsi (), EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT)); + } + + // tricks needed for the simplified LTE-only simulations + if (m_epcHelper == 0) + { + ueDevice->GetObject<LteTapUeNetDevice> ()->SetTargetEnb (enbDevice->GetObject<LteEnbNetDevice> ()); + } +} + +void +LteTapHelper::AttachToClosestEnb (NetDeviceContainer ueDevices, NetDeviceContainer enbDevices) +{ + NS_LOG_FUNCTION (this); + for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) + { + AttachToClosestEnb (*i, enbDevices); + } +} + +void +LteTapHelper::AttachToClosestEnb (Ptr<NetDevice> ueDevice, NetDeviceContainer enbDevices) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG (enbDevices.GetN () > 0, "empty enb device container"); + Vector uepos = ueDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition (); + double minDistance = std::numeric_limits<double>::infinity (); + Ptr<NetDevice> closestEnbDevice; + for (NetDeviceContainer::Iterator i = enbDevices.Begin (); i != enbDevices.End (); ++i) + { + Vector enbpos = (*i)->GetNode ()->GetObject<MobilityModel> ()->GetPosition (); + double distance = CalculateDistance (uepos, enbpos); + if (distance < minDistance) + { + minDistance = distance; + closestEnbDevice = *i; + } + } + NS_ASSERT (closestEnbDevice != 0); + Attach (ueDevice, closestEnbDevice); +} + +uint8_t +LteTapHelper::ActivateDedicatedEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer, Ptr<EpcTft> tft) +{ + NS_LOG_FUNCTION (this); + for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) + { + uint8_t bearerId = ActivateDedicatedEpsBearer (*i, bearer, tft); + return bearerId; + } + return 0; +} + + +uint8_t +LteTapHelper::ActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice, EpsBearer bearer, Ptr<EpcTft> tft) +{ + NS_LOG_FUNCTION (this); + + NS_ASSERT_MSG (m_epcHelper != 0, "dedicated EPS bearers cannot be set up when the EPC is not used"); + + uint64_t imsi = ueDevice->GetObject<LteUeNetDevice> ()->GetImsi (); + uint8_t bearerId = m_epcHelper->ActivateEpsBearer (ueDevice, imsi, tft, bearer); + return bearerId; +} + +/** + * \ingroup lte + * + * TapDrbActivatior allows user to activate bearers for UEs + * when EPC is not used. Activation function is hooked to + * the Enb RRC Connection Estabilished trace source. When + * UE change its RRC state to CONNECTED_NORMALLY, activation + * function is called and bearer is activated. +*/ +class TapDrbActivator : public SimpleRefCount<TapDrbActivator> +{ +public: + /** + * TapDrbActivator Constructor + * + * \param ueDevice the UeNetDevice for which bearer will be activated + * \param bearer the bearer configuration + */ + TapDrbActivator (Ptr<NetDevice> ueDevice, EpsBearer bearer); + + /** + * Function hooked to the Enb RRC Connection Established trace source + * Fired upon successful RRC connection establishment. + * + * \param a TapDrbActivator object + * \param context + * \param imsi + * \param cellId + * \param rnti + */ + static void ActivateCallback (Ptr<TapDrbActivator> a, std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti); + + /** + * Procedure firstly checks if bearer was not activated, if IMSI + * from trace source equals configured one and if UE is really + * in RRC connected state. If all requirements are met, it performs + * bearer activation. + * + * \param imsi + * \param cellId + * \param rnti + */ + void ActivateTapDrb (uint64_t imsi, uint16_t cellId, uint16_t rnti); +private: + /** + * Bearer can be activated only once. This value stores state of + * bearer. Initially is set to false and changed to true during + * bearer activation. + */ + bool m_active; + /** + * UeNetDevice for which bearer will be activated + */ + Ptr<NetDevice> m_ueDevice; + /** + * Configuration of bearer which will be activated + */ + EpsBearer m_bearer; + /** + * imsi the unique UE identifier + */ + uint64_t m_imsi; +}; + +TapDrbActivator::TapDrbActivator (Ptr<NetDevice> ueDevice, EpsBearer bearer) + : m_active (false), + m_ueDevice (ueDevice), + m_bearer (bearer), + m_imsi (m_ueDevice->GetObject<LteUeNetDevice> ()->GetImsi ()) +{ +} + +void +TapDrbActivator::ActivateCallback (Ptr<TapDrbActivator> a, std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti) +{ + NS_LOG_FUNCTION (a << context << imsi << cellId << rnti); + a->ActivateTapDrb (imsi, cellId, rnti); +} + +void +TapDrbActivator::ActivateTapDrb (uint64_t imsi, uint16_t cellId, uint16_t rnti) +{ + NS_LOG_FUNCTION (this << imsi << cellId << rnti << m_active); + if ((!m_active) && (imsi == m_imsi)) + { + Ptr<LteUeRrc> ueRrc = m_ueDevice->GetObject<LteUeNetDevice> ()->GetRrc (); + NS_ASSERT (ueRrc->GetState () == LteUeRrc::CONNECTED_NORMALLY); + uint16_t rnti = ueRrc->GetRnti (); + Ptr<LteEnbNetDevice> enbLteDevice = m_ueDevice->GetObject<LteUeNetDevice> ()->GetTargetEnb (); + Ptr<LteEnbRrc> enbRrc = enbLteDevice->GetObject<LteEnbNetDevice> ()->GetRrc (); + NS_ASSERT (ueRrc->GetCellId () == enbLteDevice->GetCellId ()); + Ptr<UeManager> ueManager = enbRrc->GetUeManager (rnti); + NS_ASSERT (ueManager->GetState () == UeManager::CONNECTED_NORMALLY + || ueManager->GetState () == UeManager::CONNECTION_RECONFIGURATION); + EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params; + params.rnti = rnti; + params.bearer = m_bearer; + params.bearerId = 0; + params.gtpTeid = 0; // don't care + enbRrc->GetS1SapUser ()->DataRadioBearerSetupRequest (params); + m_active = true; + } +} + + +void +LteTapHelper::ActivateDataRadioBearer (Ptr<NetDevice> ueDevice, EpsBearer bearer) +{ + NS_LOG_FUNCTION (this << ueDevice); + NS_ASSERT_MSG (m_epcHelper == 0, "this method must not be used when the EPC is being used"); + + // Normally it is the EPC that takes care of activating DRBs + // when the UE gets connected. When the EPC is not used, we achieve + // the same behavior by hooking a dedicated DRB activation function + // to the Enb RRC Connection Established trace source + + + Ptr<LteEnbNetDevice> enbLteDevice = ueDevice->GetObject<LteUeNetDevice> ()->GetTargetEnb (); + + std::ostringstream path; + path << "/NodeList/" << enbLteDevice->GetNode ()->GetId () + << "/DeviceList/" << enbLteDevice->GetIfIndex () + << "/LteEnbRrc/ConnectionEstablished"; + Ptr<TapDrbActivator> arg = Create<TapDrbActivator> (ueDevice, bearer); + Config::Connect (path.str (), MakeBoundCallback (&TapDrbActivator::ActivateCallback, arg)); +} + +void +LteTapHelper::AddX2Interface (NodeContainer enbNodes) +{ + NS_LOG_FUNCTION (this); + + NS_ASSERT_MSG (m_epcHelper != 0, "X2 interfaces cannot be set up when the EPC is not used"); + + for (NodeContainer::Iterator i = enbNodes.Begin (); i != enbNodes.End (); ++i) + { + for (NodeContainer::Iterator j = i + 1; j != enbNodes.End (); ++j) + { + AddX2Interface (*i, *j); + } + } +} + +void +LteTapHelper::AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2) +{ + NS_LOG_FUNCTION (this); + NS_LOG_INFO ("setting up the X2 interface"); + + m_epcHelper->AddX2Interface (enbNode1, enbNode2); +} + +void +LteTapHelper::HandoverRequest (Time hoTime, Ptr<NetDevice> ueDev, Ptr<NetDevice> sourceEnbDev, Ptr<NetDevice> targetEnbDev) +{ + NS_LOG_FUNCTION (this << ueDev << sourceEnbDev << targetEnbDev); + NS_ASSERT_MSG (m_epcHelper, "Handover requires the use of the EPC - did you forget to call LteTapHelper::SetEpcHelper () ?"); + Simulator::Schedule (hoTime, &LteTapHelper::DoHandoverRequest, this, ueDev, sourceEnbDev, targetEnbDev); +} + +void +LteTapHelper::DoHandoverRequest (Ptr<NetDevice> ueDev, Ptr<NetDevice> sourceEnbDev, Ptr<NetDevice> targetEnbDev) +{ + NS_LOG_FUNCTION (this << ueDev << sourceEnbDev << targetEnbDev); + + uint16_t targetCellId = targetEnbDev->GetObject<LteEnbNetDevice> ()->GetCellId (); + Ptr<LteEnbRrc> sourceRrc = sourceEnbDev->GetObject<LteEnbNetDevice> ()->GetRrc (); + uint16_t rnti = ueDev->GetObject<LteUeNetDevice> ()->GetRrc ()->GetRnti (); + sourceRrc->SendHandoverRequest (rnti, targetCellId); +} + +void +LteTapHelper::DeActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice,Ptr<NetDevice> enbDevice, uint8_t bearerId) +{ + NS_LOG_FUNCTION (this << ueDevice << bearerId); + NS_ASSERT_MSG (m_epcHelper != 0, "Dedicated EPS bearers cannot be de-activated when the EPC is not used"); + NS_ASSERT_MSG (bearerId != 1, "Default bearer cannot be de-activated until and unless and UE is released"); + + DoDeActivateDedicatedEpsBearer (ueDevice, enbDevice, bearerId); +} + +void +LteTapHelper::DoDeActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice, uint8_t bearerId) +{ + NS_LOG_FUNCTION (this << ueDevice << bearerId); + + //Extract IMSI and rnti + uint64_t imsi = ueDevice->GetObject<LteUeNetDevice> ()->GetImsi (); + uint16_t rnti = ueDevice->GetObject<LteUeNetDevice> ()->GetRrc ()->GetRnti (); + + + Ptr<LteEnbRrc> enbRrc = enbDevice->GetObject<LteEnbNetDevice> ()->GetRrc (); + + enbRrc->DoSendReleaseDataRadioBearer (imsi,rnti,bearerId); +} + + +void +LteTapHelper::ActivateDataRadioBearer (NetDeviceContainer ueDevices, EpsBearer bearer) +{ + NS_LOG_FUNCTION (this); + for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) + { + ActivateDataRadioBearer (*i, bearer); + } +} + +void +LteTapHelper::EnableLogComponents (void) +{ + LogComponentEnable ("LteTapHelper", LOG_LEVEL_ALL); + LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL); + LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL); + LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL); + LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL); + LogComponentEnable ("LteRlc", LOG_LEVEL_ALL); + LogComponentEnable ("LteRlcUm", LOG_LEVEL_ALL); + LogComponentEnable ("LteRlcAm", LOG_LEVEL_ALL); + LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL); + LogComponentEnable ("PfFfMacScheduler", LOG_LEVEL_ALL); + + LogComponentEnable ("LtePhy", LOG_LEVEL_ALL); + LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL); + LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL); + LogComponentEnable ("LteSpectrumValueHelper", LOG_LEVEL_ALL); + LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL); + LogComponentEnable ("LteInterference", LOG_LEVEL_ALL); + LogComponentEnable ("LteChunkProcessor", LOG_LEVEL_ALL); + + std::string propModelStr = m_dlPathlossModelFactory.GetTypeId ().GetName ().erase (0,5).c_str (); + LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL); + LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL); + LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL); + + LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL); + LogComponentEnable ("LteStatsCalculator", LOG_LEVEL_ALL); + LogComponentEnable ("MacStatsCalculator", LOG_LEVEL_ALL); + LogComponentEnable ("PhyTxStatsCalculator", LOG_LEVEL_ALL); + LogComponentEnable ("PhyRxStatsCalculator", LOG_LEVEL_ALL); + LogComponentEnable ("PhyStatsCalculator", LOG_LEVEL_ALL); + + +} + +void +LteTapHelper::EnableTraces (void) +{ + EnablePhyTraces (); + EnableMacTraces (); + EnableRlcTraces (); + EnablePdcpTraces (); +} + +void +LteTapHelper::EnableRlcTraces (void) +{ + NS_ASSERT_MSG (m_rlcStats == 0, "please make sure that LteTapHelper::EnableRlcTraces is called at most once"); + m_rlcStats = CreateObject<RadioBearerStatsCalculator> ("RLC"); + m_radioBearerStatsConnector.EnableRlcStats (m_rlcStats); +} + +int64_t +LteTapHelper::AssignStreams (NetDeviceContainer c, int64_t stream) +{ + int64_t currentStream = stream; + if ((m_fadingModule != 0) && (m_fadingStreamsAssigned == false)) + { + Ptr<TraceFadingLossModel> tflm = m_fadingModule->GetObject<TraceFadingLossModel> (); + if (tflm != 0) + { + currentStream += tflm->AssignStreams (currentStream); + m_fadingStreamsAssigned = true; + } + } + Ptr<NetDevice> netDevice; + for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + netDevice = (*i); + Ptr<LteEnbNetDevice> lteEnb = DynamicCast<LteEnbNetDevice> (netDevice); + if (lteEnb) + { + Ptr<LteSpectrumPhy> dlPhy = lteEnb->GetPhy ()->GetDownlinkSpectrumPhy (); + Ptr<LteSpectrumPhy> ulPhy = lteEnb->GetPhy ()->GetUplinkSpectrumPhy (); + currentStream += dlPhy->AssignStreams (currentStream); + currentStream += ulPhy->AssignStreams (currentStream); + } + Ptr<LteUeNetDevice> lteUe = DynamicCast<LteUeNetDevice> (netDevice); + if (lteUe) + { + Ptr<LteSpectrumPhy> dlPhy = lteUe->GetPhy ()->GetDownlinkSpectrumPhy (); + Ptr<LteSpectrumPhy> ulPhy = lteUe->GetPhy ()->GetUplinkSpectrumPhy (); + Ptr<LteUeMac> ueMac = lteUe->GetMac (); + currentStream += dlPhy->AssignStreams (currentStream); + currentStream += ulPhy->AssignStreams (currentStream); + currentStream += ueMac->AssignStreams (currentStream); + } + } + return (currentStream - stream); +} + + +void +LteTapHelper::EnablePhyTraces (void) +{ + EnableDlPhyTraces (); + EnableUlPhyTraces (); + EnableDlTxPhyTraces (); + EnableUlTxPhyTraces (); + EnableDlRxPhyTraces (); + EnableUlRxPhyTraces (); +} + +void +LteTapHelper::EnableTxPhyTraces (void) +{ + EnableDlTxPhyTraces (); + EnableUlTxPhyTraces (); +} + + +void +LteTapHelper::NewEnableTxPhyTraces (void) +{ + NewEnableDlTxPhyTraces (); + NewEnableUlTxPhyTraces (); +} +void +LteTapHelper::EnableDlTxPhyTraces (void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/DlPhyTransmission", + MakeBoundCallback (&PhyTxStatsCalculator::DlPhyTransmissionCallback, m_phyTxStats)); +} + +void +LteTapHelper::EnableUlTxPhyTraces (void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/UlPhyTransmission", + MakeBoundCallback (&PhyTxStatsCalculator::UlPhyTransmissionCallback, m_phyTxStats)); +} + +void +LteTapHelper::NewEnableUlTxPhyTraces(void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/UlPhyTransmission", + MakeCallback (&LteTapHelper::WriteUlPhyTransmissionMcsCallback, this)); +} + +void +LteTapHelper::NewEnableDlTxPhyTraces(void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/DlPhyTransmission", + MakeCallback (&LteTapHelper::WriteDlPhyTransmissionMcsCallback, this)); +} + +void +LteTapHelper::WriteDlPhyTransmissionMcsCallback(std::string path, + PhyTransmissionStatParameters params) +{ + NS_LOG_FUNCTION (params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi); + if(m_dlMcsStats.node_id==-1)//new element + { + m_dlMcsStats.node_id=Mcs_stats::Get_node(path); + m_dlMcsStats.avgMcs=(double)(params.m_mcs); + // m_dlMcsStats.avgThroughput=Mcs_stats::ConnvertMcsToRate (params.m_mcs); + m_dlMcsStats.avgThroughput=(double)(params.m_size)/125*2; + } else { + NS_ASSERT( m_dlMcsStats.node_id==Mcs_stats::Get_node(path)); + m_dlMcsStats.avgMcs=(double)(params.m_mcs)*(1-ALPHA)+m_dlMcsStats.avgMcs*ALPHA; + //m_dlMcsStats.avgThroughput=Mcs_stats::ConnvertMcsToRate (params.m_mcs)*(1-ALPHA)+m_dlMcsStats.avgThroughput; + m_dlMcsStats.avgThroughput=(double)(params.m_size)/125*2*(1-ALPHA)+m_dlMcsStats.avgThroughput*ALPHA; + } +} + +void +LteTapHelper::WriteUlPhyTransmissionMcsCallback(std::string path, + PhyTransmissionStatParameters params) +{ + + + NS_LOG_FUNCTION ( params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi); + + int nodeId=Mcs_stats::Get_node(path); + unsigned i; + for(i=0;i<m_ulAllMcsStats.size();i++){ + if(nodeId==m_ulAllMcsStats.at(i).node_id) + break; + } + + if(i==m_ulAllMcsStats.size())//new element + { + Mcs_stats newStats; + newStats.node_id=nodeId; + newStats.avgMcs=(double)(params.m_mcs); + // newStats.avgThroughput=Mcs_stats::ConnvertMcsToRate(params.m_mcs); + newStats.avgThroughput=(double)(params.m_size)/125*2; //Mbp/s + m_ulAllMcsStats.push_back(newStats); + } else { + m_ulAllMcsStats.at(i).avgMcs=(double)(params.m_mcs)*(1-ALPHA)+m_ulAllMcsStats.at(i).avgMcs*ALPHA; + // m_ulAllMcsStats.at(i).avgThroughput=Mcs_stats::ConnvertMcsToRate (params.m_mcs)*(1-ALPHA)+m_ulAllMcsStats.at(i).avgThroughput; + m_ulAllMcsStats.at(i).avgThroughput=(double)(params.m_size)/125*2*(1-ALPHA)+m_ulAllMcsStats.at(i).avgThroughput*ALPHA; + } + + +} + +double +LteTapHelper::GetLtePhyTxRate(int nodeId) +{ + if(m_dlMcsStats.node_id == nodeId) + return m_dlMcsStats.avgThroughput; + + //it is an UE: + unsigned i; + for(i=0; i< m_ulAllMcsStats.size();i++) + { + if(m_ulAllMcsStats.at(i).node_id == nodeId) + return m_ulAllMcsStats.at(i).avgThroughput; + } + + //bad things happened, did not find the station + std::cerr<<"LTE EMULATOR: WARNING: not find node with id="<<nodeId<<" either in downlink or uplink\n"; + return -1; +} + +void +LteTapHelper::EnableDlRxPhyTraces (void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/DlSpectrumPhy/DlPhyReception", + MakeBoundCallback (&PhyRxStatsCalculator::DlPhyReceptionCallback, m_phyRxStats)); +} + +void +LteTapHelper::EnableUlRxPhyTraces (void) +{ + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/UlSpectrumPhy/UlPhyReception", + MakeBoundCallback (&PhyRxStatsCalculator::UlPhyReceptionCallback, m_phyRxStats)); +} + + +void +LteTapHelper::EnableMacTraces (void) +{ + EnableDlMacTraces (); + EnableUlMacTraces (); +} + + +void +LteTapHelper::EnableDlMacTraces (void) +{ + NS_LOG_FUNCTION_NOARGS (); + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbMac/DlScheduling", + MakeBoundCallback (&MacStatsCalculator::DlSchedulingCallback, m_macStats)); +} + +void +LteTapHelper::EnableUlMacTraces (void) +{ + NS_LOG_FUNCTION_NOARGS (); + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbMac/UlScheduling", + MakeBoundCallback (&MacStatsCalculator::UlSchedulingCallback, m_macStats)); +} + +void +LteTapHelper::EnableDlPhyTraces (void) +{ + NS_LOG_FUNCTION_NOARGS (); + Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/ReportCurrentCellRsrpSinr", + MakeBoundCallback (&PhyStatsCalculator::ReportCurrentCellRsrpSinrCallback, m_phyStats)); +} + +void +LteTapHelper::EnableUlPhyTraces (void) +{ + NS_LOG_FUNCTION_NOARGS (); + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/ReportUeSinr", + MakeBoundCallback (&PhyStatsCalculator::ReportUeSinr, m_phyStats)); + Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/ReportInterference", + MakeBoundCallback (&PhyStatsCalculator::ReportInterference, m_phyStats)); + +} + +Ptr<RadioBearerStatsCalculator> +LteTapHelper::GetRlcStats (void) +{ + return m_rlcStats; +} + +void +LteTapHelper::EnablePdcpTraces (void) +{ + NS_ASSERT_MSG (m_pdcpStats == 0, "please make sure that LteTapHelper::EnablePdcpTraces is called at most once"); + m_pdcpStats = CreateObject<RadioBearerStatsCalculator> ("PDCP"); + m_radioBearerStatsConnector.EnablePdcpStats (m_pdcpStats); +} + +Ptr<RadioBearerStatsCalculator> +LteTapHelper::GetPdcpStats (void) +{ + return m_pdcpStats; +} + +} // namespace ns3 diff --git a/emu-radio/lte-emulator/extensions/lte-tap-helper.h b/emu-radio/lte-emulator/extensions/lte-tap-helper.h new file mode 100644 index 00000000..829672c8 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/lte-tap-helper.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LTE_TAP_HELPER_H +#define LTE_TAP_HELPER_H + +#include <ns3/config.h> +#include <ns3/simulator.h> +#include <ns3/names.h> +#include <ns3/net-device.h> +#include <ns3/net-device-container.h> +#include <ns3/node.h> +#include <ns3/node-container.h> +#include <ns3/eps-bearer.h> +#include <ns3/phy-stats-calculator.h> +#include <ns3/phy-tx-stats-calculator.h> +#include <ns3/phy-rx-stats-calculator.h> +#include <ns3/mac-stats-calculator.h> +#include <ns3/radio-bearer-stats-calculator.h> +#include <ns3/radio-bearer-stats-connector.h> +#include <ns3/epc-tft.h> +#include <ns3/mobility-model.h> + +#include <vector> + +/** + * \brief this file has been modified from the original one in ns3 lte module to support emulation of LTE channel, more specifically to support tap device functionality + */ + + +namespace ns3 { + + +class LteUePhy; +class LteEnbPhy; +class SpectrumChannel; +class EpcHelper; +class PropagationLossModel; +class SpectrumPropagationLossModel; + +/** + * \ingroup lte + * + * Creation and configuration of LTE entities. One LteHelper instance is + * typically enough for an LTE simulation. To create it: + * + * Ptr<LteHelper> lteHelper = CreateObject<LteHelper> (); + * + * The general responsibility of the helper is to create various LTE objects + * and arrange them together to make the whole LTE system. The overall + * arrangement would look like the following: + * - Downlink spectrum channel + * + Path loss model + * + Fading model + * - Uplink spectrum channel + * + Path loss model + * + Fading model + * - eNodeB node(s) + * + Mobility model + * + eNodeB device(s) + * * Antenna model + * * eNodeB PHY (includes spectrum PHY, interference model, HARQ model) + * * eNodeB MAC + * * eNodeB RRC (includes RRC protocol) + * * Scheduler + * * Handover algorithm + * * FFR (frequency reuse) algorithm + * * ANR (automatic neighbour relation) + * + EPC related models (EPC application, Internet stack, X2 interface) + * - UE node(s) + * + Mobility model + * + UE device(s) + * * Antenna model + * * UE PHY (includes spectrum PHY, interference model, HARQ model) + * * UE MAC + * * UE RRC (includes RRC protocol) + * * NAS + * - EPC helper + * - Various statistics calculator objects + * + * Spetrum channels are created automatically: one for DL, and one for UL. + * eNodeB devices are created by calling InstallEnbDevice(), while UE devices + * are created by calling InstallUeDevice(). EPC helper can be set by using + * SetEpcHelper(). + */ +class LteTapHelper : public Object +{ +public: + LteTapHelper (void); + virtual ~LteTapHelper (void); + //for lurch output + double GetLtePhyTxRate (int nodeId); + + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId (void); + virtual void DoDispose (void); + + /** + * Set the EpcHelper to be used to setup the EPC network in + * conjunction with the setup of the LTE radio access network. + * + * \note if no EpcHelper is ever set, then LteHelper will default + * to creating an LTE-only simulation with no EPC, using LteRlcSm as + * the RLC model, and without supporting any IP networking. In other + * words, it will be a radio-level simulation involving only LTE PHY + * and MAC and the FF Scheduler, with a saturation traffic model for + * the RLC. + * + * \param h a pointer to the EpcHelper to be used + */ + void SetEpcHelper (Ptr<EpcHelper> h); + + /** + * Set the type of path loss model to be used for both DL and UL channels. + * + * \param type type of path loss model, must be a type name of any class + * inheriting from ns3::PropagationLossModel, for example: + * "ns3::FriisPropagationLossModel" + */ + void SetPathlossModelType (std::string type); + + /** + * Set an attribute for the path loss models to be created. + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetPathlossModelAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of scheduler to be used by eNodeB devices. + * + * \param type type of scheduler, must be a type name of any class + * inheriting from ns3::FfMacScheduler, for example: + * "ns3::PfFfMacScheduler" + * + * Equivalent with setting the `Scheduler` attribute. + */ + void SetSchedulerType (std::string type); + + /** + * + * \return the scheduler type + */ + std::string GetSchedulerType () const; + + /** + * Set an attribute for the scheduler to be created. + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetSchedulerAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of FFR algorithm to be used by eNodeB devices. + * + * \param type type of FFR algorithm, must be a type name of any class + * inheriting from ns3::LteFfrAlgorithm, for example: + * "ns3::LteFrNoOpAlgorithm" + * + * Equivalent with setting the `FfrAlgorithm` attribute. + */ + void SetFfrAlgorithmType (std::string type); + + /** + * + * \return the FFR algorithm type + */ + std::string GetFfrAlgorithmType () const; + + /** + * Set an attribute for the FFR algorithm to be created. + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetFfrAlgorithmAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of handover algorithm to be used by eNodeB devices. + * + * \param type type of handover algorithm, must be a type name of any class + * inheriting from ns3::LteHandoverAlgorithm, for example: + * "ns3::NoOpHandoverAlgorithm" + * + * Equivalent with setting the `HandoverAlgorithm` attribute. + */ + void SetHandoverAlgorithmType (std::string type); + + /** + * + * \return the handover algorithm type + */ + std::string GetHandoverAlgorithmType () const; + + /** + * Set an attribute for the handover algorithm to be created. + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetHandoverAlgorithmAttribute (std::string n, const AttributeValue &v); + + /** + * Set an attribute for the eNodeB devices (LteEnbNetDevice) to be created. + * + * \param n the name of the attribute. + * \param v the value of the attribute + */ + void SetEnbDeviceAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of antenna model to be used by eNodeB devices. + * + * \param type type of antenna model, must be a type name of any class + * inheriting from ns3::AntennaModel, for example: + * "ns3::IsotropicAntennaModel" + */ + void SetEnbAntennaModelType (std::string type); + + /** + * Set an attribute for the eNodeB antenna model to be created. + * + * \param n the name of the attribute. + * \param v the value of the attribute + */ + void SetEnbAntennaModelAttribute (std::string n, const AttributeValue &v); + + /** + * Set an attribute for the UE devices (LteUeNetDevice) to be created. + * + * \param n the name of the attribute. + * \param v the value of the attribute + */ + void SetUeDeviceAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of antenna model to be used by UE devices. + * + * \param type type of antenna model, must be a type name of any class + * inheriting from ns3::AntennaModel, for example: + * "ns3::IsotropicAntennaModel" + */ + void SetUeAntennaModelType (std::string type); + + /** + * Set an attribute for the UE antenna model to be created. + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetUeAntennaModelAttribute (std::string n, const AttributeValue &v); + + /** + * Set the type of spectrum channel to be used in both DL and UL. + * + * \param type type of spectrum channel model, must be a type name of any + * class inheriting from ns3::SpectrumChannel, for example: + * "ns3::MultiModelSpectrumChannel" + */ + void SetSpectrumChannelType (std::string type); + + /** + * Set an attribute for the spectrum channel to be created (both DL and UL). + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetSpectrumChannelAttribute (std::string n, const AttributeValue &v); + + /** + * Create a set of eNodeB devices. + * + * \param c the node container where the devices are to be installed + * \return the NetDeviceContainer with the newly created devices + */ + NetDeviceContainer InstallEnbDevice (NodeContainer c); + + /** + * Create a set of UE devices. + * + * \param c the node container where the devices are to be installed + * \return the NetDeviceContainer with the newly created devices + */ + NetDeviceContainer InstallUeDevice (NodeContainer c); + + /** + * \brief Enables automatic attachment of a set of UE devices to a suitable + * cell using Idle mode initial cell selection procedure. + * \param ueDevices the set of UE devices to be attached + * + * By calling this, the UE will start the initial cell selection procedure at + * the beginning of simulation. In addition, the function also instructs each + * UE to immediately enter CONNECTED mode and activates the default EPS + * bearer. + * + * If this function is called when the UE is in a situation where entering + * CONNECTED mode is not possible (e.g. before the simulation begin), then the + * UE will attempt to connect at the earliest possible time (e.g. after it + * camps to a suitable cell). + * + * Note that this function can only be used in EPC-enabled simulation. + */ + void Attach (NetDeviceContainer ueDevices); + + /** + * \brief Enables automatic attachment of a UE device to a suitable cell + * using Idle mode initial cell selection procedure. + * \param ueDevice the UE device to be attached + * + * By calling this, the UE will start the initial cell selection procedure at + * the beginning of simulation. In addition, the function also instructs the + * UE to immediately enter CONNECTED mode and activates the default EPS + * bearer. + * + * If this function is called when the UE is in a situation where entering + * CONNECTED mode is not possible (e.g. before the simulation begin), then the + * UE will attempt to connect at the earliest possible time (e.g. after it + * camps to a suitable cell). + * + * Note that this function can only be used in EPC-enabled simulation. + */ + void Attach (Ptr<NetDevice> ueDevice); + + /** + * \brief Manual attachment of a set of UE devices to the network via a given + * eNodeB. + * \param ueDevices the set of UE devices to be attached + * \param enbDevice the destination eNodeB device + * + * In addition, the function also instructs each UE to immediately enter + * CONNECTED mode and activates the default EPS bearer. + * + * The function can be used in both LTE-only and EPC-enabled simulations. + * Note that this function will disable Idle mode initial cell selection + * procedure. + */ + void Attach (NetDeviceContainer ueDevices, Ptr<NetDevice> enbDevice); + + /** + * \brief Manual attachment of a UE device to the network via a given eNodeB. + * \param ueDevice the UE device to be attached + * \param enbDevice the destination eNodeB device + * + * In addition, the function also instructs the UE to immediately enter + * CONNECTED mode and activates the default EPS bearer. + * + * The function can be used in both LTE-only and EPC-enabled simulations. + * Note that this function will disable Idle mode initial cell selection + * procedure. + */ + void Attach (Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice); + + /** + * \brief Manual attachment of a set of UE devices to the network via the + * closest eNodeB (with respect to distance) among those in the set. + * \param ueDevices the set of UE devices to be attached + * \param enbDevices the set of eNodeB devices to be considered + * + * This function finds among the eNodeB set the closest eNodeB for each UE, + * and then invokes manual attachment between the pair. + * + * Users are encouraged to use automatic attachment (Idle mode cell selection) + * instead of this function. + * + * \sa LteHelper::Attach(NetDeviceContainer ueDevices); + */ + void AttachToClosestEnb (NetDeviceContainer ueDevices, NetDeviceContainer enbDevices); + + /** + * \brief Manual attachment of a UE device to the network via the closest + * eNodeB (with respect to distance) among those in the set. + * \param ueDevice the UE device to be attached + * \param enbDevices the set of eNodeB devices to be considered + * + * This function finds among the eNodeB set the closest eNodeB for the UE, + * and then invokes manual attachment between the pair. + * + * Users are encouraged to use automatic attachment (Idle mode cell selection) + * instead of this function. + * + * \sa LteHelper::Attach(Ptr<NetDevice> ueDevice); + */ + void AttachToClosestEnb (Ptr<NetDevice> ueDevice, NetDeviceContainer enbDevices); + + /** + * Activate a dedicated EPS bearer on a given set of UE devices. + * + * \param ueDevices the set of UE devices + * \param bearer the characteristics of the bearer to be activated + * \param tft the Traffic Flow Template that identifies the traffic to go on this bearer + */ + uint8_t ActivateDedicatedEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer, Ptr<EpcTft> tft); + + /** + * Activate a dedicated EPS bearer on a given UE device. + * + * \param ueDevice the UE device + * \param bearer the characteristics of the bearer to be activated + * \param tft the Traffic Flow Template that identifies the traffic to go on this bearer. + */ + uint8_t ActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice, EpsBearer bearer, Ptr<EpcTft> tft); + + /** + * \brief Manually trigger dedicated bearer de-activation at specific simulation time + * \param ueDevice the UE on which dedicated bearer to be de-activated must be of the type LteUeNetDevice + * \param enbDevice eNB, must be of the type LteEnbNetDevice + * \param bearerId Bearer Identity which is to be de-activated + * + * \warning Requires the use of EPC mode. See SetEpcHelper() method. + */ + + void DeActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice, uint8_t bearerId); + /** + * Create an X2 interface between all the eNBs in a given set. + * + * \param enbNodes the set of eNB nodes + */ + void AddX2Interface (NodeContainer enbNodes); + + /** + * Create an X2 interface between two eNBs. + * + * \param enbNode1 one eNB of the X2 interface + * \param enbNode2 the other eNB of the X2 interface + */ + void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2); + + /** + * Manually trigger an X2-based handover. + * + * \param hoTime when the handover shall be initiated + * \param ueDev the UE that hands off, must be of the type LteUeNetDevice + * \param sourceEnbDev source eNB, must be of the type LteEnbNetDevice + * (originally the UE is attached to this eNB) + * \param targetEnbDev target eNB, must be of the type LteEnbNetDevice + * (the UE would be connected to this eNB after the + * handover) + * + * \warning Requires the use of EPC mode. See SetEpcHelper() method + */ + void HandoverRequest (Time hoTime, Ptr<NetDevice> ueDev, + Ptr<NetDevice> sourceEnbDev, Ptr<NetDevice> targetEnbDev); + + + /** + * Activate a Data Radio Bearer on a given UE devices (for LTE-only simulation). + * + * \param ueDevices the set of UE devices + * \param bearer the characteristics of the bearer to be activated + */ + void ActivateDataRadioBearer (NetDeviceContainer ueDevices, EpsBearer bearer); + + /** + * Activate a Data Radio Bearer on a UE device (for LTE-only simulation). + * This method will schedule the actual activation + * the bearer so that it happens after the UE got connected. + * + * \param ueDevice the UE device + * \param bearer the characteristics of the bearer to be activated + */ + void ActivateDataRadioBearer (Ptr<NetDevice> ueDevice, EpsBearer bearer); + + /** + * Set the type of fading model to be used in both DL and UL. + * + * \param type type of fading model, must be a type name of any class + * inheriting from ns3::SpectrumPropagationLossModel, for + * example: "ns3::TraceFadingLossModel" + */ + void SetFadingModel (std::string type); + + /** + * Set an attribute for the fading model to be created (both DL and UL). + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetFadingModelAttribute (std::string n, const AttributeValue &v); + + /** + * Enables full-blown logging for major components of the LENA architecture. + */ + void EnableLogComponents (void); + + /** + * Enables trace sinks for PHY, MAC, RLC and PDCP. To make sure all nodes are + * traced, traces should be enabled once all UEs and eNodeBs are in place and + * connected, just before starting the simulation. + */ + void EnableTraces (void); + + /** + * Enable trace sinks for PHY layer. + */ + void EnablePhyTraces (void); + + /** + * NOTE: for lurch, added to only enable physical layer transmission traces only in order to track the mcs used by physical layer. + */ + void EnableTxPhyTraces(void); + + /** + * NOTE:for lurch, added to only enable physical layer transmission traces only and making time average + */ + void NewEnableTxPhyTraces(void); + + /** + * Enable trace sinks for DL PHY layer. + */ + void EnableDlPhyTraces (void); + + /** + * Enable trace sinks for UL PHY layer. + */ + void EnableUlPhyTraces (void); + + /** + * Enable trace sinks for DL transmission PHY layer. + */ + void EnableDlTxPhyTraces (void); + + /** + * Enable trace sinks for UL transmission PHY layer. + */ + void EnableUlTxPhyTraces (void); + + /** + * Enable trace sinks for DL reception PHY layer. + */ + void EnableDlRxPhyTraces (void); + + /** + * Enable trace sinks for UL reception PHY layer. + */ + void EnableUlRxPhyTraces (void); + + /** + * Enable trace sinks for MAC layer. + */ + void EnableMacTraces (void); + + /** + * Enable trace sinks for DL MAC layer. + */ + void EnableDlMacTraces (void); + + /** + * Enable trace sinks for UL MAC layer. + */ + void EnableUlMacTraces (void); + + /** + * Enable trace sinks for RLC layer. + */ + void EnableRlcTraces (void); + + /** + * + * \return the RLC stats calculator object + */ + Ptr<RadioBearerStatsCalculator> GetRlcStats (void); + + /** + * Enable trace sinks for PDCP layer + */ + void EnablePdcpTraces (void); + + /** + * + * \return the PDCP stats calculator object + */ + Ptr<RadioBearerStatsCalculator> GetPdcpStats (void); + + /** + * Assign a fixed random variable stream number to the random variables used. + * + * The InstallEnbDevice() or InstallUeDevice method should have previously + * been called by the user on the given devices. + * + * If TraceFadingLossModel has been set as the fading model type, this method + * will also assign a stream number to it, if none has been assigned before. + * + * \param c NetDeviceContainer of the set of net devices for which the + * LteNetDevice should be modified to use a fixed stream + * \param stream first stream index to use + * \return the number of stream indices (possibly zero) that have been assigned + */ + int64_t AssignStreams (NetDeviceContainer c, int64_t stream); + +protected: + // inherited from Object + virtual void DoInitialize (void); + +private: + /** + * Create an eNodeB device (LteEnbNetDevice) on the given node. + * \param n the node where the device is to be installed + * \return pointer to the created device + */ + Ptr<NetDevice> InstallSingleEnbDevice (Ptr<Node> n); + + /** + * Create a UE device (LteUeNetDevice) on the given node + * \param n the node where the device is to be installed + * \return pointer to the created device + */ + Ptr<NetDevice> InstallSingleUeDevice (Ptr<Node> n); + + /** + * The actual function to trigger a manual handover. + * \param ueDev the UE that hands off, must be of the type LteUeNetDevice + * \param sourceEnbDev source eNB, must be of the type LteEnbNetDevice + * (originally the UE is attached to this eNB) + * \param targetEnbDev target eNB, must be of the type LteEnbNetDevice + * (the UE would be connected to this eNB after the + * handover) + * + * This method is normally scheduled by HandoverRequest() to run at a specific + * time where a manual handover is desired by the simulation user. + */ + void DoHandoverRequest (Ptr<NetDevice> ueDev, + Ptr<NetDevice> sourceEnbDev, + Ptr<NetDevice> targetEnbDev); + + + /** + * \brief The actual function to trigger a manual bearer de-activation + * \param ueDevice the UE on which bearer to be de-activated must be of the type LteUeNetDevice + * \param enbDevice eNB, must be of the type LteEnbNetDevice + * \param bearerId Bearer Identity which is to be de-activated + * + * This method is normally scheduled by DeActivateDedicatedEpsBearer() to run at a specific + * time when a manual bearer de-activation is desired by the simulation user. + */ + void DoDeActivateDedicatedEpsBearer (Ptr<NetDevice> ueDevice, Ptr<NetDevice> enbDevice, uint8_t bearerId); + + /// The downlink LTE channel used in the simulation. + Ptr<SpectrumChannel> m_downlinkChannel; + /// The uplink LTE channel used in the simulation. + Ptr<SpectrumChannel> m_uplinkChannel; + /// The path loss model used in the downlink channel. + Ptr<Object> m_downlinkPathlossModel; + /// The path loss model used in the uplink channel. + Ptr<Object> m_uplinkPathlossModel; + + /// Factory of MAC scheduler object. + ObjectFactory m_schedulerFactory; + /// Factory of FFR (frequency reuse) algorithm object. + ObjectFactory m_ffrAlgorithmFactory; + /// Factory of handover algorithm object. + ObjectFactory m_handoverAlgorithmFactory; + /// Factory of LteEnbNetDevice objects. + ObjectFactory m_enbNetDeviceFactory; + /// Factory of antenna object for eNodeB. + ObjectFactory m_enbAntennaModelFactory; + /// Factory for LteUeNetDevice objects. + ObjectFactory m_ueNetDeviceFactory; + /// Factory of antenna object for UE. + ObjectFactory m_ueAntennaModelFactory; + /// Factory of path loss model object for the downlink channel. + ObjectFactory m_dlPathlossModelFactory; + /// Factory of path loss model object for the uplink channel. + ObjectFactory m_ulPathlossModelFactory; + /// Factory of both the downlink and uplink LTE channels. + ObjectFactory m_channelFactory; + + /// Name of fading model type, e.g., "ns3::TraceFadingLossModel". + std::string m_fadingModelType; + /// Factory of fading model object for both the downlink and uplink channels. + ObjectFactory m_fadingModelFactory; + /// The fading model used in both the downlink and uplink channels. + Ptr<SpectrumPropagationLossModel> m_fadingModule; + /** + * True if a random variable stream number has been assigned for the fading + * model. Used to prevent such assignment to be done more than once. + */ + bool m_fadingStreamsAssigned; + + /// Container of PHY layer statistics. + Ptr<PhyStatsCalculator> m_phyStats; + /// Container of PHY layer statistics related to transmission. + Ptr<PhyTxStatsCalculator> m_phyTxStats; + /// Container of PHY layer statistics related to reception. + Ptr<PhyRxStatsCalculator> m_phyRxStats; + /// Container of MAC layer statistics. + Ptr<MacStatsCalculator> m_macStats; + /// Container of RLC layer statistics. + Ptr<RadioBearerStatsCalculator> m_rlcStats; + /// Container of PDCP layer statistics. + Ptr<RadioBearerStatsCalculator> m_pdcpStats; + /// Connects RLC and PDCP statistics containers to appropriate trace sources + RadioBearerStatsConnector m_radioBearerStatsConnector; + + /** + * Helper which provides implementation of core network. Initially empty + * (i.e., LTE-only simulation without any core network) and then might be + * set using SetEpcHelper(). + */ + Ptr<EpcHelper> m_epcHelper; + + /** + * Keep track of the number of IMSI allocated. Increases by one every time a + * new UE is installed (by InstallSingleUeDevice()). The first UE will have + * an IMSI of 1. The maximum number of UE is 2^64 (~4.2e9). + */ + uint64_t m_imsiCounter; + /** + * Keep track of the number of cell ID allocated. Increases by one every time + * a new eNodeB is installed (by InstallSingleEnbDevice()). The first eNodeB + * will have a cell ID of 1. The maximum number of eNodeB is 65535. + */ + uint16_t m_cellIdCounter; + + /** + * The `UseIdealRrc` attribute. If true, LteRrcProtocolIdeal will be used for + * RRC signaling. If false, LteRrcProtocolReal will be used. + */ + bool m_useIdealRrc; + /** + * The `AnrEnabled` attribute. Activate or deactivate Automatic Neighbour + * Relation function. + */ + bool m_isAnrEnabled; + /** + * The `UsePdschForCqiGeneration` attribute. If true, DL-CQI will be + * calculated from PDCCH as signal and PDSCH as interference. If false, + * DL-CQI will be calculated from PDCCH as signal and PDCCH as interference. + */ + bool m_usePdschForCqiGeneration; + + ///////////////////////////////////////////////////////////////////////////////////////////// + // for communicating statistics to lurch // + ///////////////////////////////////////////////////////////////////////////////////////////// + void WriteUlPhyTransmissionMcsCallback(std::string path, PhyTransmissionStatParameters params); + void WriteDlPhyTransmissionMcsCallback(std::string path, PhyTransmissionStatParameters params); + +private: + + //added for lurch + void + NewEnableUlTxPhyTraces (void); + + void + NewEnableDlTxPhyTraces (void); + //end + + struct Mcs_stats{ + Mcs_stats() + :avgMcs (0.0) + ,avgThroughput (0.0) + ,node_id (-1) + {} + + static + int ConnvertMcsToRate(int mcs) + { + return 1; + } + + /*get node id from the config path*/ + static + int Get_node(std::string path) + { + size_t pos1=0, pos2=0; + pos1 = path.find ("/",pos1); + pos1 = path.find ("/",pos1+1); + pos2 = path.find ("/",pos1+1); + return atoi (path.substr (pos1+1,pos2-(pos1+1)).c_str()); + } + + double avgMcs; + double avgThroughput; + int node_id; + }; + + /// downlink Tx mcs statistics + Mcs_stats m_dlMcsStats; + + ///uplink Tx mcs statistics + std::vector<Mcs_stats> m_ulAllMcsStats; + + +}; // end of `class LteHelper` + + +} // namespace ns3 + + + +#endif // LTE_HELPER_H diff --git a/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.cc b/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.cc new file mode 100644 index 00000000..1d858f57 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lte-tap-ue-net-device.h" + +#include <ns3/llc-snap-header.h> +#include <ns3/simulator.h> +#include <ns3/callback.h> +#include <ns3/node.h> +#include <ns3/packet.h> +#include <ns3/lte-net-device.h> +#include <ns3/packet-burst.h> +#include <ns3/uinteger.h> +#include <ns3/trace-source-accessor.h> +#include <ns3/pointer.h> +#include <ns3/enum.h> +#include <ns3/lte-amc.h> +#include <ns3/ipv4-header.h> +#include <ns3/lte-radio-bearer-tag.h> +#include <ns3/ipv4-l3-protocol.h> +#include <ns3/log.h> + +//NOTE: this is used to handle the arp request. actually this is an hack +#include <ns3/arp-l3-protocol.h> +#include <ns3/arp-header.h> + +#include <ns3/lte-enb-net-device.h> + +/** + * \brief LteTapUeNetDevice class extends lteUeNetDevice class to support emulation of lte channel + */ + +namespace ns3 { +NS_LOG_COMPONENT_DEFINE ("LteTapUeNetDevice"); + +NS_OBJECT_ENSURE_REGISTERED ( LteTapUeNetDevice); + +//////////////////////////////// +// LteTapUeNetDevice +//////////////////////////////// + +TypeId LteTapUeNetDevice::GetTypeId (void) +{ + static TypeId + tid = + TypeId ("ns3::LteTapUeNetDevice") + + .SetParent<LteUeNetDevice> () + .AddConstructor<LteTapUeNetDevice>() + ; + return tid; +} + +LteTapUeNetDevice::LteTapUeNetDevice() + : m_virtualAddress(Mac48Address::Allocate()) +{ + +} + + +void +LteTapUeNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb) +{ + NS_LOG_FUNCTION (this); +// NS_LOG_WARN ("Promisc mode not supported"); + + /** NOTE: set the promisc callback to be compatable with tap bridge + */ + m_promiscRx = cb; +} + + +void +LteTapUeNetDevice::Receive (Ptr<Packet> p) +{ + NS_LOG_FUNCTION (this << p); + m_rxCallback (this, p, Ipv4L3Protocol::PROT_NUMBER, Address ()); + + /** NOTE: added for comptabability with tapbridge + */ + if (!m_promiscRx.IsNull ()) + { + Mac48Address from = Mac48Address::ConvertFrom (GetAddress()); + Mac48Address to = m_vmMacAdress; + + enum NetDevice::PacketType type = NetDevice::PACKET_HOST; + m_promiscRx (this, p, Ipv4L3Protocol::PROT_NUMBER, from, to, type); + } +} + +bool +LteTapUeNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (this << dest << protocolNumber); + if(protocolNumber== ArpL3Protocol::PROT_NUMBER) + { + Ptr<Packet> p=packet->Copy(); + ArpHeader arp; + uint32_t size = p->RemoveHeader (arp); + if (size == 0) + { + NS_LOG_LOGIC ("lte ue received ARP: but Cannot remove ARP header"); + return true; + } + + if (!arp.IsRequest ()) + { + NS_LOG_LOGIC ("received arp packet is not arp request, don't react to act it"); + return true; + } + + //check if ip source address of arp request equal to that of this lte device. If NOT, don't send reply + Ipv4Address lteDeviceIpAddress = GetNode ()->GetObject<Ipv4> () + ->GetAddress (1, 0) + .GetLocal (); + if (arp.GetSourceIpv4Address () != lteDeviceIpAddress || arp.GetDestinationIpv4Address () != m_bsIpAddress) + return true; + + Ipv4Address myIp = arp.GetDestinationIpv4Address (); + Ipv4Address toIp = arp.GetSourceIpv4Address (); + Address toMac = arp.GetSourceHardwareAddress (); + + //generate arp reply + ArpHeader replyArp; + replyArp.SetReply (m_virtualAddress, myIp, toMac, toIp); + Ptr <Packet> replyPacket = Create<Packet> (); + replyPacket->AddHeader (replyArp); + enum NetDevice::PacketType type = NetDevice::PACKET_HOST; + + m_promiscRx (this, replyPacket, ArpL3Protocol::PROT_NUMBER, m_virtualAddress, m_vmMacAdress, type); + + return true; + } + + return LteUeNetDevice::Send (packet, dest, protocolNumber); +} + +} diff --git a/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.h b/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.h new file mode 100644 index 00000000..7e09e4c1 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/lte-tap-ue-net-device.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LTE_TAP_UE_NET_DEVICE_H +#define LTE_TAP_UE_NET_DEVICE_H + +#include <ns3/lte-ue-net-device.h> + +/** + * \brief LteTapUeNetDevice class extends lteUeNetDevice class to support emulation of lte channel + */ + +namespace ns3 { + + +/** + * \defgroup lte LTE Models + * + */ + +/** + * \ingroup lte + * + * LteTapUeNetDevice overides the receive logic and overides SetPromiscReceiveCallback of class lteUeNetDevice, + * to make it compatable with tapbridge emulation + */ +class LteTapUeNetDevice : public LteUeNetDevice +{ +public: + static TypeId GetTypeId (void); + virtual void Receive (Ptr <Packet> p); + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + LteTapUeNetDevice (void); + + //overwrite the implementation in LteUeNetDevice in order to deal with arp request + virtual bool Send (Ptr <Packet> packet, const Address &dest, uint16_t protocolNumber); + + //TODO optional? if related tap device resides on Container + void setMacAdressOnVM (Mac48Address vmMacAddress) + { + m_vmMacAdress = vmMacAddress; + } + + void setBsIpAddress (Ipv4Address bsIp) + { + m_bsIpAddress = bsIp; + } + + protected: + NetDevice::PromiscReceiveCallback m_promiscRx; + Mac48Address m_vmMacAdress; + //used for generating arp reply only + Mac48Address m_virtualAddress; + Ipv4Address m_bsIpAddress; +}; + +} // namespace ns3 + +#endif /* LTE_TAP_UE_NET_DEVICE_H */ diff --git a/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.cc b/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.cc new file mode 100644 index 00000000..66e86f55 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.cc @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "tap-point-to-point-epc-helper.h" +#include <ns3/log.h> +#include <ns3/inet-socket-address.h> +#include <ns3/mac48-address.h> +#include <ns3/eps-bearer.h> +#include <ns3/ipv4-address.h> +#include <ns3/internet-stack-helper.h> +#include <ns3/point-to-point-helper.h> +#include <ns3/packet-socket-helper.h> +#include <ns3/packet-socket-address.h> +#include <ns3/epc-enb-application.h> +#include <ns3/epc-sgw-pgw-application.h> + +#include <ns3/lte-enb-rrc.h> +#include <ns3/epc-x2.h> +#include <ns3/lte-enb-net-device.h> +#include <ns3/lte-ue-net-device.h> +#include <ns3/epc-mme.h> +#include <ns3/epc-ue-nas.h> + +/** + * NOTE: TapPointToPointEpcHelper is modified from PointToPointEpcHelper in ns3 lte module to support + * tap device used with lte device and configuration of UE IP address + */ + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("TapPointToPointEpcHelper"); + +NS_OBJECT_ENSURE_REGISTERED (TapPointToPointEpcHelper); + +TapPointToPointEpcHelper::TapPointToPointEpcHelper (std::string ueSubnetAddr,std::string ueSubnetMask, uint32_t id) + : m_gtpuUdpPort (2152) // fixed by the standard +{ + NS_LOG_FUNCTION (this); + + // since we use point-to-point links for all S1-U links, + // we use a /30 subnet which can hold exactly two addresses + // (remember that net broadcast and null address are not valid) + m_s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252"); + + m_x2Ipv4AddressHelper.SetBase ("12.0.0.0", "255.255.255.252"); + + // we use a /8 net for all UEs + m_ueAddressHelper.SetBase (ueSubnetAddr.c_str (), ueSubnetMask.c_str (), Ipv4Address (id)); + + // create SgwPgwNode + m_sgwPgw = CreateObject<Node> (); + InternetStackHelper internet; + internet.Install (m_sgwPgw); + + // create S1-U socket + Ptr<Socket> sgwPgwS1uSocket = Socket::CreateSocket (m_sgwPgw, TypeId::LookupByName ("ns3::UdpSocketFactory")); + int retval = sgwPgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort)); + NS_ASSERT (retval == 0); + + // create TUN device implementing tunneling of user data over GTP-U/UDP/IP + m_tunDevice = CreateObject<VirtualNetDevice> (); + // allow jumbo packets + m_tunDevice->SetAttribute ("Mtu", UintegerValue (30000)); + + // yes we need this + m_tunDevice->SetAddress (Mac48Address::Allocate ()); + + m_sgwPgw->AddDevice (m_tunDevice); + NetDeviceContainer tunDeviceContainer; + tunDeviceContainer.Add (m_tunDevice); + + // the TUN device is on the same subnet as the UEs, so when a packet + // addressed to an UE arrives at the intenet to the WAN interface of + // the PGW it will be forwarded to the TUN device. + Ipv4InterfaceContainer tunDeviceIpv4IfContainer = m_ueAddressHelper.Assign (tunDeviceContainer); + + // create EpcSgwPgwApplication + m_sgwPgwApp = CreateObject<EpcSgwPgwApplication> (m_tunDevice, sgwPgwS1uSocket); + m_sgwPgw->AddApplication (m_sgwPgwApp); + + // connect SgwPgwApplication and virtual net device for tunneling + m_tunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromTunDevice, m_sgwPgwApp)); + + // Create MME and connect with SGW via S11 interface + m_mme = CreateObject<EpcMme> (); + m_mme->SetS11SapSgw (m_sgwPgwApp->GetS11SapSgw ()); + m_sgwPgwApp->SetS11SapMme (m_mme->GetS11SapMme ()); +} + +TapPointToPointEpcHelper::~TapPointToPointEpcHelper () +{ + NS_LOG_FUNCTION (this); +} + +TypeId +TapPointToPointEpcHelper::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TapPointToPointEpcHelper") + .SetParent<EpcHelper> () + .SetGroupName("Lte") + .AddConstructor<TapPointToPointEpcHelper> () + .AddAttribute ("S1uLinkDataRate", + "The data rate to be used for the next S1-U link to be created", + DataRateValue (DataRate ("1Gb/s")), + MakeDataRateAccessor (&TapPointToPointEpcHelper::m_s1uLinkDataRate), + MakeDataRateChecker ()) + .AddAttribute ("S1uLinkDelay", + "The delay to be used for the next S1-U link to be created", + TimeValue (Seconds (0)), + MakeTimeAccessor (&TapPointToPointEpcHelper::m_s1uLinkDelay), + MakeTimeChecker ()) + .AddAttribute ("S1uLinkMtu", + "The MTU of the next S1-U link to be created. Note that, because of the additional GTP/UDP/IP tunneling overhead, you need a MTU larger than the end-to-end MTU that you want to support.", + UintegerValue (2000), + MakeUintegerAccessor (&TapPointToPointEpcHelper::m_s1uLinkMtu), + MakeUintegerChecker<uint16_t> ()) + .AddAttribute ("X2LinkDataRate", + "The data rate to be used for the next X2 link to be created", + DataRateValue (DataRate ("1Gb/s")), + MakeDataRateAccessor (&TapPointToPointEpcHelper::m_x2LinkDataRate), + MakeDataRateChecker ()) + .AddAttribute ("X2LinkDelay", + "The delay to be used for the next X2 link to be created", + TimeValue (Seconds (0)), + MakeTimeAccessor (&TapPointToPointEpcHelper::m_x2LinkDelay), + MakeTimeChecker ()) + .AddAttribute ("X2LinkMtu", + "The MTU of the next X2 link to be created. Note that, because of some big X2 messages, you need a big MTU.", + UintegerValue (3000), + MakeUintegerAccessor (&TapPointToPointEpcHelper::m_x2LinkMtu), + MakeUintegerChecker<uint16_t> ()) + ; + return tid; +} + +void +TapPointToPointEpcHelper::DoDispose () +{ + NS_LOG_FUNCTION (this); + m_tunDevice->SetSendCallback (MakeNullCallback<bool, Ptr<Packet>, const Address&, const Address&, uint16_t> ()); + m_tunDevice = 0; + m_sgwPgwApp = 0; + m_sgwPgw->Dispose (); +} + + +void +TapPointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId) +{ + NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId); + + NS_ASSERT (enb == lteEnbNetDevice->GetNode ()); + + // add an IPv4 stack to the previously created eNB + InternetStackHelper internet; + internet.Install (enb); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject<Ipv4> () + ->GetNInterfaces ()); + + // create a point to point link between the new eNB and the SGW with + // the corresponding new NetDevices on each side + NodeContainer enbSgwNodes; + enbSgwNodes.Add (m_sgwPgw); + enbSgwNodes.Add (enb); + PointToPointHelper p2ph; + p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s1uLinkDataRate)); + p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s1uLinkMtu)); + p2ph.SetChannelAttribute ("Delay", TimeValue (m_s1uLinkDelay)); + NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_sgwPgw); + + //TODO********** +// AsciiTraceHelper ascii; +// p2ph.EnableAscii (ascii.CreateFileStream ("p2p-debug.tr"), enbSgwDevices ); + + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ()); + Ptr<NetDevice> enbDev = enbSgwDevices.Get (0); + Ptr<NetDevice> sgwDev = enbSgwDevices.Get (1); + m_s1uIpv4AddressHelper.NewNetwork (); + Ipv4InterfaceContainer enbSgwIpIfaces = m_s1uIpv4AddressHelper.Assign (enbSgwDevices); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after assigning Ipv4 addr to S1 dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ()); + + Ipv4Address enbAddress = enbSgwIpIfaces.GetAddress (0); + Ipv4Address sgwAddress = enbSgwIpIfaces.GetAddress (1); + + // create S1-U socket for the ENB + Ptr<Socket> enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory")); + int retval = enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort)); + NS_ASSERT (retval == 0); + + + // give PacketSocket powers to the eNB + //PacketSocketHelper packetSocket; + //packetSocket.Install (enb); + + // create LTE socket for the ENB + Ptr<Socket> enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory")); + PacketSocketAddress enbLteSocketBindAddress; + enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); + enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); + retval = enbLteSocket->Bind (enbLteSocketBindAddress); + NS_ASSERT (retval == 0); + PacketSocketAddress enbLteSocketConnectAddress; + enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ()); + enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); + enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); + retval = enbLteSocket->Connect (enbLteSocketConnectAddress); + NS_ASSERT (retval == 0); + + NS_LOG_INFO ("create EpcEnbApplication"); + Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbS1uSocket, enbAddress, sgwAddress, cellId); + enb->AddApplication (enbApp); + NS_ASSERT (enb->GetNApplications () == 1); + NS_ASSERT_MSG (enb->GetApplication (0)->GetObject<EpcEnbApplication> () != 0, "cannot retrieve EpcEnbApplication"); + NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0)); + + NS_LOG_INFO ("Create EpcX2 entity"); + Ptr<EpcX2> x2 = CreateObject<EpcX2> (); + enb->AggregateObject (x2); + + NS_LOG_INFO ("connect S1-AP interface"); + m_mme->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ()); + m_sgwPgwApp->AddEnb (cellId, enbAddress, sgwAddress); + enbApp->SetS1apSapMme (m_mme->GetS1apSapMme ()); +} + + +void +TapPointToPointEpcHelper::AddX2Interface (Ptr<Node> enb1, Ptr<Node> enb2) +{ + NS_LOG_FUNCTION (this << enb1 << enb2); + + // Create a point to point link between the two eNBs with + // the corresponding new NetDevices on each side + NodeContainer enbNodes; + enbNodes.Add (enb1); + enbNodes.Add (enb2); + PointToPointHelper p2ph; + p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_x2LinkDataRate)); + p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_x2LinkMtu)); + p2ph.SetChannelAttribute ("Delay", TimeValue (m_x2LinkDelay)); + NetDeviceContainer enbDevices = p2ph.Install (enb1, enb2); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after installing p2p dev: " << enb1->GetObject<Ipv4> ()->GetNInterfaces ()); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after installing p2p dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ()); + Ptr<NetDevice> enb1Dev = enbDevices.Get (0); + Ptr<NetDevice> enb2Dev = enbDevices.Get (1); + + m_x2Ipv4AddressHelper.NewNetwork (); + Ipv4InterfaceContainer enbIpIfaces = m_x2Ipv4AddressHelper.Assign (enbDevices); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after assigning Ipv4 addr to X2 dev: " << enb1->GetObject<Ipv4> ()->GetNInterfaces ()); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after assigning Ipv4 addr to X2 dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ()); + + Ipv4Address enb1X2Address = enbIpIfaces.GetAddress (0); + Ipv4Address enb2X2Address = enbIpIfaces.GetAddress (1); + + // Add X2 interface to both eNBs' X2 entities + Ptr<EpcX2> enb1X2 = enb1->GetObject<EpcX2> (); + Ptr<LteEnbNetDevice> enb1LteDev = enb1->GetDevice (0)->GetObject<LteEnbNetDevice> (); + uint16_t enb1CellId = enb1LteDev->GetCellId (); + NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId); + + Ptr<EpcX2> enb2X2 = enb2->GetObject<EpcX2> (); + Ptr<LteEnbNetDevice> enb2LteDev = enb2->GetDevice (0)->GetObject<LteEnbNetDevice> (); + uint16_t enb2CellId = enb2LteDev->GetCellId (); + NS_LOG_LOGIC ("LteEnbNetDevice #2 = " << enb2LteDev << " - CellId = " << enb2CellId); + + enb1X2->AddX2Interface (enb1CellId, enb1X2Address, enb2CellId, enb2X2Address); + enb2X2->AddX2Interface (enb2CellId, enb2X2Address, enb1CellId, enb1X2Address); + + enb1LteDev->GetRrc ()->AddX2Neighbour (enb2LteDev->GetCellId ()); + enb2LteDev->GetRrc ()->AddX2Neighbour (enb1LteDev->GetCellId ()); +} + + +void +TapPointToPointEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi) +{ + NS_LOG_FUNCTION (this << imsi << ueDevice ); + + m_mme->AddUe (imsi); + m_sgwPgwApp->AddUe (imsi); + +} + +uint8_t +TapPointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer) +{ + NS_LOG_FUNCTION (this << ueDevice << imsi); + + // we now retrieve the IPv4 address of the UE and notify it to the SGW; + // we couldn't do it before since address assignment is triggered by + // the user simulation program, rather than done by the EPC + Ptr<Node> ueNode = ueDevice->GetNode (); + Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> (); + NS_ASSERT_MSG (ueIpv4 != 0, "UEs need to have IPv4 installed before EPS bearers can be activated"); + int32_t interface = ueIpv4->GetInterfaceForDevice (ueDevice); + NS_ASSERT (interface >= 0); + NS_ASSERT (ueIpv4->GetNAddresses (interface) == 1); + Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal (); + NS_LOG_LOGIC (" UE IP address: " << ueAddr); m_sgwPgwApp->SetUeAddress (imsi, ueAddr); + + uint8_t bearerId = m_mme->AddBearer (imsi, tft, bearer); + Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> (); + if (ueLteDevice) + { + ueLteDevice->GetNas ()->ActivateEpsBearer (bearer, tft); + } + return bearerId; +} + + +Ptr<Node> +TapPointToPointEpcHelper::GetPgwNode () +{ + return m_sgwPgw; +} + + +Ipv4InterfaceContainer +TapPointToPointEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices) +{ + return m_ueAddressHelper.Assign (ueDevices); +} + +Ipv4InterfaceContainer +TapPointToPointEpcHelper::AssignUeIpv4Address (Ptr<NetDevice> ueLteDevice, Ipv4Address ueIpAddress) +{ + Ipv4AddressHelper ueAddrHelper; + Ipv4Mask fakemask("255.255.255.0");//the mask is irrelevant here. + Ipv4Mask fakemask2(ueIpAddress.Get() & fakemask.Get()); + Ipv4Address id=Ipv4Address(ueIpAddress.Get() ^ fakemask2.Get()); + if(id.Get()<2) + std::cout<<"WARNING: id part of UE's IP="<<ueIpAddress<<" might be too small and have collisions\n"; + + ueAddrHelper.SetBase (ueIpAddress, fakemask2, id); + return ueAddrHelper.Assign (NetDeviceContainer (ueLteDevice)); + +} + + +Ipv4Address +TapPointToPointEpcHelper::GetUeDefaultGatewayAddress () +{ + // return the address of the tun device + return m_sgwPgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal (); +} + +} // namespace ns3 diff --git a/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.h b/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.h new file mode 100644 index 00000000..2fd79763 --- /dev/null +++ b/emu-radio/lte-emulator/extensions/tap-point-to-point-epc-helper.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TAP_POINT_TO_POINT_EPC_HELPER_H +#define TAP_POINT_TO_POINT_EPC_HELPER_H + +#include <ns3/object.h> +#include <ns3/ipv4-address-helper.h> +#include <ns3/data-rate.h> +#include <ns3/epc-tft.h> +#include <ns3/eps-bearer.h> +#include <ns3/epc-helper.h> + +namespace ns3 { + +class Node; +class NetDevice; +class VirtualNetDevice; +class EpcSgwPgwApplication; +class EpcX2; +class EpcMme; + +/** + * \ingroup lte + * \brief Create an EPC network with PointToPoint links + * + * This Helper will create an EPC network topology comprising of a + * single node that implements both the SGW and PGW functionality, and + * an MME node. The S1-U, X2-U and X2-C interfaces are realized over + * PointToPoint links. + */ + +/** + * NOTE: TapPointToPointEpcHelper is modified from PointToPointEpcHelper in ns3 lte module to support + * tap device used with lte device and configuration of UE IP address + */ +class TapPointToPointEpcHelper : public EpcHelper +{ +public: + + /** + * Constructor + * \param ueSubnetAddr the ue subent ip prefix to be used for configuration, default value is "7.0.0.0" + * \param ueSubnetMask UesubnetMask is by default "255.0.0.0" + */ + TapPointToPointEpcHelper (std::string ueSubnetAddr="7.0.0.0", std::string ueSubnetMask="255.0.0.0", uint32_t id=1); + + /** + * Destructor + */ + virtual ~TapPointToPointEpcHelper (); + + // inherited from Object + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId (void); + virtual void DoDispose (); + + // inherited from EpcHelper + virtual void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId); + virtual void AddUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi); + virtual void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2); + virtual uint8_t ActivateEpsBearer (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer); + virtual Ptr<Node> GetPgwNode (); + virtual Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices); + virtual Ipv4Address GetUeDefaultGatewayAddress (); + + /** \brief explicity assign IP address to an UE device + * + */ + Ipv4InterfaceContainer AssignUeIpv4Address (Ptr<NetDevice> ueLteDevice, Ipv4Address ueIpAddress); + + private: + + /** + * helper to assign addresses to UE devices as well as to the TUN device of the SGW/PGW + */ + Ipv4AddressHelper m_ueAddressHelper; + + /** + * SGW-PGW network element + */ + Ptr<Node> m_sgwPgw; + + /** + * SGW-PGW application + */ + Ptr<EpcSgwPgwApplication> m_sgwPgwApp; + + /** + * TUN device implementing tunneling of user data over GTP-U/UDP/IP + */ + Ptr<VirtualNetDevice> m_tunDevice; + + /** + * MME network element + */ + Ptr<EpcMme> m_mme; + + /** + * S1-U interfaces + */ + + /** + * helper to assign addresses to S1-U NetDevices + */ + Ipv4AddressHelper m_s1uIpv4AddressHelper; + + /** + * The data rate to be used for the next S1-U link to be created + */ + DataRate m_s1uLinkDataRate; + + /** + * The delay to be used for the next S1-U link to be created + */ + Time m_s1uLinkDelay; + + /** + * The MTU of the next S1-U link to be created. Note that, + * because of the additional GTP/UDP/IP tunneling overhead, + * you need a MTU larger than the end-to-end MTU that you + * want to support. + */ + uint16_t m_s1uLinkMtu; + + /** + * UDP port where the GTP-U Socket is bound, fixed by the standard as 2152 + */ + uint16_t m_gtpuUdpPort; + + /** + * Map storing for each IMSI the corresponding eNB NetDevice + */ + std::map<uint64_t, Ptr<NetDevice> > m_imsiEnbDeviceMap; + + /** + * helper to assign addresses to X2 NetDevices + */ + Ipv4AddressHelper m_x2Ipv4AddressHelper; + + /** + * The data rate to be used for the next X2 link to be created + */ + DataRate m_x2LinkDataRate; + + /** + * The delay to be used for the next X2 link to be created + */ + Time m_x2LinkDelay; + + /** + * The MTU of the next X2 link to be created. Note that, + * because of some big X2 messages, you need a big MTU. + */ + uint16_t m_x2LinkMtu; + +}; + +} // namespace ns3 + +#endif // TAP_POINT_TO_POINT_EPC_HELPER_H |