diff --git a/src/lte/model/epc-x2-header.cc b/src/lte/model/epc-x2-header.cc index 0001442b8..ebc3658fc 100644 --- a/src/lte/model/epc-x2-header.cc +++ b/src/lte/model/epc-x2-header.cc @@ -970,5 +970,182 @@ EpcX2LoadInformationHeader::GetNumberOfIes () const return m_numberOfIes; } +//////////////// + +NS_OBJECT_ENSURE_REGISTERED (EpcX2ResourceStatusUpdateHeader); + +EpcX2ResourceStatusUpdateHeader::EpcX2ResourceStatusUpdateHeader () + : m_numberOfIes (3), + m_headerLength (6), + m_enb1MeasurementId (0), + m_enb2MeasurementId (0) +{ + m_cellMeasurementResultList.clear (); +} + +EpcX2ResourceStatusUpdateHeader::~EpcX2ResourceStatusUpdateHeader () +{ + m_numberOfIes = 0; + m_headerLength = 0; + m_enb1MeasurementId = 0; + m_enb2MeasurementId = 0; + m_cellMeasurementResultList.clear (); +} + +TypeId +EpcX2ResourceStatusUpdateHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::EpcX2ResourceStatusUpdateHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +EpcX2ResourceStatusUpdateHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +EpcX2ResourceStatusUpdateHeader::GetSerializedSize (void) const +{ + return m_headerLength; +} + +void +EpcX2ResourceStatusUpdateHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (m_enb1MeasurementId); + i.WriteHtonU16 (m_enb2MeasurementId); + + std::vector ::size_type sz = m_cellMeasurementResultList.size (); + i.WriteHtonU16 (sz); // number of CellMeasurementResultItem + + for (int j = 0; j < (int) sz; j++) + { + EpcX2Sap::CellMeasurementResultItem item = m_cellMeasurementResultList [j]; + + i.WriteHtonU16 (item.sourceCellId); + i.WriteU8 (item.dlHardwareLoadIndicator); + i.WriteU8 (item.ulHardwareLoadIndicator); + i.WriteU8 (item.dlS1TnlLoadIndicator); + i.WriteU8 (item.ulS1TnlLoadIndicator); + + i.WriteHtonU16 (item.dlGbrPrbUsage); + i.WriteHtonU16 (item.ulGbrPrbUsage); + i.WriteHtonU16 (item.dlNonGbrPrbUsage); + i.WriteHtonU16 (item.ulNonGbrPrbUsage); + i.WriteHtonU16 (item.dlTotalPrbUsage); + i.WriteHtonU16 (item.ulTotalPrbUsage); + + i.WriteHtonU16 (item.dlCompositeAvailableCapacity.cellCapacityClassValue); + i.WriteHtonU16 (item.dlCompositeAvailableCapacity.capacityValue); + i.WriteHtonU16 (item.ulCompositeAvailableCapacity.cellCapacityClassValue); + i.WriteHtonU16 (item.ulCompositeAvailableCapacity.capacityValue); + } +} + +uint32_t +EpcX2ResourceStatusUpdateHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_enb1MeasurementId = i.ReadNtohU16 (); + m_enb2MeasurementId = i.ReadNtohU16 (); + + int sz = i.ReadNtohU16 (); + for (int j = 0; j < sz; j++) + { + EpcX2Sap::CellMeasurementResultItem item; + + item.sourceCellId = i.ReadNtohU16 (); + item.dlHardwareLoadIndicator = (EpcX2Sap::LoadIndicator) i.ReadU8 (); + item.ulHardwareLoadIndicator = (EpcX2Sap::LoadIndicator) i.ReadU8 (); + item.dlS1TnlLoadIndicator = (EpcX2Sap::LoadIndicator) i.ReadU8 (); + item.ulS1TnlLoadIndicator = (EpcX2Sap::LoadIndicator) i.ReadU8 (); + + item.dlGbrPrbUsage = i.ReadNtohU16 (); + item.ulGbrPrbUsage = i.ReadNtohU16 (); + item.dlNonGbrPrbUsage = i.ReadNtohU16 (); + item.ulNonGbrPrbUsage = i.ReadNtohU16 (); + item.dlTotalPrbUsage = i.ReadNtohU16 (); + item.ulTotalPrbUsage = i.ReadNtohU16 (); + + item.dlCompositeAvailableCapacity.cellCapacityClassValue = i.ReadNtohU16 (); + item.dlCompositeAvailableCapacity.capacityValue = i.ReadNtohU16 (); + item.ulCompositeAvailableCapacity.cellCapacityClassValue = i.ReadNtohU16 (); + item.ulCompositeAvailableCapacity.capacityValue = i.ReadNtohU16 (); + + m_cellMeasurementResultList.push_back (item); + } + + m_headerLength = 6 + sz * 26; + m_numberOfIes = 3; + + return GetSerializedSize (); +} + +void +EpcX2ResourceStatusUpdateHeader::Print (std::ostream &os) const +{ + os << "Enb1MeasurementId = " << m_enb1MeasurementId + << " Enb2MeasurementId = " << m_enb2MeasurementId + << " NumOfCellMeasurementResultItems = " << m_cellMeasurementResultList.size (); +} + +uint16_t +EpcX2ResourceStatusUpdateHeader::GetEnb1MeasurementId () const +{ + return m_enb1MeasurementId; +} + +void +EpcX2ResourceStatusUpdateHeader::SetEnb1MeasurementId (uint16_t enb1MeasurementId) +{ + m_enb1MeasurementId = enb1MeasurementId; +} + +uint16_t +EpcX2ResourceStatusUpdateHeader::GetEnb2MeasurementId () const +{ + return m_enb2MeasurementId; +} + +void +EpcX2ResourceStatusUpdateHeader::SetEnb2MeasurementId (uint16_t enb2MeasurementId) +{ + m_enb2MeasurementId = enb2MeasurementId; +} + +std::vector +EpcX2ResourceStatusUpdateHeader::GetCellMeasurementResultList () const +{ + return m_cellMeasurementResultList; +} + +void +EpcX2ResourceStatusUpdateHeader::SetCellMeasurementResultList (std::vector cellMeasurementResultList) +{ + m_cellMeasurementResultList = cellMeasurementResultList; + + std::vector ::size_type sz = m_cellMeasurementResultList.size (); + m_headerLength += sz * 26; +} + +uint32_t +EpcX2ResourceStatusUpdateHeader::GetLengthOfIes () const +{ + return m_headerLength; +} + +uint32_t +EpcX2ResourceStatusUpdateHeader::GetNumberOfIes () const +{ + return m_numberOfIes; +} } // namespace ns3 diff --git a/src/lte/model/epc-x2-header.h b/src/lte/model/epc-x2-header.h index 20f0f63ed..611c35054 100644 --- a/src/lte/model/epc-x2-header.h +++ b/src/lte/model/epc-x2-header.h @@ -56,8 +56,9 @@ public: enum ProcedureCode_t { HandoverPreparation = 0, - LoadInformation = 2, - UeContextRelease = 5 + LoadIndication = 2, + UeContextRelease = 5, + ResourceStatusReporting = 10 }; enum TypeOfMessage_t { @@ -225,6 +226,42 @@ private: }; +class EpcX2ResourceStatusUpdateHeader : public Header +{ +public: + EpcX2ResourceStatusUpdateHeader (); + virtual ~EpcX2ResourceStatusUpdateHeader (); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual void Print (std::ostream &os) const; + + + uint16_t GetEnb1MeasurementId () const; + void SetEnb1MeasurementId (uint16_t enb1MeasurementId); + + uint16_t GetEnb2MeasurementId () const; + void SetEnb2MeasurementId (uint16_t enb2MeasurementId); + + std::vector GetCellMeasurementResultList () const; + void SetCellMeasurementResultList (std::vector cellMeasurementResultList); + + uint32_t GetLengthOfIes () const; + uint32_t GetNumberOfIes () const; + +private: + uint32_t m_numberOfIes; + uint32_t m_headerLength; + + uint16_t m_enb1MeasurementId; + uint16_t m_enb2MeasurementId; + std::vector m_cellMeasurementResultList; +}; + + } // namespace ns3 #endif // EPC_X2_HEADER_H diff --git a/src/lte/model/epc-x2-sap.h b/src/lte/model/epc-x2-sap.h index 71aef0f8c..88384925d 100644 --- a/src/lte/model/epc-x2-sap.h +++ b/src/lte/model/epc-x2-sap.h @@ -61,7 +61,7 @@ public: bool dlForwarding; Ipv4Address transportLayerAddress; uint32_t gtpTeid; - + ErabToBeSetupItem (); }; @@ -76,7 +76,7 @@ public: uint32_t ulGtpTeid; uint32_t dlGtpTeid; }; - + /** * E-RABs not admitted item as * it is used in the HANDOVER REQUEST ACKNOWLEDGE message. @@ -141,6 +141,56 @@ public: RelativeNarrowbandTxBand relativeNarrowbandTxBand; }; + /** + * Load Indicator as + * it is used in the RESOURCE STATUS UPDATE message. + * See section 9.2.36 for further info about the value + */ + enum LoadIndicator + { + LowLoad, + MediumLoad, + HighLoad, + Overload + }; + + /** + * Composite Available Capacity as + * it is used in the RESOURCE STATUS UPDATE message. + * See section 9.2.45 for further info about the parameters + */ + struct CompositeAvailCapacity + { + uint16_t cellCapacityClassValue; + uint16_t capacityValue; + }; + + /** + * Cell Measurement Result Item as + * it is used in the RESOURCE STATUS UPDATE message. + * See section 9.1.2.14 for further info about the parameters + */ + struct CellMeasurementResultItem + { + uint16_t sourceCellId; + + LoadIndicator dlHardwareLoadIndicator; + LoadIndicator ulHardwareLoadIndicator; + + LoadIndicator dlS1TnlLoadIndicator; + LoadIndicator ulS1TnlLoadIndicator; + + uint16_t dlGbrPrbUsage; + uint16_t ulGbrPrbUsage; + uint16_t dlNonGbrPrbUsage; + uint16_t ulNonGbrPrbUsage; + uint16_t dlTotalPrbUsage; + uint16_t ulTotalPrbUsage; + + CompositeAvailCapacity dlCompositeAvailableCapacity; + CompositeAvailCapacity ulCompositeAvailableCapacity; + }; + enum IdCause { @@ -165,7 +215,7 @@ public: std::vector bearers; Ptr rrcContext; }; - + /** * \brief Parameters of the HANDOVER REQUEST ACKNOWLEDGE message. * @@ -205,6 +255,19 @@ public: std::vector cellInformationList; }; + /** + * \brief Parameters of the RESOURCE STATUS UPDATE message. + * + * See section 9.1.2.14 for further info about the parameters + */ + struct ResourceStatusUpdateParams + { + uint16_t targetCellId; + uint16_t enb1MeasurementId; + uint16_t enb2MeasurementId; + std::vector cellMeasurementResultList; + }; + }; @@ -216,7 +279,7 @@ class EpcX2SapProvider : public EpcX2Sap { public: virtual ~EpcX2SapProvider (); - + /** * Service primitives */ @@ -228,6 +291,8 @@ public: virtual void SendUeContextRelease (UeContextReleaseParams params) = 0; virtual void SendLoadInformation (LoadInformationParams params) = 0; + + virtual void SendResourceStatusUpdate (ResourceStatusUpdateParams params) = 0; }; @@ -251,6 +316,8 @@ public: virtual void RecvUeContextRelease (UeContextReleaseParams params) = 0; virtual void RecvLoadInformation (LoadInformationParams params) = 0; + + virtual void RecvResourceStatusUpdate (ResourceStatusUpdateParams params) = 0; }; /////////////////////////////////////// @@ -272,7 +339,9 @@ public: virtual void SendUeContextRelease (UeContextReleaseParams params); virtual void SendLoadInformation (LoadInformationParams params); - + + virtual void SendResourceStatusUpdate (ResourceStatusUpdateParams params); + private: EpcX2SpecificEpcX2SapProvider (); C* m_x2; @@ -317,6 +386,13 @@ EpcX2SpecificEpcX2SapProvider::SendLoadInformation (LoadInformationParams par m_x2->DoSendLoadInformation (params); } +template +void +EpcX2SpecificEpcX2SapProvider::SendResourceStatusUpdate (ResourceStatusUpdateParams params) +{ + m_x2->DoSendResourceStatusUpdate (params); +} + /////////////////////////////////////// template @@ -332,11 +408,13 @@ public: virtual void RecvHandoverRequest (HandoverRequestParams params); virtual void RecvHandoverRequestAck (HandoverRequestAckParams params); - + virtual void RecvUeContextRelease (UeContextReleaseParams params); virtual void RecvLoadInformation (LoadInformationParams params); + virtual void RecvResourceStatusUpdate (ResourceStatusUpdateParams params); + private: EpcX2SpecificEpcX2SapUser (); C* m_rrc; @@ -381,6 +459,13 @@ EpcX2SpecificEpcX2SapUser::RecvLoadInformation (LoadInformationParams params) m_rrc->DoRecvLoadInformation (params); } +template +void +EpcX2SpecificEpcX2SapUser::RecvResourceStatusUpdate (ResourceStatusUpdateParams params) +{ + m_rrc->DoRecvResourceStatusUpdate (params); +} + } // namespace ns3 #endif // EPC_X2_SAP_H diff --git a/src/lte/model/epc-x2.cc b/src/lte/model/epc-x2.cc index f80ddeb44..2ff098f3f 100644 --- a/src/lte/model/epc-x2.cc +++ b/src/lte/model/epc-x2.cc @@ -40,6 +40,7 @@ X2IfaceInfo::X2IfaceInfo (Ptr localSocket, Ipv4Address remoteIpAddr) X2IfaceInfo::~X2IfaceInfo (void) { + m_localSocket = 0; } X2IfaceInfo& @@ -61,6 +62,8 @@ X2CellInfo::X2CellInfo (uint16_t localCellId, uint16_t remoteCellId) X2CellInfo::~X2CellInfo (void) { + m_localCellId = 0; + m_remoteCellId = 0; } X2CellInfo& @@ -80,10 +83,25 @@ EpcX2::EpcX2 () : m_x2cUdpPort (4444) { NS_LOG_FUNCTION (this); - + m_x2SapProvider = new EpcX2SpecificEpcX2SapProvider (this); } +EpcX2::~EpcX2 () +{ + NS_LOG_FUNCTION (this); +} + +void +EpcX2::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + + m_x2InterfaceSockets.clear (); + m_x2InterfaceCellIds.clear (); + delete m_x2SapProvider; +} + TypeId EpcX2::GetTypeId (void) { @@ -92,12 +110,6 @@ EpcX2::GetTypeId (void) return tid; } -EpcX2::~EpcX2 (void) -{ - NS_LOG_FUNCTION (this); - delete m_x2SapProvider; -} - void EpcX2::SetEpcX2SapUser (EpcX2SapUser * s) { @@ -225,7 +237,7 @@ EpcX2::RecvFromX2cSocket (Ptr socket) m_x2SapUser->RecvHandoverRequestAck (params); } } - else if (procedureCode == EpcX2Header::LoadInformation) + else if (procedureCode == EpcX2Header::LoadIndication) { if (messageType == EpcX2Header::InitiatingMessage) { @@ -265,6 +277,29 @@ EpcX2::RecvFromX2cSocket (Ptr socket) m_x2SapUser->RecvUeContextRelease (params); } } + else if (procedureCode == EpcX2Header::ResourceStatusReporting) + { + if (messageType == EpcX2Header::InitiatingMessage) + { + NS_LOG_LOGIC ("Recv X2 message: RESOURCE STATUS UPDATE"); + + EpcX2ResourceStatusUpdateHeader x2ResStatUpdHeader; + packet->RemoveHeader (x2ResStatUpdHeader); + + NS_LOG_INFO ("X2 ResourceStatusUpdate header: " << x2ResStatUpdHeader); + + EpcX2SapUser::ResourceStatusUpdateParams params; + params.enb1MeasurementId = x2ResStatUpdHeader.GetEnb1MeasurementId (); + params.enb2MeasurementId = x2ResStatUpdHeader.GetEnb2MeasurementId (); + params.cellMeasurementResultList = x2ResStatUpdHeader.GetCellMeasurementResultList (); + + NS_LOG_LOGIC ("enb1MeasurementId = " << params.enb1MeasurementId); + NS_LOG_LOGIC ("enb2MeasurementId = " << params.enb2MeasurementId); + NS_LOG_LOGIC ("cellMeasurementResultList size = " << params.cellMeasurementResultList.size ()); + + m_x2SapUser->RecvResourceStatusUpdate (params); + } + } else { NS_ASSERT_MSG (false, "ProcedureCode NOT SUPPORTED!!!"); @@ -442,7 +477,7 @@ EpcX2::DoSendLoadInformation (EpcX2SapProvider::LoadInformationParams params) EpcX2Header x2Header; x2Header.SetMessageType (EpcX2Header::InitiatingMessage); - x2Header.SetProcedureCode (EpcX2Header::LoadInformation); + x2Header.SetProcedureCode (EpcX2Header::LoadIndication); x2Header.SetLengthOfIes (x2LoadInfoHeader.GetLengthOfIes ()); x2Header.SetNumberOfIes (x2LoadInfoHeader.GetNumberOfIes ()); @@ -461,4 +496,52 @@ EpcX2::DoSendLoadInformation (EpcX2SapProvider::LoadInformationParams params) } +void +EpcX2::DoSendResourceStatusUpdate (EpcX2SapProvider::ResourceStatusUpdateParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); + NS_LOG_LOGIC ("enb1MeasurementId = " << params.enb1MeasurementId); + NS_LOG_LOGIC ("enb2MeasurementId = " << params.enb2MeasurementId); + NS_LOG_LOGIC ("cellMeasurementResultList size = " << params.cellMeasurementResultList.size ()); + + NS_ASSERT_MSG (m_x2InterfaceSockets.find (params.targetCellId) != m_x2InterfaceSockets.end (), + "Missing infos for targetCellId = " << params.targetCellId); + Ptr socketInfo = m_x2InterfaceSockets [params.targetCellId]; + Ptr sourceSocket = socketInfo->m_localSocket; + Ipv4Address targetIpAddr = socketInfo->m_remoteIpAddr; + + NS_LOG_LOGIC ("sourceSocket = " << sourceSocket); + NS_LOG_LOGIC ("targetIpAddr = " << targetIpAddr); + + NS_LOG_INFO ("Send X2 message: RESOURCE STATUS UPDATE"); + + // Build the X2 message + EpcX2ResourceStatusUpdateHeader x2ResourceStatUpdHeader; + x2ResourceStatUpdHeader.SetEnb1MeasurementId (params.enb1MeasurementId); + x2ResourceStatUpdHeader.SetEnb2MeasurementId (params.enb2MeasurementId); + x2ResourceStatUpdHeader.SetCellMeasurementResultList (params.cellMeasurementResultList); + + EpcX2Header x2Header; + x2Header.SetMessageType (EpcX2Header::InitiatingMessage); + x2Header.SetProcedureCode (EpcX2Header::ResourceStatusReporting); + x2Header.SetLengthOfIes (x2ResourceStatUpdHeader.GetLengthOfIes ()); + x2Header.SetNumberOfIes (x2ResourceStatUpdHeader.GetNumberOfIes ()); + + NS_LOG_INFO ("X2 header: " << x2Header); + NS_LOG_INFO ("X2 ResourceStatusUpdate header: " << x2ResourceStatUpdHeader); + + // Build the X2 packet + Ptr packet = Create (); + packet->AddHeader (x2ResourceStatUpdHeader); + packet->AddHeader (x2Header); + NS_LOG_INFO ("packetLen = " << packet->GetSize ()); + + // Send the X2 message through the socket + sourceSocket->SendTo (packet, 0, InetSocketAddress (targetIpAddr, m_x2cUdpPort)); + +} + + } // namespace ns3 diff --git a/src/lte/model/epc-x2.h b/src/lte/model/epc-x2.h index 83b521131..12954d9c4 100644 --- a/src/lte/model/epc-x2.h +++ b/src/lte/model/epc-x2.h @@ -82,6 +82,7 @@ public: virtual ~EpcX2 (void); static TypeId GetTypeId (void); + virtual void DoDispose (void); /** @@ -111,11 +112,12 @@ public: protected: - // Interface provided by LteRlcSapProvider + // Interface provided by EpcX2SapProvider virtual void DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params); virtual void DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params); virtual void DoSendUeContextRelease (EpcX2SapProvider::UeContextReleaseParams params); virtual void DoSendLoadInformation (EpcX2SapProvider::LoadInformationParams params); + virtual void DoSendResourceStatusUpdate (EpcX2SapProvider::ResourceStatusUpdateParams params); EpcX2SapUser* m_x2SapUser; EpcX2SapProvider* m_x2SapProvider; diff --git a/src/lte/model/lte-enb-rrc.cc b/src/lte/model/lte-enb-rrc.cc index cab161a09..517b1c590 100644 --- a/src/lte/model/lte-enb-rrc.cc +++ b/src/lte/model/lte-enb-rrc.cc @@ -1232,6 +1232,18 @@ LteEnbRrc::DoRecvLoadInformation (EpcX2SapUser::LoadInformationParams params) NS_ASSERT ("Processing of LOAD INFORMATION X2 message IS NOT IMPLEMENTED"); } +void +LteEnbRrc::DoRecvResourceStatusUpdate (EpcX2SapUser::ResourceStatusUpdateParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("Recv X2 message: RESOURCE STATUS UPDATE"); + + NS_LOG_LOGIC ("Number of cellMeasurementResultItems = " << params.cellMeasurementResultList.size ()); + + NS_ASSERT ("Processing of RESOURCE STATUS UPDATE X2 message IS NOT IMPLEMENTED"); +} + uint16_t LteEnbRrc::DoAllocateTemporaryCellRnti () diff --git a/src/lte/model/lte-enb-rrc.h b/src/lte/model/lte-enb-rrc.h index d1b08f1b2..5f479d1c8 100644 --- a/src/lte/model/lte-enb-rrc.h +++ b/src/lte/model/lte-enb-rrc.h @@ -544,7 +544,8 @@ private: void DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params); void DoRecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params); void DoRecvLoadInformation (EpcX2SapUser::LoadInformationParams params); - + void DoRecvResourceStatusUpdate (EpcX2SapUser::ResourceStatusUpdateParams params); + // CMAC SAP methods uint16_t DoAllocateTemporaryCellRnti ();