Výukový program síťového simulátoru ns-3. Kapitola 5

Výukový program síťového simulátoru ns-3. Kapitola 5
kapitola 1,2
kapitola 3
kapitola 4

5 Nastavení
5.1 Použití logovacího modulu
5.1.1 Přehled protokolování
5.1.2 Povolit protokolování
5.1.3 Přidání logování do vašeho kódu
5.2 Použití argumentů příkazového řádku
5.2.1 Přepsání výchozích hodnot atributů
5.2.2 Zachytávání vlastních příkazů
5.3 Použití systému sledování
5.3.1 Trasování ASCII
Analýza ASCII tras
5.3.2 Sledování PCAP

Kapitola 5

Nastavení

5.1 Použití logovacího modulu

Již jsme se krátce podívali na modul protokolování ns-3 pohledem na skript první.cc. V této kapitole se blíže podíváme na možná použití logovacího subsystému.

5.1.1 Přehled protokolování

Mnoho velkých systémů podporuje nějaký druh zařízení pro protokolování zpráv a ns-3 není výjimkou. V některých případech se do "konzole operátora" (což je obvykle stderr na systémech založených na Unixu) zapisují pouze chybové zprávy. Na jiných systémech se mohou zobrazovat varovné zprávy a také podrobnější informace. V některých případech se pro výstup ladicích zpráv používají protokolovací nástroje, které mohou výstup rychle rozmazat.

SubHRD použitý v ns-3 předpokládá, že všechny tyto úrovně informačního obsahu jsou užitečné, a my poskytujeme selektivní, vrstvený přístup k protokolování zpráv. Protokolování lze zcela zakázat, povolit pro jednotlivé komponenty nebo globálně. K tomuto účelu slouží nastavitelné úrovně informačního obsahu. Logovací modul ns-3 poskytuje relativně jednoduchý způsob, jak získat užitečné informace z vaší simulace.

Měli byste pochopit, že poskytujeme obecný mechanismus – trasování – pro extrahování dat z vašich modelů, což by mělo být preferovaným výstupem pro simulace (další informace o našem systému trasování viz výukový program v sekci 5.3). Protokolování by mělo být preferovanou metodou pro získávání informací o ladění, varování, chybových zpráv nebo pro rychlý výstup zpráv z vašich skriptů nebo modelů kdykoli.

V současné době systém definuje sedm úrovní (typů) zpráv protokolu v rostoucím pořadí informačního obsahu.

  • LOG_ERROR - protokolování chybových zpráv (související makro: NS_LOG_ERROR);
  • LOG_WARN - Protokolovat varovné zprávy (související makro: NS_LOG_WARN);
  • LOG_DEBUG - Protokolovat relativně vzácné speciální ladicí zprávy (související makro: NS_LOG_DEBUG);
  • LOG_INFO - registrace informačních zpráv o průběhu programu (související makro: NS_LOG_INFO);
  • LOG_FUNCTION – Zaznamenává zprávy popisující každou volanou funkci (dvě související makra: NS_LOG_FUNCTION, používané pro členské funkce, a NS_LOG_FUNCTION_NOARGS, používané pro statické funkce);
  • LOG_LOGIC - protokolování zpráv popisujících logický tok v rámci funkce (související makro: NS_LOG_LOGIC);
  • LOG_ALL - Zaznamenává vše výše uvedené (žádné přidružené makro).
    Pro každý typ (LOG_TYPE) existuje také LOG_LEVEL_TYPE, který, pokud je použit, umožňuje kromě jeho vlastní úrovně protokolovat všechny úrovně nad ním. (V důsledku toho jsou LOG_ERROR a LOG_LEVEL_ERROR a LOG_ALL a LOG_LEVEL_ALL funkčně ekvivalentní.) Například povolení LOG_INFO povolí pouze zprávy poskytované makrem NS_LOG_INFO, zatímco povolení LOG_LEVEL_INFO zahrne také zprávy poskytované makry NS_LOG_DEBUG, NS_RNS.LOG_WARN.

Poskytujeme také nepodmíněné protokolovací makro, které se zobrazuje vždy, bez ohledu na úroveň protokolování nebo komponentu výběru.

  • NS_LOG_UNCOND - Bezpodmínečné protokolování přidružené zprávy (žádná přidružená úroveň protokolování).

Každá úroveň může být dotazována jednotlivě nebo kumulativně. Protokolování lze konfigurovat pomocí proměnné prostředí sh NS_LOG nebo protokolováním volání systémové funkce. Jak bylo ukázáno dříve, protokolovací systém má dokumentaci Doxygen a nyní je vhodný čas si ji prohlédnout, pokud jste tak ještě neudělali.

Nyní, když jste si podrobně přečetli dokumentaci, využijme tyto znalosti k získání zajímavých informací z ukázkového skriptu scratch/myfirst.cckteré jste již sestavili.

5.1.2 Povolit protokolování

Použijme proměnnou prostředí NS_LOG ke spuštění dalších protokolů, ale nejprve, abyste se zorientovali, spusťte poslední skript jako dříve,

$ ./waf --run scratch/myfirst

Měli byste vidět známý výstup z prvního ukázkového programu ns-3

$ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' 'build'
finished successfully (0.413s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

Ukazuje se, že „odeslané“ a „přijaté“ zprávy, které vidíte výše, jsou ve skutečnosti protokolované zprávy od Aplikace UdpEchoClient и Aplikace UdpEchoServer. Klientskou aplikaci můžeme například požádat o vytištění dalších informací nastavením úrovně protokolování prostřednictvím proměnné prostředí NS_LOG.

Od této chvíle budu předpokládat, že používáte shell podobný sh, který používá syntaxi "VARIABLE=value". Pokud používáte shell podobný csh, budete muset mé příklady převést na syntaxi "hodnota proměnné setenv", kterou tyto shelly vyžadují.

V současné době klientská aplikace UDP echo odpovídá na následující řádek kódu scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Umožňuje úroveň protokolování LOG_LEVEL_INFO. Když předáme příznak úrovně protokolování, ve skutečnosti povolíme tuto úroveň a všechny nižší úrovně. V tomto případě jsme povolili NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN a NS_LOG_ERROR. Můžeme zvýšit úroveň protokolování a získat více informací bez změn skriptu a rekompilace nastavením proměnné prostředí NS_LOG takto:

$ export NS_LOG=UdpEchoClientApplication=level_all

Nastavíme tedy proměnnou sh shellu NS_LOG na následující hodnotu,

UdpEchoClientApplication=level_all

Na levé straně zadání je název přihlášené komponenty, kterou chceme nakonfigurovat, a na pravé straně je příznak, který pro ni chceme použít. V tomto případě povolíme v aplikaci všechny úrovně ladění. Pokud skript spustíte s takto nastaveným NS_LOG, logovací systém ns-3 přijme změny a měli byste vidět následující výstup:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Další informace o ladění poskytované aplikací jsou nyní na úrovni NS_LOG_FUNCTION. Zobrazuje každou instanci volání funkce během provádění skriptu. Obecně platí, že ve funkcích metody je vhodnější použít (minimálně)NS_LOG_FUNCTION (this)... Použití NS_LOG_FUNCTION_NOARGS ()
pouze ve statických funkcích. Pamatujte však, že systém ns-3 nemusí podporovat žádnou funkci protokolování. Rozhodnutí o tom, kolik informací se zaznamená, je ponecháno na vývojáři jednotlivých modelů. V případě aplikací echo je k dispozici velké množství protokolovacích výstupů.

Nyní můžete zobrazit protokol volání funkcí, která aplikace provedla. Když se podíváte pozorně, všimnete si dvojtečky mezi řádkem Aplikace UdpEchoClient a název metody, kde můžete očekávat operátor rozsahu C++ (: :). Toto je záměrné.

Toto ve skutečnosti není název třídy, ale název logovací komponenty. Pokud existuje shoda mezi zdrojovým souborem a třídou, je to obvykle název třídy, ale měli byste si uvědomit, že to ve skutečnosti není název třídy a místo dvojtečky je tam jedna dvojtečka. Toto je způsob, který vám pomůže koncepčně oddělit název logovací fazole od názvu třídy relativně jemným způsobem.

V některých případech však může být obtížné určit, která metoda ve skutečnosti generuje zprávu protokolu. Pokud se podíváte na text výše, možná se divíte, kde je řádek "Received 1024 bytes from 10.1.1.2" Tento problém můžete vyřešit nastavením úrovně prefix_func do proměnné prostředí NS_LOG. Zkuste následující:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Všimněte si, že uvozovky jsou nezbytné, protože svislá čára, kterou používáme k reprezentaci operace OR, je také spojka potrubí Unix. Nyní, když spustíte skript, uvidíte, že systém protokolování zajišťuje, že každá zpráva v daném protokolu má předponu s názvem komponenty.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Nyní můžete vidět, že všechny zprávy přicházející z klientské aplikace UDP echo jsou jako takové identifikovány. Zpráva "Received 1024 bytes from 10.1.1.2“ je nyní jasně identifikován jako pocházející z klientské aplikace echo. Zbývající zpráva musí pocházet z aplikace serveru UDP echo. Tuto komponentu můžeme povolit zadáním seznamu komponent oddělených dvojtečkou do proměnné prostředí NS_LOG.

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
               UdpEchoServerApplication=level_all|prefix_func'

Upozornění: Ve výše uvedeném příkladu textu budete muset odstranit znak nového řádku za dvojtečkou (:), který se používá k formátování dokumentu. Nyní, když spustíte skript, uvidíte všechny zprávy protokolu z klientských a serverových echo aplikací. Můžete vidět, že to může být velmi užitečné při ladění.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
UdpEchoServerApplication:HandleRead(): Echoing packet
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Někdy je také užitečné mít možnost vidět čas simulace, ve kterém byla zpráva protokolu vygenerována. To lze provést přidáním bitu OR prefix_time:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: UdpEchoServerApplication=level_all|prefix_func|prefix_time'

Opět budete muset odstranit výše uvedený znak nového řádku. Pokud nyní skript spustíte, měli byste vidět následující výstup:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Vezměte prosím na vědomí, že konstruktor pro Server UdpEcho bylo voláno během simulace 0 sekund. Ve skutečnosti se to stane před zahájením simulace, ale čas je zobrazen jako nula sekund. Totéž platí pro zprávu konstruktoru UdpEchoClient.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Připomeňme si, že skript scratch/first.cc spustil aplikaci echo server jednu sekundu před začátkem simulace. Nyní můžete vidět, že metoda Spusťte aplikaci server je skutečně volán v první sekundě. Můžete si také všimnout, že klient echo se spustí ve druhé sekundě simulace, jak jsme se ptali ve skriptu.

Nyní můžete během hovoru sledovat průběh simulace ScheduleTransmit v klientovi, který volá zpětné volání HandleRead Send v aplikaci serveru echo. Všimněte si, že uplynulý čas pro odeslání paketu přes spojení point-to-point je 3,69 milisekund. Můžete vidět, že server echo zaprotokoluje zprávu, že odpověděl na paket, a po zpoždění kanálu uvidíte, že klient echo obdrží paket echo ve své metodě HandleRead.

V této simulaci se toho děje hodně, aniž byste si toho všimli. Celý proces ale můžete velmi snadno sledovat povolením všech logovacích komponent v systému. Zkuste nastavit proměnnou NS_LOG na následující hodnotu,

$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'

Výše uvedená hvězdička je zástupný znak pro komponentu protokolování. To bude zahrnovat všechny položky ve všech komponentách použitých v simulaci. Nebudu zde reprodukovat výstup (v době psaní tohoto článku produkuje 1265 řádků výstupu pro jeden echo paket), ale tyto informace můžete přesměrovat do souboru a zobrazit si je ve svém oblíbeném editoru.

$ ./waf --run scratch/myfirst > log.out 2>&1

Osobně používám tuto extrémně podrobnou verzi protokolování, když mám problém a netuším, kde se stala chyba. Spouštění kódu mohu sledovat poměrně snadno, aniž bych nastavoval zarážky a procházel kód v ladicím programu. Mohu jen upravit výstup ve svém oblíbeném editoru a hledat, co očekávám, a vidět, že se stane něco, co jsem nečekal. Jakmile mám obecnou představu o tom, co se nedaří, skočím do ladicího programu, abych problém prohloubil. Tento typ výstupu může být zvláště užitečný, když váš skript provede něco zcela neočekávaného. Pokud používáte pouze debugger, můžete zcela přehlédnout zvrat. Díky registraci jsou takové obraty patrné.

5.1.3 Přidání logování do vašeho kódu

Do svých simulací můžete přidat nové položky voláním komponenty protokolu z více maker. Udělejme to ve skriptu myfirst.cc, který máme v adresáři „čisté“. Připomeňme, že jsme v tomto scénáři definovali komponentu protokolování:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Jste si vědomi toho, že můžete povolit protokolování všech zpráv z této komponenty nastavením proměnné prostředí NS_LOG na různých úrovních. Pojďme do toho a přidejte do skriptu nějaké položky. Makro používané k přidávání zpráv na úrovni informací do protokolu je NS_LOG_INFO. Přidejte zprávu (těsně předtím, než začneme vytvářet uzly), která vám sdělí, že skript je ve fázi „Vytváření topologie“. To se provádí v následujícím fragmentu kódu,
Otevřít scratch/myfirst.cc ve svém oblíbeném editoru a přidejte řádek,
NS_LOG_INFO ("Creating Topology");
těsně před řádky,

NodeContainer nodes;
nodes.Create (2);

Nyní zkompilujte skript pomocí WAFa vymažte proměnnou NS_LOG, abyste deaktivovali stream protokolování, který jsme povolili dříve:

$ ./waf
$ export NS_LOG=
Теперь, если вы запустите скрипт,
$ ./waf --run scratch/myfirst

Nová zpráva se nezobrazí, protože přidružená komponenta protokolování (FirstScriptExample) nebyla povolena. Chcete-li zobrazit vaši zprávu, musíte povolit komponentu protokolování FirstScriptExample s úrovní ne nižší než NS_LOG_INFO. Pokud chcete pouze vidět tuto konkrétní úroveň protokolování, můžete ji povolit takto,

$ export NS_LOG=FirstScriptExample=info

Pokud nyní skript spustíte, uvidíte novou zprávu „Creating Topology“,

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
Creating Topology
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

5.2 Použití argumentů příkazového řádku

5.2.1 Přepsání výchozích hodnot atributů

Dalším způsobem, jak změnit chování skriptů ns-3 bez úprav nebo sestavování, je použití argumentů příkazového řádku. Poskytujeme mechanismus pro analýzu argumentů příkazového řádku a automatické nastavení lokálních a globálních proměnných na základě výsledků.

Prvním krokem při použití systému argumentů příkazového řádku je deklarace analyzátoru příkazového řádku. To je docela snadné (ve vašem hlavním programu), jako v následujícím kódu,

int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}

Tento jednoduchý dvouřádkový úryvek je ve skutečnosti velmi užitečný sám o sobě. Otevírá dveře do globálního systému proměnných a atributů ns-3. Přidejme dva řádky kódu na začátek funkce hlavního skriptu scratch/myfirst.cc. Pokračujeme, zkompilujeme skript a spustíme jej, při spuštění požádáme o pomoc následovně,

$ ./waf --run "scratch/myfirst --PrintHelp"

Tento příkaz se zeptá Waf spustit skript škrábnout/můj první a předejte mu argument příkazového řádku — PrintHelp. Uvozovky jsou povinné k označení programu, pro který je argument určen. Analyzátor příkazového řádku argument zjistí — PrintHelp a zobrazí odpověď,

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.

Nyní se podíváme na možnost —PrintAtributes. O atributovém systému ns-3 jsme se již zmínili při studiu skriptu first.cc. Viděli jsme následující řádky kódu,

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

a řekli to Rychlost přenosu dat je vlastně atribut PointToPointNetDevice. K zobrazení atributů použijeme analyzátor argumentů příkazového řádku PointToPointNetDevice. Seznam nápovědy říká, co musíme poskytnout TypeId. Toto je název třídy, do které patří příslušné atributy. V našem případě tomu tak bude ns3::PointToPointNetDevice. Pojďme stále vpřed, vstupme,

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"

Systém vytiskne všechny atributy tohoto typu síťového zařízení. Uvidíte, že mezi atributy v seznamu jsou

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
The default data rate for point to point links

Toto je výchozí hodnota, kterou systém použije při vytváření objektu PointToPointNetDevice. Tuto výchozí hodnotu přepíšeme pomocí parametru Atribut в PointToPointHelper vyšší. Použijme výchozí hodnoty pro zařízení a kanály typu point-to-point. Za tímto účelem odstraníme hovory SetDeviceAttribute и SetChannelAttribute z myfirst.cc, který máme v čistém adresáři.

Váš skript by měl nyní jednoduše deklarovat PointToPointHelper a neprovádějte žádné instalační operace, jak je uvedeno v příkladu níže,

...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...

Pokračujte a vytvořte nový skript pomocí Waf (./waff) a vraťme se a zahrňte nějakou položku z aplikace serveru UDP echo a zahrňte předponu času.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Pokud skript spustíte, měli byste vidět následující výstup:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Připomeňme, že když jsme se naposledy podívali na čas simulace, v okamžiku přijetí paketu serverem echo to bylo 2,00369 sekund.

2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1

Nyní obdrží paket za 2.25732 sekundy. Je to proto, že jsme jednoduše resetovali přenosovou rychlost PointToPointNetDevice z pěti megabitů za sekundu na výchozí hodnotu, která je 32768 bitů za sekundu. Pokud bychom nahradili nový DataRate pomocí příkazového řádku, mohli bychom naši simulaci opět urychlit. Uděláme to následovně, podle vzorce implikovaného prvkem nápovědy:

$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"

To vrátí atribut DataRate na výchozí hodnotu XNUMX megabitů za sekundu. Jste překvapeni výsledkem? Ukazuje se, že abychom vrátili původní chování skriptu, musíme také nastavit zpoždění kanálu tak, aby odpovídalo rychlosti světla. Můžeme požádat systém příkazového řádku, aby vytiskl atributy kanálu, stejně jako jsme to udělali pro síťové zařízení:

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"

Zjistíme, že atribut zpoždění kanálu je nastaven následovně:

--ns3::PointToPointChannel::Delay=[0ns]:
Transmission delay through the channel

Poté můžeme prostřednictvím systému příkazového řádku nastavit obě tyto výchozí hodnoty.

$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"

v tomto případě obnovíme čas, který jsme měli, když jsme ve skriptu explicitně nastavili DataRate a Delay:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.00369s Received 1024 bytes from 10.1.1.1
2.00369s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Všimněte si, že paket je přijat serverem znovu po 2,00369 sekundách. Tímto způsobem bychom vlastně mohli nastavit kterýkoli z atributů použitých ve skriptu. Konkrétně bychom mohli nastavit atributy MaxPackets na jiné hodnoty UdpEchoClient.

Jak byste to použili? Zkus to. Nezapomeňte, že musíte zakomentovat místo, kde přepíšeme výchozí hodnotu atributu a explicitně nastavíme MaxPackets ve scénáři. Poté musíte skript znovu sestavit. Můžete také použít příkazový řádek k získání nápovědy k syntaxi pro nastavení nové výchozí hodnoty atributu. Jakmile to pochopíte, můžete ovládat počet balíčků zobrazených na příkazovém řádku. Protože jsme pilní lidé, náš příkazový řádek by měl vypadat nějak takto:

$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms
--ns3::UdpEchoClient::MaxPackets=2"

Přirozená otázka, která v tomto bodě vyvstává, je, jak vědět o existenci všech těchto atributů. Systém příkazového řádku má v této věci opět funkci nápovědy. Pokud požádáme příkazový řádek o pomoc, měli bychom vidět:

$ ./waf --run "scratch/myfirst --PrintHelp"
myfirst [Program Arguments] [General Arguments]
General Arguments:
--PrintGlobals: Print the list of globals.
--PrintGroups: Print the list of groups.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintTypeIds: Print all TypeIds.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintHelp: Print this help message.

Pokud vyberete argument "PrintGroups", měli byste vidět seznam všech registrovaných skupin TypeId. Názvy skupin jsou konzistentní s názvy modulů ve zdrojovém adresáři (i když velkými písmeny). Tisk všech informací najednou by byl příliš objemný, takže je k dispozici další filtr pro tisk informací podle skupin. Opět se tedy zaměříme na modul point-to-point:

./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in group PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeader

Zde najdete dostupná jména TypeId pro vyhledávání atributů, například v
--PrintAttributes = ns3 :: PointToPointChanneljak je uvedeno výše.

Dalším způsobem, jak se dozvědět o atributech, je Doxygen ns‑3. Existuje stránka se seznamem všech atributů registrovaných v simulátoru.

5.2.2 Zachytávání vlastních příkazů

Můžete také přidat své vlastní háčky prostřednictvím systému příkazového řádku. To se provádí zcela jednoduše pomocí metody analyzátoru příkazového řádku Přidaná hodnota.
Pomocí této funkce určíme počet balíčků, které se mají zobrazit, zcela jiným způsobem. Přidejme lokální proměnnou tzv nPackets do funkce hlavní. Nastavíme ji na jednu, aby odpovídala našemu předchozímu výchozímu chování. Aby mohl analyzátor příkazového řádku tuto hodnotu změnit, musíme tuto hodnotu zachytit v analyzátoru. Děláme to přidáním hovoru Přidaná hodnota. Jdi a změň skript scratch/myfirst.cc takže začněte s následujícím kódem,

int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
cmd.Parse (argc, argv);
...

Přejděte dolů k bodu ve skriptu, kde nastavujeme atribut MaxPackets a změňte jej tak, aby byl nastaven na proměnnou nPackets namísto konstanty 1, jak je znázorněno níže.

echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));

Pokud nyní spustíte skript a zadáte argument -PrintHelp, měli byste vidět argument nového uživatele. uvedené na displeji nápovědy. zadejte,

$ ./waf --run "scratch/myfirst --PrintHelp"
Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.403s)
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.
User Arguments:
--nPackets: Number of packets to echo

Pokud chcete změnit počet přenášených paketů, můžete tak učinit nastavením argumentu příkazového řádku - -nPackets.

$ ./waf --run "scratch/myfirst --nPackets=2"

Nyní byste měli vidět

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
Sent 1024 bytes to 10.1.1.2
3.25732s Received 1024 bytes from 10.1.1.1
3.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Nyní jste odeslali dva balíčky. Docela jednoduché, že?
Můžete vidět, že jako uživatel ns-3 můžete použít systém argumentů příkazového řádku k manipulaci s globálními hodnotami a atributy. Pokud jste autorem modelu, můžete ke svým objektům přidat nové atributy a budou automaticky dostupné pro konfiguraci vašim uživatelům prostřednictvím systému příkazového řádku. Pokud jste autorem skriptu, můžete do svých skriptů přidávat nové proměnné a bez problémů je zapojit do systému příkazového řádku.

5.3 Použití systému sledování

Celým smyslem modelování je generovat výstup pro další studium a systém sledování ns-3 je pro to hlavním mechanismem. Protože ns-3 je program v C++, lze použít standardní prostředky pro generování výstupu z programu C++:

#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}

Můžete dokonce použít protokolovací modul k přidání malé struktury do vašeho řešení. Existuje mnoho známých problémů způsobených tímto přístupem, a proto jsme poskytli obecný subsystém sledování událostí, který tyto problémy řeší.

Hlavní cíle systému sledování ns-3 jsou:

  • Pro základní úlohy by měl systém sledování umožňovat uživateli generovat standardní sledování pro oblíbené zdroje a vybírat objekty, které generují sledování;

  • Středně pokročilí uživatelé by měli být schopni rozšířit systém sledování o změnu generovaného výstupního formátu nebo vložit nové zdroje sledování, aniž by bylo nutné upravovat jádro simulátoru;

  • Pokročilí uživatelé mohou upravit jádro simulátoru a přidat nové zdroje trasování a jímky. Trasovací systém ns-3 je postaven na principech nezávislých sledovacích zdrojů a přijímačů a také jednotného mechanismu pro připojení zdrojů ke spotřebitelům.

Trasovací systém ns-3 je postaven na principech nezávislých trasovacích zdrojů a přijímačů a také jednotného mechanismu pro připojení zdrojů k přijímačům. Zdroje trasování jsou objekty, které mohou signalizovat události vyskytující se v simulaci a poskytují přístup k podkladovým datům, která nás zajímají. Zdroj trasování může například indikovat, kdy síťové zařízení přijalo paket, a zpřístupnit obsah paketu zainteresovaným trasovacím přijímačům.

Zdroje trasování samy o sobě jsou k ničemu, pokud nejsou „spojeny“ s jinými částmi kódu, které skutečně dělají něco užitečného s informacemi poskytovanými jímkou. Sledovače jsou spotřebitelé událostí a dat poskytovaných zdroji sledování. Můžete například vytvořit jímku trasování, která (po připojení ke zdroji trasování z předchozího příkladu) vytiskne části, které vás zajímají v přijatém paketu.

Důvodem tohoto explicitního oddělení je umožnit uživatelům připojit nové typy jímek ke stávajícím zdrojům trasování, aniž by museli upravovat a znovu kompilovat jádro simulátoru. Takže ve výše uvedeném příkladu může uživatel definovat nový sledovací modul ve svém skriptu a připojit jej k existujícímu zdroji sledování definovanému v jádru simulace pouze úpravou uživatelského skriptu.

V tomto tutoriálu si projdeme některé z předdefinovaných zdrojů a jímek a ukážeme si, jak je lze nakonfigurovat s minimálním úsilím ze strany uživatele. Informace o pokročilé konfiguraci trasování, včetně rozšíření jmenného prostoru trasování a vytváření nových zdrojů trasování, najdete v příručce ns-3 nebo v částech s postupy.

5.3.1 Trasování ASCII

ns-3 poskytuje pomocnou funkci, která poskytuje nízkoúrovňový systém trasování, který vám pomůže s podrobnostmi při nastavování jednoduchých trasování paketů. Pokud tuto funkci povolíte, uvidíte výstup v souborech ASCII. Pro ty, kteří jsou obeznámeni s výstupem ns-2, je tento typ trasování podobný out.tr, který je generován mnoha skripty.

Pojďme k věci a do našeho skriptu scratch/myfirst.cc přidejte nějaké výsledky trasování ASCII. Těsně před hovorem Simulator :: Run (), přidejte následující řádky kódu:
AsciiTraceHelper ascii;

pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Stejně jako mnoho jiných idiomů ns-3, tento kód používá pomocný objekt k vytváření ASCII tras. Druhý řádek obsahuje dvě vnořená volání metod. Metoda "uvnitř". CreateFileStream() používá idiom anonymního objektu k vytvoření objektu toku souboru na zásobníku (bez názvu objektu) a předá jej volané metodě. V budoucnu se tomu budeme věnovat hlouběji, ale vše, co v tuto chvíli potřebujete vědět, je, že vytváříte objekt, který představuje soubor s názvem myfirst.tr a přeneste jej do ns-3. ns-3 svěřujeme péči o vytvořený objekt po celou dobu jeho životnosti, během níž řeší problémy způsobené málo známým (záměrným) omezením spojeným s konstruktory kopírování objektů C++ stream.

Externí hovor EnableAsciiAll() sdělí asistentovi, že chcete zahrnout trasování ASCII do vaší simulace pro všechna připojení zařízení typu point-to-point a že chcete, aby (specifikované) přijímače trasování zaznamenávaly informace o pohybu paketů ve formátu ASCII.

Pro ty, kdo jsou obeznámeni s ns-2, jsou sledované události ekvivalentní známým sledovacím bodům, které zaznamenávají události "+", "-", "d" a "r".
Nyní můžete vytvořit skript a spustit jej z příkazového řádku:

$ ./waf --run scratch/myfirst

Stejně jako mnohokrát předtím uvidíte několik zpráv od Waf a poté „'build' úspěšně dokončeno“ s několika zprávami ze spuštěného programu.

Při spuštění program vytvoří soubor s názvem myfirst.tr. Vzhledem k povaze práce Waf, ve výchozím nastavení se soubor nevytváří v místním adresáři, ale v adresáři nejvyšší úrovně úložiště. Pokud chcete změnit cestu, kam se stopy ukládají, můžete ji zadat pomocí parametru Waf --cwd. To jsme ještě neudělali, takže abychom se mohli podívat na trasovací soubor ASCII myfirst.tr ve vašem oblíbeném editoru, budeme muset přejít do adresáře nejvyšší úrovně našeho úložiště.

Analýza ASCII tras

Je tam spousta informací v poměrně husté podobě, ale první věcí, které si musíte všimnout, je, že soubor se skládá z jednotlivých řádků. To bude jasně viditelné, pokud rozšíříte zobrazovací okno.

Každý řádek v souboru odpovídá události trasování. V tomto případě sledujeme události v přenosové frontě přítomné v každém síťovém zařízení typu point-to-point v simulaci. Přenosová fronta je fronta, kterou musí projít každý paket pro spojení typu point-to-point. Všimněte si, že každý řádek ve trasovacím souboru začíná jedním znakem (a za ním je mezera). Tento symbol bude mít následující význam:

+: ve frontě zařízení došlo k operaci řazení do fronty;
-: ve frontě zařízení došlo k operaci načítání prvku;
d: paket byl zahozen, obvykle proto, že fronta byla plná;
r: Paket byl přijat síťovým zařízením.

Podívejme se blíže na první řádek trasovacího souboru. Rozdělím to na části (s odsazením pro přehlednost) a číslo řádku vlevo:

0 +
1 2
2 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
3 ns3::PppHeader (
4   Point-to-Point Protocol: IP (0x0021))
6   ns3::Ipv4Header (
7     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
8     length: 1052 10.1.1.1 > 10.1.1.2)
9     ns3::UdpHeader (
10      length: 1032 49153 > 9)
11      Payload (size=1024)

První částí této události rozšířeného trasování (řádek 0) je operace. Máme zde symbol +, který odpovídá operaci řazení do fronty na přenos. Druhá část (řádek 1) je doba simulace vyjádřená v sekundách. Možná si pamatujete, na co jsme se ptali Aplikace UdpEchoClient začněte odesílat pakety za dvě sekundy. Zde vidíme potvrzení, že se tak skutečně děje.

Další část příkladu trasování (z řádku 2) ukazuje, který zdroj trasování vygeneroval tuto událost (s uvedením trasování jmenného prostoru). Jmenný prostor trasování si můžete představit podobně jako jmenný prostor souborového systému. Kořenem jmenného prostoru je NodeList. To odpovídá kontejneru spravovanému v hlavním kódu ns-3. Obsahuje všechny uzly, které jsou ve skriptu vytvořeny. Stejně jako souborový systém může mít adresáře ve svém kořenovém adresáři, NodeList můžeme mít mnoho uzlů. Řádek /NodeList/0 tedy odkazuje na nulový uzel v seznamu NodeList, který obvykle považujeme za "uzel 0". Každý uzel má seznam zařízení, která byla nainstalována. Tento seznam se nachází jako další ve jmenném prostoru. Můžete vidět, že tato událost trasování pochází Seznam zařízení/0, což je nulové zařízení nainstalované v uzlu.

Další podřetězec, $ ns3 :: PointToPointNetDevice, říká, které zařízení je na pozici nula: seznam zařízení s nulovým uzlem. Připomeňme, že operace + nalezená v řádku 0 znamenala, že do přenosové fronty zařízení byl přidán prvek. To se odráží v posledních segmentech „trasy“: TxQueue/Enqueue.

Zbývající sekce trasování by měly být poměrně intuitivní. Řádky 3-4 označují, že paket je zapouzdřen v protokolu point-to-point. Řádky 5-7 ukazují, že paket má hlavičku verze IP4 a pochází z adresy IP 10.1.1.1 a určené pro 10.1.1.2. Řádky 8-9 ukazují, že tento paket má hlavičku UDP a konečně řádek 10 ukazuje, že užitečné zatížení je očekávaných 1024 bajtů.

Další řádek ve trasovacím souboru ukazuje, že stejný paket byl vytažen z přenosové fronty na stejném uzlu.

Třetí řádek v souboru trasování ukazuje, že paket byl přijat síťovým zařízením na hostiteli serveru echo. Níže jsem reprodukoval událost.

0 r
1 2.25732
2 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
3   ns3::Ipv4Header (
4     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
5     length: 1052 10.1.1.1 > 10.1.1.2)
6     ns3::UdpHeader (
7       length: 1032 49153 > 9)
8       Payload (size=1024)

Všimněte si, že operace trasování je nyní r a doba simulace byla zvýšena na 2,25732 sekund. Pokud jste postupovali pečlivě podle návodu, znamená to, že jste ponechali DataRate a Link Delay síťových zařízení na výchozích hodnotách. Tento čas by měl být známý, jak jste viděli v předchozí části.

Položka jmenného prostoru zdroje trasování (řádek 2) byla upravena tak, aby odrážela, že tato událost pochází z uzlu 1 (/NodeList/1) a paket je přijat zdrojem trasování (/MacRx). Mělo by pro vás být poměrně snadné sledovat pohyb paketu topologií pohledem na zbývající stopy v souboru.

5.3.2 Sledování PCAP

Pomocníky zařízení ns-3 lze také použít k vytvoření trasovacích souborů ve formátu .pcap. Akronym pcap (obvykle psáno malými písmeny) znamená zachycení paketů a je to vlastně API, které zahrnuje definování formátu souboru .pcap. Nejoblíbenější program, který umí číst a zobrazovat tento formát, je Wireshark (dříve nazývané Éterický). Existuje však mnoho analyzátorů trasování provozu, které používají tento formát paketů. Doporučujeme uživatelům, aby používali mnoho dostupných nástrojů k analýze tras pcap. V tomto tutoriálu se zaměříme na prohlížení tras pcap pomocí tcpdump.

Povolení trasování pcap se provádí pomocí jednoho řádku kódu.

pointToPoint.EnablePcapAll ("myfirst");

Vložte tento řádek kódu za trasovací kód ASCII, který jsme právě přidali scratch/myfirst.cc. Všimněte si, že jsme předali pouze řetězec "myfirst", nikoli "myfirst.pcap" nebo něco podobného. Důvodem je, že parametr je předpona, nikoli celé jméno souboru. Během simulace asistent skutečně vytvoří trasovací soubor pro každé zařízení typu point-to-point. Názvy souborů budou vytvořeny pomocí předpony, čísla uzlu, čísla zařízení a přípony ".pcap".

Pro náš vzorový skript nakonec uvidíme soubory s názvem "myfirst-0-0.pcap"A"myfirst-1-0.pcap", což jsou trasování pcap pro uzel 0-zařízení 0 a uzel 1-zařízení 0, resp. Jakmile přidáte řádek kódu pro povolení trasování pcap, můžete skript spustit obvyklým způsobem:

$ ./waf --run scratch/myfirst

Pokud se podíváte do adresáře nejvyšší úrovně vaší distribuce, měli byste vidět tři soubory: trasovací soubor ASCII myfirst.tr, které jsme dříve studovali, soubory myfirst-0-0.pcap и myfirst-1-0.pcap - nové soubory pcap, které jsme právě vygenerovali.

Čtení výstupu pomocí tcpdump

Prozatím je nejjednodušším způsobem, jak zobrazit soubory pcap, použít tcpdump.

$ tcpdump -nn -tt -r myfirst-0-0.pcap
reading from file myfirst-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
tcpdump -nn -tt -r myfirst-1-0.pcap
reading from file myfirst-1-0.pcap, link-type PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024

Na skládce myfirst-0-0.pcap (klientské zařízení) můžete vidět, že echo paket je odeslán po 2 sekundách simulace. Pokud se podíváte na druhou skládku (myfirst-1-0.pcap), uvidíte, že paket je přijat za 2,257324 sekund. Ve druhém výpisu uvidíte, že paket je vrácen v 2.257324 sekundy a nakonec, že ​​paket byl přijat zpět klientem v prvním výpisu v 2.514648 sekund.

Výstup čtení s Wireshark

Pokud nejste obeznámeni s Wireshark, existuje webová stránka, ze které si můžete stáhnout programy a dokumentaci: http://www.wireshark.org/. Wireshark je grafické uživatelské rozhraní, které lze použít k zobrazení těchto trasovacích souborů. Pokud máte Wireshark, můžete otevřít kterýkoli ze trasovacích souborů a zobrazit obsah, jako byste pakety zachytili pomocí snifferu paketů.

Zdroj: www.habr.com

Přidat komentář