/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * 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 (); InternetStackHelper internet; internet.Install (m_sgwPgw); // create S1-U socket Ptr 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 (); // 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 (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 (); 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 () .SetGroupName("Lte") .AddConstructor () .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 ()) .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 ()) ; return tid; } void TapPointToPointEpcHelper::DoDispose () { NS_LOG_FUNCTION (this); m_tunDevice->SetSendCallback (MakeNullCallback, const Address&, const Address&, uint16_t> ()); m_tunDevice = 0; m_sgwPgwApp = 0; m_sgwPgw->Dispose (); } void TapPointToPointEpcHelper::AddEnb (Ptr enb, Ptr 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 () ->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 ()->GetNInterfaces ()); Ptr enbDev = enbSgwDevices.Get (0); Ptr 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 ()->GetNInterfaces ()); Ipv4Address enbAddress = enbSgwIpIfaces.GetAddress (0); Ipv4Address sgwAddress = enbSgwIpIfaces.GetAddress (1); // create S1-U socket for the ENB Ptr 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 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 enbApp = CreateObject (enbLteSocket, enbS1uSocket, enbAddress, sgwAddress, cellId); enb->AddApplication (enbApp); NS_ASSERT (enb->GetNApplications () == 1); NS_ASSERT_MSG (enb->GetApplication (0)->GetObject () != 0, "cannot retrieve EpcEnbApplication"); NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0)); NS_LOG_INFO ("Create EpcX2 entity"); Ptr x2 = CreateObject (); 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 enb1, Ptr 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 ()->GetNInterfaces ()); NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after installing p2p dev: " << enb2->GetObject ()->GetNInterfaces ()); Ptr enb1Dev = enbDevices.Get (0); Ptr 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 ()->GetNInterfaces ()); NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after assigning Ipv4 addr to X2 dev: " << enb2->GetObject ()->GetNInterfaces ()); Ipv4Address enb1X2Address = enbIpIfaces.GetAddress (0); Ipv4Address enb2X2Address = enbIpIfaces.GetAddress (1); // Add X2 interface to both eNBs' X2 entities Ptr enb1X2 = enb1->GetObject (); Ptr enb1LteDev = enb1->GetDevice (0)->GetObject (); uint16_t enb1CellId = enb1LteDev->GetCellId (); NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId); Ptr enb2X2 = enb2->GetObject (); Ptr enb2LteDev = enb2->GetDevice (0)->GetObject (); 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 ueDevice, uint64_t imsi) { NS_LOG_FUNCTION (this << imsi << ueDevice ); m_mme->AddUe (imsi); m_sgwPgwApp->AddUe (imsi); } uint8_t TapPointToPointEpcHelper::ActivateEpsBearer (Ptr ueDevice, uint64_t imsi, Ptr 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 ueNode = ueDevice->GetNode (); Ptr ueIpv4 = ueNode->GetObject (); 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 ueLteDevice = ueDevice->GetObject (); if (ueLteDevice) { ueLteDevice->GetNas ()->ActivateEpsBearer (bearer, tft); } return bearerId; } Ptr TapPointToPointEpcHelper::GetPgwNode () { return m_sgwPgw; } Ipv4InterfaceContainer TapPointToPointEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices) { return m_ueAddressHelper.Assign (ueDevices); } Ipv4InterfaceContainer TapPointToPointEpcHelper::AssignUeIpv4Address (Ptr 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="<GetObject ()->GetAddress (1, 0).GetLocal (); } } // namespace ns3