Ostatnimi czasy intensywnie studiuję temat protokołów routingu w sieciach typu ad hoc. Zbudowanie odpowiedniej infrastruktury, posiadającej wiele komputerów, routerów oraz ich właściwe sparowanie znacznie wykracza poza moje możliwości logistyczno-finansowe, to też zdecydowałem się na ich symulacje. Użyłem w tym celu ns-3 Network Simulator, i właśnie o tym narzędziu oraz o pisaniu symulacji będzie dzisiejszy wpis.
Symulację piszemy w języku C++ (można też w Python), umieszczając pliki w folderze scratch programu. W przypadku języka C++ pliki muszą mieć rozszerzenie "cc". Zalecane jest by w przypadku większej liczby plików pogrupować je w projekty poprzez utworzenie folderów. Należy wtedy jednak pamiętać o zdefiniowaniu funkcji main, która zostanie uruchomiona jako punkt startowy symulacji. Kompilacja plików robi się automatycznie podczas uruchomienia symulacji, sam program odpala się w następujący sposób:
./waf run --nazwa naszego pliku, ale bez rozszerzenia cc
Na czym polega filozofia pisania symulacji w ns-3?
Właściwie sprowadza się ona do odpowiedniego skonfigurowania topologi sieci, którą byśmy chcieli badać. Odpalenia zestawu aplikacji (symulowania ruchu), a następnie zebrania wyników i ich obrobienie. Ns-3 posiada gotowe komponenty, które znacznie przyspieszają całą pracę. Topologie sieci budujemy w oparciu o strukturę Node (węzeł). Może to być dowolne urządzenie w sieci (niekoniecznie tylko host). Do każdego węzła przypisujemy urządzenia, które ma posiadać (np. karta sieciowa i jej parametry), jak również zestaw aplikacji (można pisać własne, albo użyć już dostarczonych), które mają być na nim uruchomione. Dobrze to ilustruje obrazek poniżej (zapożyczony z prezentacji ns3 intro slides autorstwa Adil Alsuhaim).

Na szczęście do naszej dyspozycji jest masa helperów, które przyspieszą cały ten proces i skonfigurują ustaloną przez nas grupę węzłów. Poniżej przykład jak można utworzyć topologię sieci WIFI typu ad hoc, zaczerpnięty z http://www.lrc.ic.unicamp.br/ofswitch13/doc/html/wifi-hidden-terminal_8cc_source.html.
// 1. Create 3 nodes
NodeContainer nodes;
nodes.Create (3);
// 2. Place nodes
for (size_t i = 0; i < 4; ++i)
{
nodes.Get(i)-> AggregateObject (CreateObject<ConstantPositionMobilityModel> ());
}
// 3. Create propagation loss matrix
Ptr<MatrixPropagationLossModel> lossModel = CreateObject<MatrixPropagationLossModel> ();
lossModel->SetDefaultLoss (200); // set default loss to 200 dB (no link)
for (size_t i = 0; i < 3; ++i)
{
lossModel->SetLoss (nodes.Get (i)-> GetObject<MobilityModel>(), nodes.Get (i+1)->GetObject<MobilityModel>(), 50); // set symmetric loss i <-> i+1 to 50 dB
}
// 4. Create & setup wifi channel
Ptr<YansWifiChannel> wifiChannel = CreateObject <YansWifiChannel> ();
wifiChannel->SetPropagationLossModel (lossModel);
wifiChannel->SetPropagationDelayModel (CreateObject <ConstantSpeedPropagationDelayModel> ());
// 5. Install wireless devices
WifiHelper wifi;
wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200"));
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
"DataMode",StringValue ("DsssRate11Mbps"));
YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
wifiPhy.SetChannel (wifiChannel);
WifiMacHelper wifiMac;
wifiMac.SetType ("ns3::AdhocWifiMac");
NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, nodes);
// 6. Install TCP/IP stack & assign IP addresses
InternetStackHelper internet;
internet.Install (nodes);
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.0.0.0", "255.0.0.0");
ipv4.Assign (devices);
Jak widać powyżej tworzymy 3 węzły, na których konfigurujemy sieć WIFI typu ad hoc i ustawiamy adresy ip dla sieci 10.0.0.0. By uczynić symulację bardziej realną używamy tak zwanej tablicy utraty propagacji sygnału na wskutek np. działania warunków pogodowych. Ważna kwestią, o której jeszcze nie wspomniałem to kwestia kanałów. Powyżej używamy jednego z nich tj. YansWifiChannel. Kanały pozwalają określić relacje, połączyć poszczególne węzły. W przypadku sieci typu ad hoc, YansWifiChannel musi połączyć węzły na zasadzie "każdy z każdym". Gdy już mamy skonfigurowaną topologie naszej symulowanej sieci, pozostaje nam zasymulować jakiś ruch przy użyciu aplikacji. Poniżej przykład żądania i odpowiedzi na ping, który zostanie wysłany w ściśle określonym przez nas przedziale czasowym.
ApplicationContainer serverApps = echoServer.Install (nodes.Get (3));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (3), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
Jeśli ktoś z Was złapał bakcyla, lub potrzebuje coś sobie potestować to polecam filmik poniżej, który bardziej szczegółowo to wszystko omawia.