|
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
|
2 /* |
|
3 * Copyright (c) 2011-2013 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC) |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License version 2 as |
|
7 * published by the Free Software Foundation; |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 * |
|
18 * Author: Jaume Nin <jnin@cttc.es> |
|
19 * Nicola Baldo <nbaldo@cttc.es> |
|
20 * Manuel Requena <manuel.requena@cttc.es> |
|
21 */ |
|
22 |
|
23 #include <ns3/point-to-point-epc-helper.h> |
|
24 #include <ns3/log.h> |
|
25 #include <ns3/inet-socket-address.h> |
|
26 #include <ns3/mac48-address.h> |
|
27 #include <ns3/eps-bearer.h> |
|
28 #include <ns3/ipv4-address.h> |
|
29 #include <ns3/internet-stack-helper.h> |
|
30 #include <ns3/point-to-point-helper.h> |
|
31 #include <ns3/packet-socket-helper.h> |
|
32 #include <ns3/packet-socket-address.h> |
|
33 #include <ns3/epc-enb-application.h> |
|
34 #include <ns3/epc-sgw-pgw-application.h> |
|
35 |
|
36 #include <ns3/lte-enb-rrc.h> |
|
37 #include <ns3/epc-x2.h> |
|
38 #include <ns3/lte-enb-net-device.h> |
|
39 #include <ns3/lte-ue-net-device.h> |
|
40 #include <ns3/epc-mme.h> |
|
41 #include <ns3/epc-ue-nas.h> |
|
42 |
|
43 namespace ns3 { |
|
44 |
|
45 NS_LOG_COMPONENT_DEFINE ("PointToPointEpcHelper"); |
|
46 |
|
47 NS_OBJECT_ENSURE_REGISTERED (PointToPointEpcHelper); |
|
48 |
|
49 |
|
50 PointToPointEpcHelper::PointToPointEpcHelper () |
|
51 : m_gtpuUdpPort (2152) // fixed by the standard |
|
52 { |
|
53 NS_LOG_FUNCTION (this); |
|
54 |
|
55 // since we use point-to-point links for all S1-U links, |
|
56 // we use a /30 subnet which can hold exactly two addresses |
|
57 // (remember that net broadcast and null address are not valid) |
|
58 m_s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252"); |
|
59 |
|
60 m_x2Ipv4AddressHelper.SetBase ("12.0.0.0", "255.255.255.252"); |
|
61 |
|
62 // we use a /8 net for all UEs |
|
63 m_ueAddressHelper.SetBase ("7.0.0.0", "255.0.0.0"); |
|
64 |
|
65 // create SgwPgwNode |
|
66 m_sgwPgw = CreateObject<Node> (); |
|
67 InternetStackHelper internet; |
|
68 internet.Install (m_sgwPgw); |
|
69 |
|
70 // create S1-U socket |
|
71 Ptr<Socket> sgwPgwS1uSocket = Socket::CreateSocket (m_sgwPgw, TypeId::LookupByName ("ns3::UdpSocketFactory")); |
|
72 int retval = sgwPgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort)); |
|
73 NS_ASSERT (retval == 0); |
|
74 |
|
75 // create TUN device implementing tunneling of user data over GTP-U/UDP/IP |
|
76 m_tunDevice = CreateObject<VirtualNetDevice> (); |
|
77 // allow jumbo packets |
|
78 m_tunDevice->SetAttribute ("Mtu", UintegerValue (30000)); |
|
79 |
|
80 // yes we need this |
|
81 m_tunDevice->SetAddress (Mac48Address::Allocate ()); |
|
82 |
|
83 m_sgwPgw->AddDevice (m_tunDevice); |
|
84 NetDeviceContainer tunDeviceContainer; |
|
85 tunDeviceContainer.Add (m_tunDevice); |
|
86 |
|
87 // the TUN device is on the same subnet as the UEs, so when a packet |
|
88 // addressed to an UE arrives at the intenet to the WAN interface of |
|
89 // the PGW it will be forwarded to the TUN device. |
|
90 Ipv4InterfaceContainer tunDeviceIpv4IfContainer = m_ueAddressHelper.Assign (tunDeviceContainer); |
|
91 |
|
92 // create EpcSgwPgwApplication |
|
93 m_sgwPgwApp = CreateObject<EpcSgwPgwApplication> (m_tunDevice, sgwPgwS1uSocket); |
|
94 m_sgwPgw->AddApplication (m_sgwPgwApp); |
|
95 |
|
96 // connect SgwPgwApplication and virtual net device for tunneling |
|
97 m_tunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromTunDevice, m_sgwPgwApp)); |
|
98 |
|
99 // Create MME and connect with SGW via S11 interface |
|
100 m_mme = CreateObject<EpcMme> (); |
|
101 m_mme->SetS11SapSgw (m_sgwPgwApp->GetS11SapSgw ()); |
|
102 m_sgwPgwApp->SetS11SapMme (m_mme->GetS11SapMme ()); |
|
103 } |
|
104 |
|
105 PointToPointEpcHelper::~PointToPointEpcHelper () |
|
106 { |
|
107 NS_LOG_FUNCTION (this); |
|
108 } |
|
109 |
|
110 TypeId |
|
111 PointToPointEpcHelper::GetTypeId (void) |
|
112 { |
|
113 static TypeId tid = TypeId ("ns3::PointToPointEpcHelper") |
|
114 .SetParent<EpcHelper> () |
|
115 .AddConstructor<PointToPointEpcHelper> () |
|
116 .AddAttribute ("S1uLinkDataRate", |
|
117 "The data rate to be used for the next S1-U link to be created", |
|
118 DataRateValue (DataRate ("10Gb/s")), |
|
119 MakeDataRateAccessor (&PointToPointEpcHelper::m_s1uLinkDataRate), |
|
120 MakeDataRateChecker ()) |
|
121 .AddAttribute ("S1uLinkDelay", |
|
122 "The delay to be used for the next S1-U link to be created", |
|
123 TimeValue (Seconds (0)), |
|
124 MakeTimeAccessor (&PointToPointEpcHelper::m_s1uLinkDelay), |
|
125 MakeTimeChecker ()) |
|
126 .AddAttribute ("S1uLinkMtu", |
|
127 "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.", |
|
128 UintegerValue (2000), |
|
129 MakeUintegerAccessor (&PointToPointEpcHelper::m_s1uLinkMtu), |
|
130 MakeUintegerChecker<uint16_t> ()) |
|
131 .AddAttribute ("X2LinkDataRate", |
|
132 "The data rate to be used for the next X2 link to be created", |
|
133 DataRateValue (DataRate ("10Gb/s")), |
|
134 MakeDataRateAccessor (&PointToPointEpcHelper::m_x2LinkDataRate), |
|
135 MakeDataRateChecker ()) |
|
136 .AddAttribute ("X2LinkDelay", |
|
137 "The delay to be used for the next X2 link to be created", |
|
138 TimeValue (Seconds (0)), |
|
139 MakeTimeAccessor (&PointToPointEpcHelper::m_x2LinkDelay), |
|
140 MakeTimeChecker ()) |
|
141 .AddAttribute ("X2LinkMtu", |
|
142 "The MTU of the next X2 link to be created. Note that, because of some big X2 messages, you need a big MTU.", |
|
143 UintegerValue (3000), |
|
144 MakeUintegerAccessor (&PointToPointEpcHelper::m_x2LinkMtu), |
|
145 MakeUintegerChecker<uint16_t> ()) |
|
146 ; |
|
147 return tid; |
|
148 } |
|
149 |
|
150 void |
|
151 PointToPointEpcHelper::DoDispose () |
|
152 { |
|
153 NS_LOG_FUNCTION (this); |
|
154 m_tunDevice->SetSendCallback (MakeNullCallback<bool, Ptr<Packet>, const Address&, const Address&, uint16_t> ()); |
|
155 m_tunDevice = 0; |
|
156 m_sgwPgwApp = 0; |
|
157 m_sgwPgw->Dispose (); |
|
158 } |
|
159 |
|
160 |
|
161 void |
|
162 PointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId) |
|
163 { |
|
164 NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId); |
|
165 |
|
166 NS_ASSERT (enb == lteEnbNetDevice->GetNode ()); |
|
167 |
|
168 // add an IPv4 stack to the previously created eNB |
|
169 InternetStackHelper internet; |
|
170 internet.Install (enb); |
|
171 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
172 |
|
173 // create a point to point link between the new eNB and the SGW with |
|
174 // the corresponding new NetDevices on each side |
|
175 NodeContainer enbSgwNodes; |
|
176 enbSgwNodes.Add (m_sgwPgw); |
|
177 enbSgwNodes.Add (enb); |
|
178 PointToPointHelper p2ph; |
|
179 p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s1uLinkDataRate)); |
|
180 p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s1uLinkMtu)); |
|
181 p2ph.SetChannelAttribute ("Delay", TimeValue (m_s1uLinkDelay)); |
|
182 NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_sgwPgw); |
|
183 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
184 Ptr<NetDevice> enbDev = enbSgwDevices.Get (0); |
|
185 Ptr<NetDevice> sgwDev = enbSgwDevices.Get (1); |
|
186 m_s1uIpv4AddressHelper.NewNetwork (); |
|
187 Ipv4InterfaceContainer enbSgwIpIfaces = m_s1uIpv4AddressHelper.Assign (enbSgwDevices); |
|
188 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after assigning Ipv4 addr to S1 dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
189 |
|
190 Ipv4Address enbAddress = enbSgwIpIfaces.GetAddress (0); |
|
191 Ipv4Address sgwAddress = enbSgwIpIfaces.GetAddress (1); |
|
192 |
|
193 // create S1-U socket for the ENB |
|
194 Ptr<Socket> enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory")); |
|
195 int retval = enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort)); |
|
196 NS_ASSERT (retval == 0); |
|
197 |
|
198 |
|
199 // give PacketSocket powers to the eNB |
|
200 //PacketSocketHelper packetSocket; |
|
201 //packetSocket.Install (enb); |
|
202 |
|
203 // create LTE socket for the ENB |
|
204 Ptr<Socket> enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory")); |
|
205 PacketSocketAddress enbLteSocketBindAddress; |
|
206 enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); |
|
207 enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); |
|
208 retval = enbLteSocket->Bind (enbLteSocketBindAddress); |
|
209 NS_ASSERT (retval == 0); |
|
210 PacketSocketAddress enbLteSocketConnectAddress; |
|
211 enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ()); |
|
212 enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); |
|
213 enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); |
|
214 retval = enbLteSocket->Connect (enbLteSocketConnectAddress); |
|
215 NS_ASSERT (retval == 0); |
|
216 |
|
217 |
|
218 NS_LOG_INFO ("create EpcEnbApplication"); |
|
219 Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbS1uSocket, enbAddress, sgwAddress, cellId); |
|
220 enb->AddApplication (enbApp); |
|
221 NS_ASSERT (enb->GetNApplications () == 1); |
|
222 NS_ASSERT_MSG (enb->GetApplication (0)->GetObject<EpcEnbApplication> () != 0, "cannot retrieve EpcEnbApplication"); |
|
223 NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0)); |
|
224 |
|
225 |
|
226 NS_LOG_INFO ("Create EpcX2 entity"); |
|
227 Ptr<EpcX2> x2 = CreateObject<EpcX2> (); |
|
228 enb->AggregateObject (x2); |
|
229 |
|
230 NS_LOG_INFO ("connect S1-AP interface"); |
|
231 m_mme->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ()); |
|
232 m_sgwPgwApp->AddEnb (cellId, enbAddress, sgwAddress); |
|
233 enbApp->SetS1apSapMme (m_mme->GetS1apSapMme ()); |
|
234 } |
|
235 |
|
236 |
|
237 void |
|
238 PointToPointEpcHelper::AddX2Interface (Ptr<Node> enb1, Ptr<Node> enb2) |
|
239 { |
|
240 NS_LOG_FUNCTION (this << enb1 << enb2); |
|
241 |
|
242 // Create a point to point link between the two eNBs with |
|
243 // the corresponding new NetDevices on each side |
|
244 NodeContainer enbNodes; |
|
245 enbNodes.Add (enb1); |
|
246 enbNodes.Add (enb2); |
|
247 PointToPointHelper p2ph; |
|
248 p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_x2LinkDataRate)); |
|
249 p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_x2LinkMtu)); |
|
250 p2ph.SetChannelAttribute ("Delay", TimeValue (m_x2LinkDelay)); |
|
251 NetDeviceContainer enbDevices = p2ph.Install (enb1, enb2); |
|
252 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after installing p2p dev: " << enb1->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
253 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after installing p2p dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
254 Ptr<NetDevice> enb1Dev = enbDevices.Get (0); |
|
255 Ptr<NetDevice> enb2Dev = enbDevices.Get (1); |
|
256 |
|
257 m_x2Ipv4AddressHelper.NewNetwork (); |
|
258 Ipv4InterfaceContainer enbIpIfaces = m_x2Ipv4AddressHelper.Assign (enbDevices); |
|
259 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after assigning Ipv4 addr to X2 dev: " << enb1->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
260 NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after assigning Ipv4 addr to X2 dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ()); |
|
261 |
|
262 Ipv4Address enb1X2Address = enbIpIfaces.GetAddress (0); |
|
263 Ipv4Address enb2X2Address = enbIpIfaces.GetAddress (1); |
|
264 |
|
265 // Add X2 interface to both eNBs' X2 entities |
|
266 Ptr<EpcX2> enb1X2 = enb1->GetObject<EpcX2> (); |
|
267 Ptr<LteEnbNetDevice> enb1LteDev = enb1->GetDevice (0)->GetObject<LteEnbNetDevice> (); |
|
268 uint16_t enb1CellId = enb1LteDev->GetCellId (); |
|
269 NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId); |
|
270 |
|
271 Ptr<EpcX2> enb2X2 = enb2->GetObject<EpcX2> (); |
|
272 Ptr<LteEnbNetDevice> enb2LteDev = enb2->GetDevice (0)->GetObject<LteEnbNetDevice> (); |
|
273 uint16_t enb2CellId = enb2LteDev->GetCellId (); |
|
274 NS_LOG_LOGIC ("LteEnbNetDevice #2 = " << enb2LteDev << " - CellId = " << enb2CellId); |
|
275 |
|
276 enb1X2->AddX2Interface (enb1CellId, enb1X2Address, enb2CellId, enb2X2Address); |
|
277 enb2X2->AddX2Interface (enb2CellId, enb2X2Address, enb1CellId, enb1X2Address); |
|
278 |
|
279 enb1LteDev->GetRrc ()->AddX2Neighbour (enb2LteDev->GetCellId ()); |
|
280 enb2LteDev->GetRrc ()->AddX2Neighbour (enb1LteDev->GetCellId ()); |
|
281 } |
|
282 |
|
283 |
|
284 void |
|
285 PointToPointEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi) |
|
286 { |
|
287 NS_LOG_FUNCTION (this << imsi << ueDevice ); |
|
288 |
|
289 m_mme->AddUe (imsi); |
|
290 m_sgwPgwApp->AddUe (imsi); |
|
291 |
|
292 |
|
293 } |
|
294 |
|
295 void |
|
296 PointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer) |
|
297 { |
|
298 NS_LOG_FUNCTION (this << ueDevice << imsi); |
|
299 |
|
300 // we now retrieve the IPv4 address of the UE and notify it to the SGW; |
|
301 // we couldn't do it before since address assignment is triggered by |
|
302 // the user simulation program, rather than done by the EPC |
|
303 Ptr<Node> ueNode = ueDevice->GetNode (); |
|
304 Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> (); |
|
305 NS_ASSERT_MSG (ueIpv4 != 0, "UEs need to have IPv4 installed before EPS bearers can be activated"); |
|
306 int32_t interface = ueIpv4->GetInterfaceForDevice (ueDevice); |
|
307 NS_ASSERT (interface >= 0); |
|
308 NS_ASSERT (ueIpv4->GetNAddresses (interface) == 1); |
|
309 Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal (); |
|
310 NS_LOG_LOGIC (" UE IP address: " << ueAddr); m_sgwPgwApp->SetUeAddress (imsi, ueAddr); |
|
311 |
|
312 m_mme->AddBearer (imsi, tft, bearer); |
|
313 Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> (); |
|
314 if (ueLteDevice) |
|
315 { |
|
316 ueLteDevice->GetNas ()->ActivateEpsBearer (bearer, tft); |
|
317 } |
|
318 } |
|
319 |
|
320 |
|
321 Ptr<Node> |
|
322 PointToPointEpcHelper::GetPgwNode () |
|
323 { |
|
324 return m_sgwPgw; |
|
325 } |
|
326 |
|
327 |
|
328 Ipv4InterfaceContainer |
|
329 PointToPointEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices) |
|
330 { |
|
331 return m_ueAddressHelper.Assign (ueDevices); |
|
332 } |
|
333 |
|
334 |
|
335 |
|
336 Ipv4Address |
|
337 PointToPointEpcHelper::GetUeDefaultGatewayAddress () |
|
338 { |
|
339 // return the address of the tun device |
|
340 return m_sgwPgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal (); |
|
341 } |
|
342 |
|
343 |
|
344 } // namespace ns3 |