Δημιουργία Τοπολογιών
Δημιουργώντας μια Τοπολογία Δικτύου Αρτηρίας
Σε αυτή την ενότητα πρόκειται να επεκτείνουμε την ικανότητά μας να διαχειριζόμαστε
τις συσκευές δικτύου του ns-3 και τα κανάλια, ώστε να καλύψουμε ένα παράδειγμα ενός δικτύου
αρτηρίας. O ns-3 παρέχει μια δικτυακή συσκευή και ένα κανάλι που εμείς αποκαλούμε CSMA
(Carrier Sense Multiple Access).
Η CSMA συσκευή του ns-3 μοντελοποιεί ένα απλό δίκτυο στο πνεύμα του Ethernet.
Ένα πραγματικό Ethernet χρησιμοποιεί το CSMA/CD (Carrier Sense Multiple Access with
Collision Detection) σχήμα με εκθετικά αυξανόμενη οπισθοχώρηση για τη διεκδίκηση του
διαμοιραζόμενου μέσου μετάδοσης. Η CSMA συσκευή του ns-3 και το αντίστοιχο κανάλι
μοντελοποιούν μόνο ένα υποσύνολο από αυτά.
Όπως έχουμε δει αντικείμενα βοηθών για τοπολογίες σημείου-προς-σημείο όταν κατασκευάζαμε
τέτοιες τοπολογίες, σε αυτή την ενότητα θα δούμε ισοδύναμους CSMA βοηθούς τοπολογίας. Η
εμφάνιση και η λειτουργία αυτών των βοηθών θα πρέπει να σας φαίνεται αρκετά οικεία.
Παραθέτουμε ένα παραδειγματικό σενάριο στον κατάλογο examples/tutorial. Το σενάριο αυτό
«πατάει» πάνω στο σενάριο first.cc και προσθέτει ένα δίκτυο CSMA στην προσομοίωση
σημείου-προς-σημείο που έχουμε ήδη εξετάσει. Ανοίξτε το examples/tutorial/second.cc
στον επεξεργαστή κειμένου της προτίμησής σας. Θα πρέπει να έχετε ήδη δει αρκετό κώδικα του
ns-3 ώστε να μπορείτε να καταλάβετε τα περισσότερα από όσα συμβαίνουν σε αυτό το παράδειγμα, αλλά
εμείς θα δούμε ολόκληρο το σενάριο και θα εξετάσουμε κάποια από τα αποτελέσματα.
Όπως και στο παράδειγμα του first.cc (και σε όλα τα παραδείγματα του ns-3), το αρχείο
ξεκινάει με μια γραμμή κατάστασης για τον emacs και κάποιες κοινές δηλώσεις GPL.
Ο πραγματικός κώδικας ξεκινάει με τη φόρτωση αρχείων συμπερίληψης ενοτήτων (module includes), όπως έγινε
και στο παράδειγμα first.cc.
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"
Ένα πράγμα που μπορεί να είναι εκπληκτικά χρήσιμο είναι ένα μικρό κομμάτι τέχνης σε
ASCII, το οποίο δείχνει ένα «σχέδιο» της τοπολογίας δικτύου που κατασκευάζεται στο
παράδειγμα. Θα βρείτε ένα παρόμοιο «σχέδιο» στα περισσότερα από τα παραδείγματά μας.
Σε αυτήν την περίπτωση, μπορείτε να δείτε ότι πρόκειται να επεκτείνουμε το παράδειγμά
μας από σημείο-προς-σημείο (ο σύνδεσμος μεταξύ των κόμβων n0 και n1 παρακάτω) συνδέοντας
ένα δίκτυο αρτηρίας στη δεξιά του πλευρά. Παρατηρήστε ότι αυτή είναι η προεπιλεγμένη
τοπολογία δικτύου καθώς μπορείτε ουσιαστικά να αλλάξετε τον αριθμό των κόμβων που
δημιουργούνται στο LAN. Εάν θέσετε τη nCsma στην τιμή ένα, θα υπάρχουν συνολικά δύο
κόμβοι στο LAN (CSMA κανάλι) — ένας απαιτούμενος κόμβος και ένας «επιπλέον» κόμβος. Εξ
ορισμού υπάρχουν τρεις «επιπλέον» κόμβοι, όπως φαίνεται παρακάτω:
// Default Network Topology
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0
Έπειτα χρησιμοποιείται (used) ο χώρος ονομάτων του ns-3 και ορίζεται ένα στοιχείο
καταγραφής. Όλα αυτά είναι όπως ήταν και στο first.cc, οπότε δεν υπάρχει κάτι
καινούργιο ακόμα.
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");
Το κυρίως πρόγραμμα ξεκινά με λίγο διαφορετική εξέλιξη. Χρησιμοποιούμε μια σημαία
verbose για να καθορίσουμε εάν θα ενεργοποιηθούν τα στοιχεία καταγραφής των
UdpEchoClientApplication και UdpEchoServerApplication. Αυτή η σημαία
τίθεται εξ ορισμού ως αληθής (τα στοιχεία καταγραφής είναι ενεργοποιημένα) αλλά μας
επιτρέπει να απενεργοποιήσουμε την καταγραφή κατά τη διάρκεια της προς-τα-πίσω δοκιμής
αυτού του παραδείγματος.
Θα δείτε μερικό οικείο κώδικα, ο οποίος θα σας επιτρέψει να αλλάξετε τον αριθμό
των συσκευών στο CSMA δίκτυο μέσω ορισμάτων στη γραμμή εντολών. Κάναμε κάτι παρόμοιο
όταν επιτρέψαμε να αλλάξει ο αριθμός των πακέτων που στέλνονται στην ενότητα με τα
ορίσματα της γραμμής εντολών. Η τελευταία γραμμή διασφαλίζει ότι έχετε τουλάχιστον
έναν «επιπλέον» κόμβο.
Ο κώδικας αποτελείται από παραλλαγές του API που έχουμε εξετάσει πιο πριν, οπότε θα
πρέπει να είστε πλήρως άνετοι με τον ακόλουθο κώδικα σε αυτό το σημείο του οδηγού.
bool verbose = true;
uint32_t nCsma = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc, argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma;
Το επόμενο βήμα είναι η δημιουργία δύο κόμβων, τους οποίους θα συνδέσουμε μέσω
ενός συνδέσμου σημείου-προς-σημείο. Χρησιμοποιείται ο NodeContainer για να
το κάνει αυτό, ακριβώς όπως το έκανε και στο first.cc.
NodeContainer p2pNodes;
p2pNodes.Create (2);
Έπειτα, δηλώνουμε άλλον ένα NodeContainer, ο οποίος θα περιέχει τους κόμβους
που θα είναι μέρος του δικτύου αρτηρίας (CSMA). Αρχικά, πρέπει να δημιουργήσουμε
το αντικείμενο container αυτό καθαυτό.
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
Η επόμενη γραμμή κώδικα παίρνει (Gets) τον πρώτο κόμβο (δηλαδή σα να έχει ένα ευρετήριο
που να περιέχει έναν κόμβο) από τον container κόμβων σημείου-προς-σημείο και τον προσθέτει
στον container των κόμβων που θα δεχτούν τις CSMA συσκευές. Ο εν λόγω κόμβος πρόκειται
να καταλήξει με μια συσκευή σημείου-προς-σημείο και μια CSMA συσκευή. Έπειτα δημιουργούμε
έναν αριθμό από «επιπλέον» κόμβους που συνθέτουν το υπόλοιπο του CSMA δικτύου. Δεδομένου ότι
έχουμε ήδη έναν κόμβο στο CSMA δίκτυο – εκείνον που θα έχει και μια δικτυακή συσκευή
σημείου-προς-σημείο και μια CSMA, ο αριθμός των «επιπλέον» κόμβων ισούται με τον αριθμό
των κόμβων που επιθυμείτε στο κομμάτι του CSMA πλην ενός.
Το επόμενο κομμάτι κώδικα θα πρέπει να σας είναι ήδη πολύ οικείο. Δημιουργούμε έναν
PointToPointHelper και καθορίζουμε τα σχετικά προεπιλεγμένα Attributes, έτσι ώστε
να δημιουργήσουμε έναν πομπό με ταχύτητα μετάδοσης πέντε megabit ανά δευτερόλεπτο στις
συσκευές που δημιουργήθηκαν με τη χρήση του βοηθού και μια καθυστέρηση δύο μιλιδευτερολέπτων
στα κανάλια που δημιουργήθηκαν από τον βοηθό.
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
Έπειτα δημιουργούμε ένα NetDeviceContainer για να καταγράφει τις δικτυακές
συσκευές σημείου-προς-σημείο και εγκαθιστούμε (Install) τις συσκευές στους κόμβους
σημείου-προς-σημείο.
Αναφέραμε προηγουμένως πως πρόκειται να δείτε έναν βοηθό για CSMA συσκευές και
κανάλια, και οι επόμενες γραμμές εισάγουν αυτά τα στοιχεία. Ο CsmaHelper λειτουργεί
όπως ένας PointToPointHelper, μόνο που δημιουργεί και συνδέει CSMA συσκευές και
κανάλια. Στην περίπτωση ενός ζεύγους CSMA συσκευής και καναλιού, παρατηρήστε ότι ο
ρυθμός δεδομένων καθορίζεται μέσω ενός Attribute του καναλιού αντί για κάποιο
Attribute της συσκευής. Αυτό συμβαίνει επειδή ένα πραγματικό CSMA δίκτυο δεν επιτρέπει
την ανάμειξη, για παράδειγμα, συσκευών 10Base-T και 100Base-T σε ένα δεδομένο κανάλι. Πρώτα
θέτουμε το ρυθμό δεδομένων στα 100 megabit ανά δευτερόλεπτο, και μετά θέτουμε την καθυστέρηση
του καναλιού στα 6560 νανοδευτερόλεπτα (έχοντας επιλέξει αυθαίρετα ότι χρειάζεται 1
νανοδευτερόλεπτο ανά πόδι αντί ανά τμήματα 100 μέτρων). Σημειώστε ότι μπορείτε να καθορίσετε
ένα Attribute χρησιμοποιώντας τον ενδογενή τύπο δεδομένων του.
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
Με τον ίδιο τρόπο που δημιουργήσαμε ένα NetDeviceContainer ώστε να περιέχει τις
συσκευές που δημιουργούνται από τον PointToPointHelper, έτσι δημιουργούμε ένα
NetDeviceContainer για να περιέχει τις συσκευές που δημιουργούνται από τον CsmaHelper
μας. Καλούμε τη μέθοδο Install του CsmaHelper ώστε να εγκαταστήσουμε τις συσκευές
στους κόμβους του csmaNodes NodeContainer.
Τώρα έχουμε δημιουργήσει τους κόμβους μας, τις συσκευές και τα κανάλια μας, αλλά δεν έχουμε
καμία εγκατεστημένη στοίβα πρωτοκόλλου. Όπως και στο σενάριο του first.cc, θα
χρησιμοποιήσουμε τον InternetStackHelper για να εγκαταστησουμε αυτές τις στοίβες.
InternetStackHelper stack;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);
Θυμηθείτε ότι πήραμε έναν από τους κόμβους από τον container p2pNodes και τον
προσθέσαμε στον container csmaNodes. Έτσι χρειάζεται μόνο να εγκαταστήσουμε
τις στοίβες στον εναπομείναντα κόμβου του p2pNodes, και σε όλους τους κόμβους
του container csmaNodes, ώστε να καλύψουμε όλους τους κόμβους της προσομοίωσης.
Όπως και στο παράδειγμα του first.cc, πρόκειται να χρησιμοποιήσουμε τον
Ipv4AddressHelper για την ανάθεση των IP διευθύνσεων στις διεπαφές των συσκευών
μας. Αρχικά χρησιμοποιούμε το δίκτυο 10.1.1.0 για να δημιουργήσουμε τις δύο
διευθύνσεις που χρειάζονται για τις δύο σημείο-προς-σημείο συσκευές μας.
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
Θυμηθείτε ότι αποθηκεύουμε τις δημιουργημένες διεπαφές σε ένα container ώστε να κάνουμε
πιο εύκολη την ανάκτηση πληροφορίας διευθυνσιοδότησης αργότερα, για χρήση κατά το στήσιμο
των εφαρμογών.
Τώρα πρέπει να αναθέσουμε IP διευθύνσεις στις διεπαφές των CSMA συσκευών μας. Η
λειτουργία πραγματοποιείται όπως και στην περίπτωση σημείου-προς-σημείο, με τη διαφορά
ότι τώρα πραγματοποιούμε τη λειτουργία σε ένα container που έχει ένα μεταβλητό αριθμό
από CSMA συσκευές — θυμηθείτε ότι κάναμε τον αριθμό των CSMA συσκευών μεταβλητό μέσω
ορίσματος στη γραμμή εντολών. Οι CSMA συσκευές θα συσχετιστούν σε αυτήν την περίπτωση
με τις IP διευθύνσεις από τη διεύθυνση δικτύου 10.1.2.0, όπως βλέπετε παρακάτω.
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
Τώρα έχουμε δημιουργήσει μια τοπολογία, αλλά χρειαζόμαστε εφαρμογές. Αυτή η ενότητα
θα είναι κατά βάση παρόμοια με το τμήμα των εφαρμογών στο first.cc, αλλά εδώ θα
εκκινήσουμε τον εξυπηρετητή σε έναν από τους κόμβους ο οποίος έχει μια CSMA συσκευή ,
και τον πελάτη στον κόμβο που έχει μόνο μία συσκευή σημείου-προς-σημείο.
Αρχικά, στήνουμε έναν εξυπηρετητή echo. Δημιουργούμε έναν UdpEchoServerHelper και
παρέχουμε μια απαιτούμενη τιμή για Attribute στον δημιουργό, η οποία είναι ο αριθμός
port του εξυπηρετητή. Θυμηθείτε ότι αυτό το port μπορεί να αλλάξει αργότερα, εάν το επιθυμείτε,
με τη χρήση της μεθόδου SetAttribute, αλλά εμείς απαιτούμε να δίνεται ως όρισμα στον δημιουργό.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
Θυμηθείτε ότι ο csmaNodes NodeContainer περιέχει έναν από τους κόμβους που
δημιουργήθηκαν στο δίκτυο σημείου-προς-σημείο και nCsma «επιπλέον» κόμβους.
Εκεί που θέλουμε να φτάσουμε είναι στον τελευταίο από τους “επιπλέον” κόμβους. Οπότε,
ο εύκολος τρόπος για να το σκεφτούμε είναι πως εάν δημιουργήσουμε έναν «επιπλέον» CSMA κόμβο,
τότε αυτός θα βρίσκεται στην πρώτη θέση του container csmaNodes. Επαγωγικά, εάν
δημιουργήσουμε nCsma «επιπλέον» κόμβους, ο τελευταίος θα είναι στη θέση nCsma.
Μπορείτε να το δείτε αυτό στο Get της πρώτης γραμμής του κώδικα.
Η εφαρμογή του πελάτη εγκαθίσταται ακριβώς όπως και στο σενάριο του first.cc. Ξανά,
παρέχουμε τα απαιτούμενα Attributes στον UdpEchoClientHelper μέσα στον δημιουργό
(σε αυτή την περίπτωση την απομακρυσμένη διεύθυνση και το port). Λέμε στον πελάτη να
στέλνει πακέτα στον εξυπηρετητή που μόλις έχουμε εγκαταστήσει στον τελευταίο από τους
«επιπλέον» CSMA κόμβους. Εγκαθιστούμε τον πελάτη στον αριστερότερο κόμβο του σημείου-προς-σημείο
κομματιού που φαίνεται στην απεικόνιση της τοπολογίας.
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
Καθώς έχουμε στήσει στην ουσία ένα διαδίκτυο εδώ, χρειαζόμαστε κάποια μορφή διαδικτυακής
δρομολόγησης. Ο ns-3 παρέχει αυτό που εμείς αποκαλούμε «καθολική δρομολόγηση» (global routing), προκειμένου
να σας βοηθήσει. Η καθολική δρομολόγηση εκμεταλλεύεται το γεγονός ότι ολόκληρο το διαδίκτυο
είναι προσβάσιμο μέσα στην προσομοίωση και εκτελείται διαμέσου όλων των κόμβων που
έχουν δημιουργηθεί για την προσομοίωση — αναλαμβάνει την δύσκολη δουλειά του καθορισμού της
δρομολόγησης για εσάς χωρίς να χρειάζεται να ρυθμίσετε εσείς δρομολογητές.
Βασικά, αυτό που συμβαίνει είναι ότι κάθε κόμβος συμπεριφέρεται σα να ήταν ένας δρομολογητής
OSPF, ο οποίος επικοινωνεί άμεσα και μαγικά με όλους τους άλλους δρομολογητές στο παρασκήνιο.
Κάθε κόμβος παράγει δηλώσεις των συνδέσεων και τις μεταδίδει κατευθείαν σε έναν διαχειριστή
καθολικής δρομολόγησης, ο οποίος χρησιμοποιεί αυτή την καθολική πληροφορία για να κατασκευάσει
τους πίνακες δρομολόγησης σε κάθε κόμβο. Η εγκατάσταση μιας τέτοιας μορφής δρομολόγησης γίνεται
σε μία γραμμή:
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
Έπειτα ενεργοποιούμε την καταγραφή pcap. Η πρώτη γραμμή του κώδικα που ενεργοποιεί την
καταγραφή pcap στον βοηθό σημείου-προς-σημείο θα πρέπει να σας είναι οικεία μέχρι τώρα.
Η δεύτερη γραμμή ενεργοποιεί την καταγραφή pcap στον CSMA βοηθό και υπάρχει μία επιπλέον
παράμετρος που δεν έχετε συναντήσει ακόμα.
pointToPoint.EnablePcapAll ("second");
csma.EnablePcap ("second", csmaDevices.Get (1), true);
Το CSMA δίκτυο είναι ένα πολλαπλό σημείο-προς-σημείο δίκτυο. Αυτό σημαίνει ότι
μπορούν να υπάρχουν (και όντως υπάρχουν σε αυτήν την περίπτωση) πολλαπλά τερματικά σημεία
σε ένα κοινόχρηστο μέσο. Κάθε ένα από αυτά τα τερματικά σημεία έχει μια δικτυακή συσκευή
που συσχετίζεται με αυτό. Υπάρχουν δύο βασικές εναλλακτικές για τη συλλογή πληροφορίας ιχνών
από ένα τέτοιο δίκτυο. Η μία είναι η δημιουργία ενός αρχείου καταγραφής για κάθε μία δικτυακή
συσκευή και η αποθήκευση μόνο των πακέτων που μεταδίδονται ή καταναλώνονται από αυτήν την
δικτυακή συσκευή. Μια άλλη εναλλακτική είναι η επιλογή μίας από τις συσκευές και η μετάβασή της
σε μεικτή κατάσταση. Έτσι, αυτή μόνο η συσκευή «παρακολουθεί» (sniff) το δίκτυο για όλα τα πακέτα
και τα αποθηκεύει σε ένα μοναδικό αρχείο pcap. Με αυτόν τον τρόπο λειτουργεί, για παράδειγμα, το
tcpdump. Εκείνη η τελική παράμετρος λέει στον CSMA βοηθό εάν πρέπει ή όχι να κανονίσει ώστε να
δεσμεύει πακέτα σε μεικτή κατάσταση.
Σε αυτό το παράδειγμα, θα επιλέξουμε μία από τις συσκευές στο CSMA δίκτυο και θα της
ζητήσουμε να εκτελέσει μία μεικτή παρακολούθηση (promiscuous sniff) του δικτύου,
προσομοιώνοντας έτσι αυτό που θα έκανε το tcpdump. Εάν ήσασταν σε ένα μηχάνημα με Linux,
θα μπορούσατε να δώσετε την εντολή tcpdump -i eth0 προκειμένου να πάρετε τα ίχνη.
Σε αυτήν την περίπτωση, προσδιορίζουμε τη συσκευή χρησιμοποιώντας την csmaDevices.Get(1),
η οποία επιλέγει την πρώτη συσκευή στον container. Θέτοντας την τελευταία παράμετρο ως αληθή
ενεργοποιούνται οι μεικτές καταγραφές (promiscuous captures).
Το τελευταίο μέρος του κώδικα απλά τρέχει και καθαρίζει μετά την προσομοίωση, όπως
και στο παράδειγμα του first.cc.
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
Προκειμένου να εκτελέσετε αυτό το παράδειγμα, αντιγράψτε το παράδειγμα σεναρίου του
second.cc στον κατάλογο scratch και χρησιμοποιήστε το waf για το build όπως κάνατε
και στο παράδειγμα first.cc. Εάν είστε στον υψηλότερου επιπέδου κατάλογο του αποθετηρίου,
απλά πληκτρολογήστε,
$ cp examples/tutorial/second.cc scratch/mysecond.cc
$ ./waf
Προειδοποίηση: χρησιμοποιούμε το αρχείο second.cc ως ένα από τα τεστ οπισθοδρόμησής μας
προκειμένου να επικυρώσουμε ότι δουλεύει όπως ακριβώς πιστεύουμε ότι πρέπει να δουλεύει, ώστε
η εμπειρία σας με τον παρόντα οδηγό να είναι θετική. Αυτό σημαίνει ότι υπάρχει ήδη ένα
εκτελέσιμο αρχείο με το όνομα second σε αυτό το project. Για να αποφύγετε οποιαδήποτε
σύγχυση σχετικά με το τι εκτελείτε, παρακαλούμε κάντε τη μετονομασία σε mysecond.cc που
προτείνεται παραπάνω.
Εάν ακολουθείτε αυτόν τον οδηγό με θρησκευτική ευλάβεια (το κάνετε, έτσι δεν είναι;) θα
έχετε ακόμα τη μεταβλητή NS_LOG τεθειμένη, οπότε καθαρίστε αυτή τη μεταβλητή και
εκτελέστε το πρόγραμμα.
$ export NS_LOG=
$ ./waf --run scratch/mysecond
Δεδομένου ότι έχουμε στήσει τις εφαρμογές UDP echo για καταγραφή, ακριβώς όπως κάναμε
και στο first.cc, θα δείτε μια παρόμοια έξοδο όταν τρέξετε το σενάριο.
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.415s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.2.4
Θυμηθείτε ότι το πρώτο μήνυμα, “Sent 1024 bytes to 10.1.2.4”, είναι ο UDP echo πελάτης
που στέλνει ένα πακέτο στον εξυπηρετητή. Στην προκειμένη περίπτωση, ο εξυπηρετητής είναι
σε ένα διαφορετικό δίκτυο (10.1.2.0). Το δεύτερο μήνυμα, “Received 1024 bytes from 10.1.1.1”,
είναι από τον UDP echo εξυπηρετητή, και δημιουργήθηκε όταν αυτός έλαβε το echo πακέτο. Το τελικό
μήνυμα, “Received 1024 bytes from 10.1.2.4”, είναι από τον echo πελάτη, και δείχνει ότι αυτός
έχει λάβει το echo μήνυμα από τον εξυπηρετητή.
Εάν τώρα πάτε και δείτε στον κατάλογο του υψηλότερου επιπέδου, θα βρείτε τρία αρχεία καταγραφής
ιχνών:
second-0-0.pcap second-1-0.pcap second-2-0.pcap
Ας δούμε για μια στιγμή την ονομασία αυτών των αρχείων. Όλα έχουν την ίδια μορφή,
<name>-<node>-<device>.pcap. Για παράδειγμα, το πρώτο αρχείο στην παραπάνω απαρίθμηση
είναι το second-0-0.pcap, το οποίο είναι το αρχείο ιχνών pcap από τον κόμβο μηδέν, από
τη συσκευή μηδέν. Αυή είναι η συσκευή σημείου-προς-σημείο στον κόμβο μηδέν. Το αρχείο
second-1-0.pcap είναι το αρχείο ιχνών pcap για τη συσκευή μηδέν στον κόμβο ένα, η οποία
είναι επίσης μια δικτυακή συσκευή σημείου-προς-σημείο. Και το αρχείο second-2-0.pcap είναι
το αρχείο ιχνών pcap για τη συσκευή μηδέν στον κόμβο δύο.
Εάν ανατρέξετε πίσω στην απεικόνιση της τοπολογίας στην αρχή αυτής της ενότητας,
θα δείτε ότι ο κόμβος μηδέν είναι ο αριστερότερος κόμβος στη σύνδεση σημείου-προς-σημείο,
και ο κόμβος ένα είναι ο κόμβος που έχει τόσο μια σημείου-προς-σημείο συσκευή όσο και μια
CSMA συσκευή. Θα δείτε ότι ο κόμβος δύο είναι ο πρώτος «επιπλέον» κόμβος στο CSMA
δίκτυο και ότι η συσκευή μηδέν του έχει επιλεγεί ως η συσκευή που θα καταγράψει τα
ίχνη στην μεικτή κατάσταση.
Τώρα, ας ακολουθήσουμε το echo πακέτο μέσα στο διαδίκτυο. Αρχικά, εκτελέστε το tcpdump
του αρχείου ιχνών για τον αριστερότερο κόμβο σημείου-προς-σημείο — τον κόμβο μηδέν.
$ tcpdump -nn -tt -r second-0-0.pcap
Θα πρέπει να σας εμφανιστούν τα περιεχόμενα του αρχείου pcap:
reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Η πρώτη γραμμή του αποτελέσματος δείχνει ότι ο τύπος σύνδεσης είναι PPP (point-to-point ή
σημείο-προς-σημείο) κάτι το οποίο αναμέναμε. Έπειτα θα δείτε ότι το echo πακέτο φεύγει από
τον κόμβο μηδέν μέσω της συσκευής που αντιστοιχίζεται στην IP διεύθυνση 10.1.1.1 με κατεύθυνση
προς την IP διεύθυνση 10.1.2.4 (ο δεξιότερος κόμβος του CSMA). Αυτό το πακέτο θα κινηθεί πάνω από
τη σύνδεση σημείου-προς-σημείο και θα παραληφθεί από τη δικτυακή συσκευή σημείου-προς-σημείο στον
κόμβο ένα. Ας ρίξουμε μια ματιά:
$ tcpdump -nn -tt -r second-1-0.pcap
Θα πρέπει τώρα να βλέπετε το αποτέλεσμα των ιχνών pcap της άλλης πλευράς του συνδέσμου
σημείου-προς-σημείο:
reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Εδώ βλέπουμε ότι ο τύπος σύνδεσης είναι επίσης PPP όπως θα περιμέναμε. Βλέπετε ότι το πακέτο
από την IP διεύθυνση 10.1.1.1 (το οποίο στάλθηκε τη χρονική στιγμή 2.000000 δευτερολέπτων)
με κατεύθυνση προς την IP διεύθυνση 10.1.2.4 εμφανίστηκε στη διεπαφή αυτή. Τώρα, εσωτερικά σε
αυτόν τον κόμβο, το πακέτο θα προωθηθεί στη διεπαφή CSMA και θα πρέπει να το δούμε να εξέρχεται
από τη συσκευή με κατεύθυνση προς τον τελικό του προορισμό.
Θυμηθείτε ότι επιλέξαμε τον κόμβο δύο ως τον κόμβο που θα παρακολουθήσει (promiscuous sniffer)
το CSMA δίκτυο, οπότε ας δούμε στο second-2-0.pcap για να διαπιστώσουμε αν είναι όντως εκεί.
$ tcpdump -nn -tt -r second-2-0.pcap
Θα πρέπει να βλέπετε τώρα τα αποτελέσματα για τον κόμβο δύο, και τη συσκευή μηδέν:
reading from file second-2-0.pcap, link-type EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007710 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Όπως μπορείτε να δείτε, ο τύπος σύνδεσης είναι τώρα “Ethernet”. Κάτι νέο έχει προκύψει,
ωστόσο. Το δίκτυο αρτηρίας χρειάζεται το ARP, το Πρωτόκολλο Ανάλυσης Διευθύνσεων
(Address Resolution Protocol). Ο κόμβος ένα γνωρίζει ότι χρειάζεται να στείλει το πακέτο
στην IP διεύθυνση 10.1.2.4, αλλά δεν ξέρει τη MAC διεύθυνση του αντίστοιχου κόμβου. Εκπέμπει
στο δίκτυο CSMA (ff:ff:ff:ff:ff:ff) αναζητώντας τη συσκευή με IP διεύθυνση 10.1.2.4.
Σε αυτήν την περίπτωση, ο δεξιότερος κόμβος απαντάει λέγοντας ότι βρίσκεται στη MAC διεύθυνση
00:00:00:00:00:06. Σημειώστε ότι ο κόμβος δύο δεν εμπλέκεται άμεσα σε αυτήν την ανταλλαγή, αλλά
παρακολουθεί το δίκτυο και αναφέρει κάθε κίνηση που ανιχνεύει.
Η ανταλλαγή αυτή φαίνεται στις ακόλουθες γραμμές,
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007710 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
Τότε η συσκευή ένα στον κόμβο ένα προχωρά και στέλνει το echo πακέτο στον UDP echo εξυπηρετητή
στην IP διεύθυνση 10.1.2.4.
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
Ο εξυπηρετητής λαμβάνει το αίτημα echo και αντιστρέφει την κατεύθυνση του πακέτου προσπαθώντας
να το στείλει πίσω στην πηγή. Ο εξυπηρετητής γνωρίζει ότι αυτή η διεύθυνση είναι σε ένα άλλο
δίκτυο το οποίο μπορεί να προσπελάσει μέσω της IP διεύθυνσης 10.1.2.1. Αυτό συμβαίνει επειδή
έχουμε ενεργοποιήσει την καθολική δρομολόγηση και τα έχει ξεκαθαρίσει όλα αυτά εκ μέρους μας. Αλλά,
ο κόμβος του echo εξυπηρετητή δεν γνωρίζει τη MAC διεύθυνση του πρώτου CSMA κόμβου, οπότε πρέπει να
εκτελέσει το πρωτόκολλο ARP, όπως χρειάστηκε να κάνει και ο πρώτος CSMA κόμβος.
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
Ο εξυπηρετητής στέλνει τότε το echo πακέτο πίσω στον κόμβο προώθησης.
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Κοιτώντας πίσω στον δεξιότερο κόμβο του συνδέσμου σημείου-προς-σημείο,
$ tcpdump -nn -tt -r second-1-0.pcap
Μπορείτε να δείτε τώρα το πακέτο που έχει γίνει echo να επιστρέφει μέσω του συνδέσμου
σημείου-προς-σημείο στην τελευταία γραμμή των αποτελεσμάτων καταγραφής.
reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Τέλος, μπορείτε να δείτε πίσω στον κόμβο που ξεκίνησε το echo
$ tcpdump -nn -tt -r second-0-0.pcap
και να διαπιστώσετε ότι το πακέτο που έγινε echo φτάνει πίσω στην πηγή τη χρονική στιγμή
των 2.007602 δευτερολέπτων,
reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
Εν τέλει, θυμηθείτε ότι προσθέσαμε την δυνατότητα ελέγχου του αριθμού των CSMA συσκευών
στη προσομοίωση μέσω ορίσματος στη γραμμή εντολών. Μπορείτε να αλλάξετε αυτό το όρισμα με τον
ίδιο τρόπο όπως τότε που εξετάσαμε την αλλαγή του αριθμού των πακέτων που γίνονται echo στο
παράδειγμα first.cc. Δοκιμάστε να τρέξετε το πρόγραμμα με το αριθμό των «επιπλέον» συσκευών
να είναι ίσος με τέσσερεις:
$ ./waf --run "scratch/mysecond --nCsma=4"
Θα πρέπει τώρα να βλέπετε τα εξής:
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)
At time 2s client sent 1024 bytes to 10.1.2.5 port 9
At time 2.0118s server received 1024 bytes from 10.1.1.1 port 49153
At time 2.0118s server sent 1024 bytes to 10.1.1.1 port 49153
At time 2.02461s client received 1024 bytes from 10.1.2.5 port 9
Παρατηρήστε ότι ο εξυπηρετητής echo έχει επανατοποθετηθεί πλέον στον τελευταίο από τους CSMA κόμβους, ο οποίος είναι στη διεύθυνση 10.1.2.5 αντί της προεπιλεγμένης, 10.1.2.4.
Είναι πιθανό να μην είστε ικανοποιημένοι με ένα αρχείο καταγραφής που δημιουργείται
από έναν παρατηρητή στο CSMA δίκτυο. Μπορεί να θέλετε πραγματικά να λάβετε ίχνη από
μια μόνο συσκευή και να μην ενδιαφέρεστε για κάποια άλλη κίνηση στο δίκτυο. Αυτό
μπορείτε να το κάνετε αρκετά εύκολα.
Ας δούμε το scratch/mysecond.cc και ας προσθέσουμε εκείνον τον κώδικα που θα μας
επιτρέψει να είμαστε πιο συγκεκριμένοι. Οι βοηθοί του ns-3 παρέχουν μεθόδους που δέχονται
έναν αριθμό κόμβου και έναν αριθμό συσκευής ως παραμέτρους. Προχωρήστε και αντικαταστήστε τις
κλήσεις EnablePcap με τις παρακάτω κλήσεις.
pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false);
Γνωρίζουμε ότι θέλουμε να δημιουργήσουμε ένα αρχείο pcap με το βασικό όνομα “second”, και
επίσης γνωρίζουμε ότι η συσκευή που μας ενδιαφέρει και στις δύο περιπτώσεις πρόκειται να είναι
η μηδέν, κατά συνέπεια οι παράμετροι δεν είναι και πολύ ενδιαφέρουσες.
Προκειμένου να βρείτε τον αριθμό του κόμβου, έχετε δύο επιλογές: πρώτον, οι κόμβοι είναι
αριθμημένοι με μονότονα αύξοντα τρόπο, ξεκινώντας από το μηδέν, με τη σειρά σύμφωνα με την
οποία τους δημιουργείτε. Ένας τρόπος για να πάρετε τον αριθμό ενός κόμβου είναι να βρείτε
τον αριθμό αυτό «μηχανικά», μελετώντας τη σειρά της δημιουργίας των κόμβων. Εάν ρίξετε μια ματιά
στην απεικόνιση της τοπολογίας του δικτύου στην αρχή του αρχείου, θα δείτε ότι το κάναμε ήδη αυτό
για εσάς, και θα διαπιστώσετε ότι ο τελευταίος CSMA κόμβος είναι ο κόμβος με τον αριθμό
nCsma + 1. Αυτή η προσέγγιση μπορεί να καταστεί ενοχλητικά δύσκολη σε μεγαλύτερες
προσομοιώσεις.
Ένας εναλλακτικός τρόπος, τον οποίο χρησιμοποιούμε εδώ, είναι το να διαπιστώσετε ότι οι
NodeContainers περιέχουν δείκτες προς αντικείμενα Node του ns-3. Το αντικείμενο
Node έχει μια μέθοδο που ονομάζεται GetId, η οποία επιστρέφει την ID του κόμβου,
η οποία είναι ο αριθμός του κόμβου που ψάχνουμε. Ας πάμε να δούμε στο Doxygen για το
Node και ας εντοπίσουμε αυτή τη μέθοδο, η οποία βρίσκεται στο χαμηλότερο επίπεδο του
πυρήνα του ns-3 που έχουμε φτάσει μέχρι στιγμής. Κάποιες φορές θα χρειαστεί όντως να ψάξετε
με μεγάλη επιμέλεια για να βρείτε χρήσιμα πράγματα.
Μεταβείτε στην τεκμηρίωση του Doxygen για την έκδοσή σας (θυμηθείτε ότι μπορείτε να τη βρείτε
στον ιστότοπο του project). Μπορείτε να βρείτε την τεκμηρίωση του Node ψάχνοντας στην
καρτέλα “Classes” και κατεβαίνοντας κάτω στην “Class List” μέχρι να βρείτε το ns3::Node.
Επιλέξτε το ns3::Node και θα μεταβείτε στην τεκμηρίωση για την κλάση Node. Εάν κατεβείτε
κάτω στη μέθοδο GetId και την επιλέξετε, θα μεταβείτε σε μια λεπτομερή τεκμηρίωση της μεθόδου
αυτής. Η χρήση της μεθόδου GetId μπορεί να κάνει τον προσδιορισμό του αριθμού ενός κόμβου
πολύ ευκολότερο σε πολύπλοκες τοπολογίες.
Ας διαγράψουμε τα παλιά αρχεία καταγραφής από τον κατάλογο υψηλότερου επιπέδου, ώστε να αποφύγουμε
οποιαδήποτε σύγχυση σχετικά με το τι συμβαίνει.
Εάν κάνετε build το νέο σενάριο και εκτελέσετε την προσομοίωση θέτοντας τη μεταβλητή
nCsma στο 100,
$ ./waf --run "scratch/mysecond --nCsma=100"
θα δείτε την ακόλουθη έξοδο:
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.407s)
At time 2s client sent 1024 bytes to 10.1.2.101 port 9
At time 2.0068s server received 1024 bytes from 10.1.1.1 port 49153
At time 2.0068s server sent 1024 bytes to 10.1.1.1 port 49153
At time 2.01761s client received 1024 bytes from 10.1.2.101 port 9
Σημειώστε ότι ο echo εξυπηρετητής βρίσκεται τώρα στη διεύθυνση 10.1.2.101, γεγονός που οφείλεται
στο ότι έχουμε 100 «επιπλέον» CSMA κόμβους, μαζί με τον echo εξυπηρετητή που βρίσκεται στον
τελευταίο από αυτούς. Εάν ζητήσετε τη λίστα με τα αρχεία pcap στον κατάλογο υψηλότερου επιπέδου
θα δείτε τα εξής:
second-0-0.pcap second-100-0.pcap second-101-0.pcap
Το αρχείο καταγραφής second-0-0.pcap είναι η «αριστερότερη» συσκευή σημείου-προς-σημείο,
η οποία είναι η πηγή του πακέτου echo. Το αρχείο second-101-0.pcap αντιστοιχεί στην
δεξιότερη CSMA συσκευή στην οποία βρίσκεται ο εξυπηρετητής echo. Μπορεί να παρατηρήσατε
ότι η τελευταία παράμετρος κατά την κλήση για ενεργοποίηση της pcap καταγραφής στον κόμβο του
echo εξυπηρετητή είναι τεθειμένη ως ψευδής. Αυτό σημαίνει ότι τα ίχνη που συγκεντρώνονται σε
αυτόν τον κόμβο ήταν σε μη-μεικτή κατάσταση.
Για να διευκρινίσουμε τη διαφορά μεταξύ μεικτών και μη-μεικτών ιχνών, ζητήσαμε επιπλέον
ένα μη-μεικτό ίχνος για τον κόμβο δίπλα από τον τελευταίο. Ρίξτε μια ματιά στο tcpdump
για το αρχείο second-100-0.pcap.
$ tcpdump -nn -tt -r second-100-0.pcap
Μπορείτε τώρα να δείτε ότι ο κόμβος 100 είναι πράγματι ένας παρατηρητής κατά την ανταλλαγή echo.
Τα μόνα πακέτα που λαμβάνει είναι οι αιτήσεις ARP οι οποίες εκπέμπονται σε όλο το CSMA δίκτυο.
reading from file second-100-0.pcap, link-type EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, length 50
Δείτε τώρα το tcpdump για το αρχείο second-101-0.pcap.
$ tcpdump -nn -tt -r second-101-0.pcap
Μπορείτε τώρα να δείτε ότι ο κόμβος 101 είναι πραγματικά ο παραλήπτης της ανταλλαγής echo.
reading from file second-101-0.pcap, link-type EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.006698 ARP, Reply 10.1.2.101 is-at 00:00:00:00:00:67, length 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, length 1024
2.013803 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, length 1024
Μοντέλα, Χαρακτηριστικά και Πραγματικότητα
Αυτό το σημείο ενδείκνυται ώστε να κάνουμε μια μικρή παρένθεση και να σημειώσουμε κάτι
σημαντικό. Μπορεί να είναι φανερό σε εσάς ή μπορεί και όχι, μα όποτε κάποιος πραγματοποιεί
μια προσομοίωση, είναι σημαντικό να καταλαβαίνει ακριβώς τι μοντελοποιείται και τι όχι. Είναι
δελεαστικό, για παράδειγμα, να σκεφτεί κανείς ότι οι CSMA συσκευές και τα κανάλια που
χρησιμοποιήθηκαν στην προηγούμενη ενότητα είναι σαν αληθινές συσκευές Ethernet. Και να περιμένει
ότι το αποτέλεσμα μιας προσομοίωσης θα αντανακλά άμεσα το τι θα συμβεί σε ένα πραγματικό Ethernet.
Δεν είναι, όμως, έτσι τα πράγματα.
Ένα μοντέλο είναι, εξ ορισμού, μια αφαίρεση της πραγματικότητας. Είναι τελικά στην
κρίση του συγγραφέα του σεναρίου προσομοίωσης το να καθορίσει το λεγόμενο «εύρος της ακρίβειας»
και «την περιοχή της εφαρμοσιμότητας» της προσομοίωσης συνολικά, και κατά συνέπεια των
συστατικών μερών της.
Σε μερικές περιπτώσεις, όπως στο Csma, μπορεί να είναι σχετικά εύκολο το να καθοριστεί
τι δεν μπορεί να μοντελοποιηθεί. Διαβάζοντας την περιγραφή του μοντέλου (csma.h) μπορείτε
να διαπιστώσετε ότι δεν υπάρχει ανίχνευση συγκρούσεων στο CSMA μοντέλο, και να αποφασίσετε το
κατά πόσο εφαρμόσιμη θα είναι η χρήση του στην προσομοίωσή σας ή τι προειδοποιήσεις μπορεί
να θέλετε να συμπεριλάβετε στα αποτελέσματά σας. Σε άλλες περιπτώσεις, μπορεί να είναι
αρκετά εύκολη η ρύθμιση συμπεριφορών που ενδέχεται να μη συμβαδίζουν με την πραγματικότητα. Το να αφιερώσετε χρόνο εξετάζοντας μερικές τέτοιες περιπτώσεις θα
αποδειχτεί ότι αξίζει τον κόπο, καθώς και το να εξετάσετε πόσο εύκολα μπορείτε να παρεκκλίνετε
εκτός των ορίων της πραγματικότητας στις προσομοιώσεις σας.
Όπως θα έχετε δει, ο ns-3 παρέχει Attributes τα οποία ένας χρήστης μπορεί εύκολα
να θέσει ώστε να αλλάξει τη συμπεριφορά του μοντέλου. Θεωρήστε δύο από τα Attributes της
CsmaNetDevice: το Mtu και το EncapsulationMode. Το Mtu χαρακτηριστικό υποδηλώνει
τη Μέγιστη Μονάδα Μετάδοσης (Maximum Transmission Unit) της συσκευής. Είναι το μέγεθος της
μεγαλύτερης Μονάδας Δεδομένων του Πρωτοκόλλου (Protocol Data Unit ή PDU) που μπορεί να στείλει
η συσκευή.
Το MTU είναι εξ ορισμού στα 1500 byte στην CsmaNetDevice. Αυτή η προεπιλογή
αντιστοιχεί σε έναν αριθμό που υπάρχει στο πρότυπο RFC 894, “A Standard for the Transmission
of IP Datagrams over Ethernet Networks”. Ο αριθμός προέρχεται όντως από το μέγιστο
μέγεθος πακέτου για δίκτυα τύπου 10Base5 (full-spec Ethernet) – 1518 byte. Εάν αφαιρέσετε
το πλεόνασμα της DIX ενθυλάκωσης (DIX encapsulation overhead) για τα Ethernet πακέτα
(18 byte) θα καταλήξετε να έχετε μέγιστο δυνατό μέγεθος δεδομένων (MTU) ίσο με 1500 byte.
Κάποιοι μπορεί να παρατηρήσουν ότι το MTU για δίκτυα IEEE 802.3 είναι 1492 byte. Αυτό
συμβαίνει επειδή η ενθυλάκωση LLC/SNAP προσθέτει ένα επιπρόσθετο βάρος από byte στο πλεόνασμα του
πακέτου. Και στις δύο περιπτώσεις, το υποκείμενο υλικό μπορεί να στείλει μόνο 1518 byte, αλλά το
μέγεθος των δεδομένων είναι διαφορετικό.
Προκειμένου να καθορίσουμε την κατάσταση ενθυλάκωσης, η CsmaNetDevice παρέχει ένα
Attribute που καλείται EncapsulationMode, το οποίο μπορεί να πάρει τις
τιμές Dix ή Llc. Αυτές αντιστοιχούν στην πλαισίωση Ethernet και LLC/SNAP
κατ’ αναλογία.
Αν αφήσει κάποιος το Mtu στα 1500 byte και αλλάξει την κατάσταση ενθυλάκωσης σε Llc,
το αποτέλεσμα θα είναι ένα δίκτυο το οποίο ενθυλακώνει PDU των 1500 byte σε LLC/SNAP πλαίσια,
που έχει σα συνέπεια την ύπαρξη πακέτων των 1526 byte, κάτι που θα ήταν ανεπιτρεπτό σε πολλά δίκτυα,
καθώς αυτά μπορούν να μεταδώσουν το πολύ 1518 byte ανά πακέτο. Πιθανότατα αυτό να είχε ως
αποτέλεσμα μια προσομοίωση που κατά περίεργο τρόπο δεν θα αντανακλά την πραγματικότητα που
μπορεί εσείς να περιμένατε.
Για να κάνουμε πιο περίπλοκη την όλη υπόθεση, υπάρχουν τεράστια πλαίσια (1500 < MTU <= 9000 byte)
και υπερ-τεράστια (MTU > 9000 byte) πλαίσια που δεν είναι επίσημα επικυρωμένα από την IEEE, αλλά
είναι διαθέσιμα για κάποια δίκτυα υψηλών ταχυτήτων (Gigabit) και NIC. Κάποιος θα μπορούσε να
αφήσει την κατάσταση ενθυλάκωσης στην επιλογή Dix, και να θέσει το Attribute Mtu
σε μια CsmaNetDevice στα 64000 byte – ακόμα και αν ένα σχετικό CsmaChannel DataRate
ήταν καθορισμένο στα 10 megabit ανά δευτερόλεπτο. Αυτό θα μοντελοποιούσε στην ουσία έναν διακόπτη
Ethernet, φτιαγμένο από δίκτυα 10Base5 της δεκαετίας του 1980 συνδεδεμένα με συσκευές vampire tap
που υποστηρίζουν υπερ-τεράστια πακέτα. Αυτό σίγουρα δεν είναι κάτι που έχει φτιαχτεί στο παρελθόν,
ούτε και πρόκειται να φτιαχτεί, αλλά είναι κάτι που μπορείτε πολύ εύκολα να ρυθμίσετε εσείς.
Στο προηγούμενο παράδειγμα, χρησιμοποιήσατε τη γραμμή εντολών για να δημιουργήσετε μια
προσομοίωση η οποία είχε 100 Csma κόμβους. Θα μπορούσατε το ίδιο απλά να έχετε
δημιουργήσει μια προσομοίωση με 500 κόμβους. Εάν μοντελοποιούσατε πραγματικά το παραπάνω δίκτυο
10Base5 με τις vampire tap συσκευές, το μέγιστο μήκος ενός full-spec Ethernet καλωδίου είναι
500 μέτρα, με ελάχιστη απόσταση μεταξύ συσκευών τα 2.5 μέτρα. Κάτι που σημαίνει ότι θα μπορούσαν
να υπάρχουν μόνο 200 τέτοιες συσκευές σε ένα πραγματικό δίκτυο. Επίσης, θα μπορούσατε αρκετά εύκολα
να φτιάξετε και ένα δίκτυο εκτός των προτύπων με τον ίδιο τρόπο. Κάτι τέτοιο μπορεί να έχει ή να
μην έχει έχει ως αποτέλεσμα μια ουσιαστική προσομοίωση, δεδομένου και του τι προσπαθείτε
να μοντελοποιήσετε.
Παρόμοιες καταστάσεις μπορούν να προκύψουν σε πολλά σημεία στον ns-3 και σε οποιαδήποτε
προσομοίωση. Για παράδειγμα, μπορεί να είστε σε θέση να τοποθετήσετε κόμβους με τέτοιο τρόπο
ώστε να καταλαμβάνουν τον ίδιο χώρο την ίδια στιγμή, ή μπορεί να είστε σε θέση να ρυθμίσετε
του ενισχυτές ή τα επίπεδα θορύβου ώστε να παραβιάζουν τους βασικούς νόμους της Φυσικής.
Ο ns-3 ευνοεί γενικά την ευελιξία, και πολλά μοντέλα θα σας επιτρέψουν να θέσετε
ελεύθερα Attributes χωρίς να προσπαθήσουν να σας επιβάλλουν οποιαδήποτε αυθαίρετη
συνοχή ή συγκεκριμένη υποκείμενη προδιαγραφή.
Αυτό που θα πρέπει να κρατήσετε εσείς είναι ότι ο ns-3 θα σας παρέχει μια υπερ-ευέλικτη βάση
πάνω στην οποία μπορείτε να πειραματιστείτε. Εξαρτάται από εσάς το αν θα κατανοήσετε τι
ζητάτε από το σύστημα να κάνει και αν θα διασφαλίσετε ότι οι προσομοιώσεις που δημιουργείτε
έχουν κάποιο νόημα και κάποια σύνδεση με κάποια πραγματικότητα που καθορίζεται από εσάς.
Δημιουργώντας μια Τοπολογία Ασύρματου Δικτύου
Σε αυτήν την ενότητα θα επεκτείνουμε τις γνώσεις μας για τις δικτυακές συσκευές και τα
κανάλια του ns-3 ώστε να καλύψουμε ένα παράδειγμα ενός ασύρματου δικτύου. Ο ns-3 παρέχει
ένα σύνολο από μοντέλα τύπου 802.11 που επιχειρούν να παρέχουν μια ακριβή υλοποίηση MAC-επιπέδου
των προδιαγραφών του 802.11, και ένα «όχι-και-τόσο-αργό» μοντέλο φυσικού επιπέδου σύμφωνα με
τις προδιαγραφές του 802.11a.
Ακριβώς όπως έχουμε δει στα αντικείμενα βοηθών τοπολογίας και σημείου-προς-σημείο και CSMA όταν
κατασκευάζαμε τοπολογίες σημείου-προς σημείο, θα δούμε ανάλογους βοηθούς τοπολογίας Wifi σε
αυτήν την ενότητα. Η εμφάνιση και η λειτουργία αυτών των βοηθών θα πρέπει να σας είναι αρκετά
οικεία.
Σας παρέχουμε ένα παραδειγματικό σενάριο στον κατάλογο examples/tutorial. Το σενάριο αυτό
βασίζεται πάνω στο σενάριο second.cc και προσθέτει ένα δίκτυο Wifi. Προχωρήστε και ανοίξτε
το αρχείο examples/tutorial/third.cc στον επεξεργαστή κειμένου της προτίμησής σας. Θα έχετε
ήδη δει αρκετό κώδικα του ns-3 ώστε πλέον να μπορείτε να καταλάβετε τα περισσότερα από αυτά που
συμβαίνουν σε αυτό το παράδειγμα, αλλά υπάρχουν και μερικά νέα πράγματα, οπότε θα περιηγηθούμε κατά
μήκος ολόκληρου του σενάριου και θα εξετάσουμε κάποια από τα αποτελέσματά του.
Όπως και στο παράδειγμα second.cc (και σε όλα τα παραδείγματα του ns-3) το αρχείο
ξεκινά με μια γραμμή κατάστασης για τον emacs και κάποιες κοινές δηλώσεις GPL.
Ρίξτε μια ματιά στην ASCII τέχνη (που παρατίθεται παρακάτω), η οποία δείχνει την
προεπιλεγμένη τοπολογία δικτύου που κατασκευάζεται στο παράδειγμα. Μπορείτε να δείτε ότι
πρόκειται να επεκτείνουμε το παράδειγμά μας συνδέοντας ένα ασύρματο δίκτυο στην αριστερή
πλευρά. Παρατηρήστε ότι αυτή είναι μια προεπιλεγμένη τοπολογία δικτύου, καθώς μπορείτε
στην ουσία να αλλάξετε τον αριθμό των κόμβων που δημιουργούνται στα ενσύρματα και ασύρματα
δίκτυα. Όπως και στην περίπτωση του σεναρίου second.cc, εάν αλλάξετε τη nCsma, θα σας
δώσει έναν αριθμό από «επιπλέον« CSMA κόμβους. Με παρόμοιο τρόπο, μπορείτε να θέσετε
τη μεταβλητή nWifi ώστε να ελέγχετε πόσοι STA κόμβοι (station ή σταθμοί) θα δημιουργηθούν
στην προσομοίωση. Πάντα θα υπάρχει ένας κόμβος AP (access point ή σημείο πρόσβασης) στο
ασύρματο δίκτυο. Εξ ορισμού, υπάρχουν τρεις «επιπλέον» CSMA κόμβου και τρεις ασύρματοι STA
κόμβοι.
Ο κώδικας ξεκινά με τη φόρτωση αρχείων συμπερίληψης ενοτήτων, όπως έγινε και στο παράδειγμα
second.cc. Υπάρχουν μερικές νέες συμπεριλήψεις κώδικα που αντιστοιχούν στην ενότητα του
Wifi και στην ενότητα της κινητικότητας (mobility), για τις οποίες θα πούμε παρακάτω.
#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
Ακολουθεί η απεικόνιση της τοπολογίας δικτύου:
// Default Network Topology
//
// Wifi 10.1.3.0
// AP
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0
Μπορείτε να δείτε ότι προσθέτουμε μια καινούργια δικτυακή συσκευή στον κόμβο στην αριστερή
πλευρά της σύνδεσης σημείου-προς-σημείο, η οποία γίνεται το σημείο πρόσβασης για το ασύρματο
δίκτυο. Ένας αριθμός από ασύρματους STA κόμβους δημιουργείται ώστε να γεμίσει το νέο
δίκτυο με διεύθυνση 10.1.3.0, όπως φαίνεται στην αριστερή πλευρά της απεικόνισης.
Μετά την απεικόνιση, χρησιμοποιείται ο χώρος ονομάτων του ns-3 και ορίζεται
ένα στοιχείο καταγραφής. Όλα αυτά θα πρέπει να σας είναι αρκετά οικεία πλέον.
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");
Το κυρίως πρόγραμμα ξεκινά όπως και στο second.cc με την προσθήκη μερικών
παραμέτρων της γραμμής εντολών για την ενεργοποίηση ή απενεργοποίηση των στοιχείων καταγραφής
και για την αλλαγή του αριθμού των συσκευών που δημιουργούνται.
bool verbose = true;
uint32_t nCsma = 3;
uint32_t nWifi = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc,argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
Όπως και σε όλα τα προηγούμενα παραδείγματα, το επόμενο βήμα είναι η δημιουργία δύο κόμβων
που θα ενώνονται μέσω ενός συνδέσμου σημείου-προς-σημείο.
NodeContainer p2pNodes;
p2pNodes.Create (2);
Έπειτα, συναντάμε έναν παλιό μας γνώριμο. Δημιουργούμε έναν PointToPointHelper και
θέτουμε τα σχετικά προεπιλεγμένα Attributes, έτσι ώστε να δημιουργήσουμε έναν πομπό
με ταχύτητα μετάδοσης πέντε megabit ανά δευτερόλεπτο πάνω στις συσκευές που δημιουργήσαμε
με τη βοήθεια του βοηθού, και για να ορίσουμε καθυστέρηση δύο μιλιδευτερολέπτων στα κανάλια
που δημιουργήθηκαν από τον βοηθό. Έπειτα εγκαθιστούμε τις συσκευές στους κόμβους
και τα κανάλια ανάμεσά τους.
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
Στη συνέχεια, δηλώνουμε άλλον ένα NodeContainer, προκειμένου να περιέχει τους κόμβους που θα
είναι μέρος του δικτύου αρτηρίας (CSMA).
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
Η επόμενη γραμμή κώδικα παίρνει (Gets) τον πρώτο κόμβο (δηλαδή σα να έχει ένα ευρετήριο
που να περιέχει έναν) από τον container των κόμβων σημείου-προς-σημείο και τον προσθέτει στον
container των κόμβων οι οποίοι θα δεχτούν μετέπειτα τις CSMA συσκευές. Ο εν λόγω κόμβος πρόκειται
να καταλήξει να έχει μια συσκευή σημείου-προς-σημείο και μια CSMA συσκευή. Έπειτα δημιουργούμε
έναν αριθμός από «επιπλέον» κόμβους, οι οποίοι συνθέτουν το υπόλοιπο του CSMA δικτύου.
Έπειτα δημιουργούμε έναν CsmaHelper και θέτουμε τα Attributes του όπως κάναμε
και στο προηγούμενο παράδειγμα. Δημιουργούμε ένα NetDeviceContainer για να καταγράψουμε
τις δικτυακές συσκευές CSMA που δημιουργήθηκαν και στη συνέχεια εγκαθιστούμε τις CSMA
συσκευές στους επιλεγμένους κόμβους.
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
Μετά πρόκειται να δημιουργήσουμε τους κόμβους που θα είναι μέρος του Wifi δικτύου. Θα
δημιουργησουμε έναν αριθμό από κόμβους-«σταθμούς», όπως προσδιορίζεται από το όρισμα στη
γραμμή εντολών, και θα χρησιμοποιήσουμε τον «αριστερότερο» κόμβο του συνδέσμου
σημείου-προς-σημείο ως τον κόμβο για το σημείο πρόσβασης.
NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);
Το επόμενο κομμάτι κώδικα κατασκευάζει τις συσκευές wifi και το διασυνδετικό κανάλι
ανάμεσα σε αυτούς τους wifi κόμβους. Αρχικά, ρυθμίζει τους βοηθούς φυσικού επιπέδου (PHY)
και καναλιού:
YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
Για λόγους απλότητας, αυτός ο κώδικας χρησιμοποιεί την προεπιλεγμένη ρύθμιση του φυσικού
επιπέδου και μοντέλα καναλιού που έχουν τεκμηριωθεί στην τεκμηρίωση API στο Doxygen για τις
μεθόδους YansWifiChannelHelper::Default και YansWifiPhyHelper::Default. Μόλις
δημιουργηθούν αυτά τα αντικείμενα, δημιουργούμε ένα αντικείμενο καναλιού και το
συσχετίζουμε με τον διαχειριστή αντικειμένων μας του φυσικού επιπέδου, ώστε να σιγουρευτούμε
ότι όλα τα αντικείμενα που δημιουργούνται στο φυσικό επίπεδο από τον YansWifiPhyHelper
μοιράζονται το ίδιο βασικό κανάλι, που σημαίνει ότι μοιράζονται το ίδιο ασύρματο μέσο
και μπορούν να επικοινωνήσουν και να παρέμβουν:
phy.SetChannel (channel.Create ());
Μόλις ρυθμιστεί και ο βοηθός φυσικού επιπέδου (PHY), μπορούμε να επικεντρωθούμε στο MAC επίπεδο.
Εδώ επιλέγουμε να δουλέψουμε με non-Qos MAC, οπότε χρησιμοποιούμε ένα αντικείμενο NqosWifiMacHelper
για να θέσουμε τις παραμέτρους που αφορούν το MAC.
WifiHelper wifi = WifiHelper::Default ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");
NqosWifiMacHelper mac = NqosWifiMacHelper::Default ();
Η μέθοδος SetRemoteStationManager λέει στον βοηθό τον τύπο του αλγορίθμου για τον
έλεγχο του ρυθμού που πρέπει να χρησιμοποιήσει. Εδώ, ζητάει από τον βοηθό να χρησιμοποιήσει τον
αλγόριθμο AARF — λεπτομέρειες σχετικά με αυτόν υπάρχουν, φυσικά, στο Doxygen.
Έπειτα, ρυθμίζουμε τον τύπο του MAC, το SSID του δικτύου υποδομής που θέλουμε να στήσουμε
και διασφαλίζουμε ότι οι σταθμοί μας δεν πραγματοποιούν ενεργητικές ανιχνεύσεις:
Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (false));
Αυτός ο κώδικας αρχικά δημιουργεί ένα αντικείμενο τύπου 802.11 SSID, το οποίο θα
χρησιμοποιηθεί για να τεθεί η τιμή του “Ssid” Attribute της υλοποίησης του MAC
επιπέδου. Το συγκεκριμένο είδος επιπέδου MAC που θα δημιουργηθεί από τον βοηθό καθορίζεται
μέσω Attribute ως τύπου “ns3::StaWifiMac”. Η χρήση του NqosWifiMacHelper θα διασφαλίσει
ότι το Attribute “QosSupported” για τα δημιουργηθέντα αντικείμενα MAC θα τεθεί ως ψευδές. Ο
συνδυασμός αυτών των δύο ρυθμίσεων σημαίνει ότι το επόμενο αντικείμενο MAC που θα δημιουργηθεί
θα είναι ένας σταθμός (STA) non-QoS non-AP σε μια BSS υποδομή (π.χ. μία BSS με ένα AP).
Τέλος, το Attribute “ActiveProbing” τίθεται ως ψευδές. Αυτό σημαίνει ότι δε θα στέλνονται
αιτήματα ανίχνευσης από τα MAC που δημιουργούνται από αυτόν τον βοηθό.
Μόλις ρυθμιστούν πλήρως όλες οι παράμετροι που αφορούν τους σταθμούς, τόσο στο MAC όσο και στο
φυσικό επίπεδο, μπορούμε να καλέσουμε τη γνωστή μας μέθοδο Install για να δημιουργήσουμε
τις συσκευές wifi σε αυτούς τους σταθμούς:
NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);
Έχουμε ρυθμίσει το Wifi για όλους τους STA κόμβους μας, και τώρα χρειάζεται να ρυθμίσουμε
τον AP κόμβο (σημείο πρόσβασης). Ξεκινάμε αυτή τη διαδικασία αλλάζοντας τα προεπιλεγμένα
Attributes του NqosWifiMacHelper ώστε να ανταποκρίνονται στις απαιτήσεις του AP.
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssid));
Σε αυτή την περίπτωση, ο NqosWifiMacHelper θα δημιουργήσει επίπεδα MAC του
“ns3::ApWifiMac”, με το τελευταίο να ορίζει ότι πρέπει να δημιουργηθεί ένα MAC επίπεδο
ρυθμισμένο ως AP, με τον τύπο βοηθού να υποδηλώνει ότι το Attribute “QosSupported” πρέπει
να τεθεί ως ψευδές - απενεργοποιώντας την υποστήριξη τύπου 802.11e/WMM-style QoS στα AP που
θα δημιουργηθούν.
Οι επόμενες γραμμές δημιουργούν ένα μοναδικό AP το οποίο μοιράζεται το ίδιο σύνολο από
Attributes φυσικού επιπέδου (και καναλιού) με τους σταθμούς:
NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);
Σε αυτό το σημείο θα προσθέσουμε τα μοντέλα κινητικότητάς μας. Θέλουμε οι STA σταθμοί να είναι
κινητοί, περιπλανώμενοι μέσα στα πλαίσια ενός περιοριστικού κουτιού, και θέλουμε να κάνουμε τον
AP κόμβο σταθερό. Χρησιμοποιούμε τον MobilityHelper για να διευκολυνθούμε. Αρχικά,
δημιουργούμε ένα αντικείμενο MobilityHelper και θέτουμε κάποια Attributes που ελέγχουν
τη λειτουργία του «κατανεμητή θέσεων» (position allocator).
MobilityHelper mobility;
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));
Αυτός ο κώδικας λέει στον βοηθό κινητικότητας να χρησιμοποιήσει ένα δισδιάστατο πλέγμα για
να τοποθετήσει αρχικά τους STA κόμβους. Εξερευνήστε ελεύθερα το Doxygen ψάχνοντας για την κλάση
ns3::GridPositionAllocator για να δείτε ακριβώς τι γίνεται.
Έχουμε τοποθετήσει τους κόμβους μας στο αρχικό πλέγμα, αλλά τώρα πρέπει να τους πούμε πώς να
κινηθούν. Επιλέγουμε το RandomWalk2dMobilityModel, το οποίο βάζει τους κόμβους να κινούνται προς
μια τυχαία κατεύθυνση, με τυχαία ταχύτητα, μέσα σε ένα οριοθετημένο κουτί.
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));
Τώρα λέμε στο MobilityHelper να εγκαταστήσει τα μοντέλα κινητικότητας στους STA κόμβους.
mobility.Install (wifiStaNodes);
Θέλουμε το σημείο πρόσβασης να παραμείνει σε μια καθορισμένη θέση κατά τη διάρκεια της
προσομοίωσης. Αυτό το επιτυγχάνουμε θέτοντας ως μοντέλο κινητικότητας για αυτόν τον κόμβο
το ns3::ConstantPositionMobilityModel:
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (wifiApNode);
Τώρα πλέον έχουμε δημιουργήσει τους κόμβους μας, τις συσκευές και τα κανάλια μας, έχουμε
επιλέξει τα μοντέλα κινητικότητας για τους Wifi κόμβους, αλλά δεν έχουμε καμία στοίβα πρωτοκόλλου.
Ακριβώς όπως κάναμε και πολλές φορές πριν, θα χρησιμοποιήσουμε τον InternetStackHelper για να
εγκαταστήσουμε αυτές τις στοίβες.
InternetStackHelper stack;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);
Όπως και στο παράδειγμα του second.cc, θα χρησιμοποιήσουμε τον Ipv4AddressHelper
για να αναθέσουμε IP διευθύνσεις στις διεπαφές των συσκευών μας. Αρχικά θα χρησιμοποιήσουμε
το δίκτυο 10.1.1.0 για να δημιουργήσουμε τις δύο διευθύνσεις που χρειαζονται οι δύο συσκευές μας
σημείου-προς-σημείο. Έπειτα χρησιμοποιούμε το δίκτυο 10.1.2.0 για να αναθέσουμε διευθύνσεις στο
CSMA δίκτυο, και έπειτα αναθέτουμε διευθύνσεις από το δίκτυο 10.1.3.0 τόσο στις STA συσκευές όσο και
στην AP συσκευή στο ασύρματο δίκτυο.
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
address.SetBase ("10.1.3.0", "255.255.255.0");
address.Assign (staDevices);
address.Assign (apDevices);
Τοποθετούμε τον εξυπηρετητή echo στον «δεξιότερο» κόμβο της απεικόνισης στην αρχή του αρχείου.
Το έχουμε κάνει και πιο πριν αυτό.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
Τοποθετούμε και τον πελάτη echo στον τελευταίο STA κόμβο που δημιουργήσαμε, κατευθύνοντάς τον
προς τον εξυπηρετητή του CSMA δικτύου. Έχουμε επίσης δει παρόμοιες λειτουργίες και παλιότερα.
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 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));
Αφότου έχουμε χτίσει ένα διαδίκτυο εδώ, χρειάζεται να ενεργοποιήσουμε τη δρομολόγηση διαδικτύου
όπως κάναμε και στο σενάριο του παραδείγματος στο second.cc.
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
Ένα πράγμα που μπορεί να εκπλήσσει κάποιους χρήστες είναι το γεγονός ότι η προσομοίωση που
μόλις δημιουργήσαμε δε θα σταματήσει ποτέ «εκ των πραγμάτων». Αυτό οφείλεται στο ότι
ζητήσαμε από το ασύρματο σημείο πρόσβασης να παράγει beacons. Θα παράγει beacons για πάντα,
και αυτό θα έχει ως αποτέλεσμα να προγραμματίζονται ασταμάτητα γεγονότα προσομοίωσης για το μέλλον,
οπότε πρέπει να πούμε στον προσομοιωτή να σταματήσει, παρόλο που μπορεί να έχουν προγραμματιστεί
γεγονότα δημιουργίας beacon. Η ακόλουθη γραμμή κώδικα λέει στον προσομοιωτή να σταματήσει έτσι ώστε
να μην προσομοιώνουμε beacons για πάντα, μπαίνοντας με αυτόν τον τρόπο σε έναν κατ’ ουσίαν
ατέρμονα βρόχο.
Simulator::Stop (Seconds (10.0));
Δημιουργούμε τόσα ίχνη καταγραφής έτσι ώστε να καλύψουμε και τα τρία δίκτυα:
pointToPoint.EnablePcapAll ("third");
phy.EnablePcap ("third", apDevices.Get (0));
csma.EnablePcap ("third", csmaDevices.Get (0), true);
Αυτές οι τρεις γραμμές κώδικα θα ξεκινήσουν την καταγραφή pcap και στους δύο κόμβους
σημείου-προς-σημείο που λειτουργούν ως η ραχοκοκαλιά μας, θα αρχίσουν μια καταγραφή
μεικτής κατάστασης στο Wifi δίκτυο, και μια μεικτή καταγραφή στο CSMA δίκτυο. Αυτό θα
μας επιτρέψει να δούμε όλη την κίνηση με τη βοήθεια του ελάχιστου αριθμού αρχείων ιχνών.
Τέλος, τρέχουμε όντως την προσομοίωση, καθαρίζουμε και έπειτα βγαίνουμε από το πρόγραμμα.
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
Για να τρέξετε αυτό το παράδειγμα, θα πρέπει να αντιγράψετε το σενάριο third.cc στον
κατάλογο scratch και να χρησιμοποιήσετε το Waf για να κάνετε build, όπως κάνατε και στο
παράδειγμα second.cc. Εάν είστε στον κατάλογο του υψηλότερου επιπέδου του αποθετηρίου,
θα πληκτρολογήσετε,
$ cp examples/tutorial/third.cc scratch/mythird.cc
$ ./waf
$ ./waf --run scratch/mythird
Ξανά, από τη στιγμή που έχετε θέσει τις εφαρμογές UDP echo όπως κάναμε στο σενάριο
second.cc, θα δείτε μία παρόμοια έξοδο.
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.407s)
At time 2s client sent 1024 bytes to 10.1.2.4 port 9
At time 2.01796s server received 1024 bytes from 10.1.3.3 port 49153
At time 2.01796s server sent 1024 bytes to 10.1.3.3 port 49153
At time 2.03364s client received 1024 bytes from 10.1.2.4 port 9
Θυμηθείτε ότι το πρώτο μήνυμα, “Sent 1024 bytes to 10.1.2.4”, είναι ο πελάτης
UDP echo που στέλνει ένα πακέτο στον εξυπηρετητή. Σε αυτή την περίπτωση, ο πελάτης είναι
στο ασύρματο δίκτυο (10.1.3.0). Το δεύτερο μήνυμα, “Received 1024 bytes from 10.1.3.3”,
είναι από τον UDP echo εξυπηρετητή, και δημιουργήθηκε όταν αυτός έλαβε το echo πακέτο. Το τελικό
μήνυμα, “Received 1024 bytes from 10.1.2.4”, είναι από τον πελάτη echo, και δείχνει ότι
αυτός έχει λάβει το echo πακέτο του πίσω από τον εξυπηρετητή.
Εάν τώρα πάτε και δείτε στον κατάλογο του υψηλότερου επιπέδου, θα βρείτε τέσσερα αρχεία
ιχνών από την προσομοίωση, δύο από τον κόμβο μηδέν και δύο από τον κόμβο ένα:
third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap
Το αρχείο “third-0-0.pcap” αντιστοιχεί στη συσκευή σημείου-προς-σημείο στον κόμβο μηδέν –
στην αριστερή πλευρά της «ραχοκοκαλιάς». Το αρχείο “third-1-0.pcap” αντιστοιχεί στη συσκευή
σημείου-προς-σημείο στον κόμβο ένα – στην δεξιά πλευρά της “ραχοκοκαλιάς”. Το αρχείο
“third-0-1.pcap” θα είναι το μεικτό (κατάσταση παρακολούθησης) ίχνος από το Wifi δίκτυο και το
αρχείο “third-1-1.pcap” θα είναι το μεικτό ίχνος από το CSMA δίκτυο. Μπορείτε να το επιβεβαιώσετε
αυτό εξετάζοντας τον κώδικα;
Από τη στιγμή που ο echo πελάτης είναι στο Wifi δίκτυο, ας αρχίσουμε από εκεί. Ας δούμε
στο μεικτό (σε κατάσταση παρακολούθησης) ίχνος που καταγράψαμε σε αυτό το δίκτυο.
$ tcpdump -nn -tt -r third-0-1.pcap
Θα πρέπει να δείτε κάποια περιεχόμενα σχετικά με το Wifi που δεν έχετε ξαναδεί προηγουμένως:
reading from file third-0-1.pcap, link-type IEEE802_11 (802.11)
0.000025 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000324 Acknowledgment RA:00:00:00:00:00:08
0.000402 Assoc Response AID(0) :: Successful
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000737 Acknowledgment RA:00:00:00:00:00:07
0.000824 Assoc Response AID(0) :: Successful
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001150 Acknowledgment RA:00:00:00:00:00:09
0.001273 Assoc Response AID(0) :: Successful
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
Μπορείτε να δείτε ότι ο τύπος σύνδεσης είναι τώρα ο 802.11, όπως θα περιμένατε. Μπορείτε
πιθανώς να καταλάβετε τι γίνεται και να βρείτε τα πακέτα του IP echo αιτήματος και της απάντησης
σε αυτό το ίχνος. Την πλήρη ανάλυση των ιχνών αυτών σας την αφήνουμε ως άσκηση.
Τώρα, δείτε στο αρχείο pcap της αριστερής πλευράς του συνδέσμου σημείου-προς-σημείο,
$ tcpdump -nn -tt -r third-0-0.pcap
Ξανά, θα δείτε μερικά γνώριμα περιεχόμενα:
reading from file third-0-0.pcap, link-type PPP (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024
Αυτό είναι το echo πακέτο που πηγαίνει από αριστερά προς τα δεξιά (από το Wifi στο CSMA) και
ξανά πίσω διαμέσου του συνδέσμου σημείου-προς-σημείο.
Τώρα, δείτε στο αρχείο pcap της δεξιάς πλευράς του συνδέσμου σημείου-προς-σημείο,
$ tcpdump -nn -tt -r third-1-0.pcap
Ξανά, θα δείτε μερικά γνώριμα περιεχόμενα:
reading from file third-1-0.pcap, link-type PPP (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024
Αυτό είναι επίσης το echo πακέτο που πηγαίνει από τα αριστερά προς τα δεξιά (από το Wifi στο
CSMA) και πάλι πίσω διαμέσου του συνδέσμου σημείου-προς-σημείο, με λίγο διαφορετικούς χρονισμούς
όπως πιθανόν να αναμένατε.
Ο echo εξυπηρετητής βρίσκεται στο CSMA δίκτυο, οπότε ας ρίξουμε μια ματιά στο μεικτό ίχνος εκεί:
$ tcpdump -nn -tt -r third-1-1.pcap
Θα πρέπει να βλέπετε μερικά γνώριμα περιεχόμενα:
reading from file third-1-1.pcap, link-type EN10MB (Ethernet)
2.017837 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.017861 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.022966 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.022966 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024
Αυτό θα πρέπει να είναι εύκολα κατανοητό. Εάν έχετε ξεχάσει τι και πώς, επιστρέψτε πίσω και κοιτάξτε
στα όσα είπαμε στο παράδειγμα second.cc. Είναι η ίδια ακολουθία.
Τώρα, αφιερώσαμε αρκετό χρόνο καθορίζοντας τα μοντέλα κινητικότητας για το ασύρματο δίκτυο
και έτσι θα ήταν κρίμα να κλείσουμε χωρίς καν να δείξουμε ότι όντως οι STA κόμβοι κινούνται
κατά τη διάρκεια της προσομοίωσης. Ας το κάνουμε αυτό εξετάζοντας τον πηγαίο κώδικα της καταγραφής
των αλλαγών πορείας του MobilityModel. Πρόκειται απλά για μια γρήγορη ματιά στην λεπτομερή
ενότητα σχετικά με την ιχνηλασία που ακολουθεί μετέπειτα, μα το σημείο αυτό φαίνεται ιδανικό
για να δούμε ένα σχετικό παράδειγμα.
Όπως αναφέρθηκε στην ενότητα «Μικρορυθμίσεις», το σύστημα ιχνηλασίας του ns-3
χωρίζεται σε πηγές ιχνηλασίας (trace source) και καταβόθρες ιχνηλασίας (trace sinks), και
εμείς παρέχουμε μεθόδους για τη σύνδεση αυτών των δύο. Θα χρησιμοποιήσουμε την προκαθορισμένη
πηγή ιχνηλασίας των αλλαγών πορείας για το μοντέλο κινητικότητας ώστε να πυροδοτήσουμε τα
γεγονότα ιχνηλασίας. Θα χρειαστεί να συντάξουμε μια καταβόθρα ιχνηλασίας ώστε να τη συνδέσουμε
με την πηγή, η οποία θα μας εμφανίζει μερικές ωραίες πληροφορίες. Παρά τη φήμη περί δυσκολίας αυτού
του πράγματος, στην πραγματικότητα είναι εξαιρετικά απλό. Απλά πριν το κυρίως πρόγραμμα του
σεναρίου scratch/mythird.cc (π.χ. αμέσως μετά τη δήλωση NS_LOG_COMPONENT_DEFINE),
προσθέστε την ακόλουθη συνάρτηση:
void
CourseChange (std::string context, Ptr<const MobilityModel> model)
{
Vector position = model->GetPosition ();
NS_LOG_UNCOND (context <<
" x = " << position.x << ", y = " << position.y);
}
Αυτός ο κώδικας τραβάει τις πληροφορίες τοποθεσίας από το μοντέλο κινητικότητας και
καταγράφει άνευ όρων τις συντεταγμένες x και y του κόμβου. Θα τα ρυθμίσουμε έτσι ώστε αυτή η μέθοδος
να καλείται κάθε φορά που ο ασύρματος κόμβος με τον echo πελάτη αλλάζει θέση. Αυτό το πετυχαίνουμε
με τη χρήση της συνάρτησης Config::Connect. Προσθέστε τις ακόλουθες γραμμές κώδικα στο
σενάριο, ακριβώς πριν από την κλήση Simulator::Run.
std::ostringstream oss;
oss <<
"/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
"/$ns3::MobilityModel/CourseChange";
Config::Connect (oss.str (), MakeCallback (&CourseChange));
Αυτό που κάνουμε εδώ είναι ότι δημιουργούμε μια ακολουθία που περιέχει το μονοπάτι του χώρου
ονομάτων που αφορά στην ιχνηλασία του γεγονότος στο οποίο θέλουμε να συνδεθούμε. Αρχικά, πρέπει
να καταλάβουμε ποιος είναι ο κόμβος που θέλουμε, χρησιμοποιώντας τη μέθοδο GetId όπως
περιγράφθηκε νωρίτερα. Στην περίπτωση του εξ ορισμού αριθμού CSMA και ασύρματων κόμβων, προκύπτει
ότι ο ζητούμενος κόμβος είναι ο κόμβος επτά και το μονοπάτι του χώρου ονομάτων που αφορά
στην ιχνηλασία για το μοντέλο κινητικότητας θα μοιάζει κάπως έτσι:
/NodeList/7/$ns3::MobilityModel/CourseChange
Με βάση τα όσα είπαμε στην ενότητα περί ιχνηλασίας, μπορείτε να παρέμβετε έτσι ώστε το
μονοπάτι ιχνηλασίας να αναφέρεται στον έβδομο κόμβο της καθολικής NodeList. Αυτό ορίζει
κάτι το οποίο αποκαλείται ενσωματωμένο (aggregated) αντικείμενο τύπου ns3::MobilityModel. Το πρόθεμα
του δολαρίου υποδηλώνει ότι το MobilityModel είναι ενσωματωμένο στον κόμβο επτά. Το τελευταιό
μέρος του μονοπατιού σημαίνει ότι βρισκόμαστε στο γεγονός “CourseChange” αυτού του μοντέλου.
Κάνουμε τη σύνδεση μεταξύ της πηγής ιχνηλασίας στον κόμβο επτά με την καταβόθρα ιχνηλασίας μας,
καλώντας την Config::Connect και περνώντας ως όρισμα το μονοπάτι του χώρου ονομάτων. Μόλις
γίνει αυτό, κάθε γεγονός αλλαγής πορείας στον κόμβο επτά θα καταλήγει στην καταβόθρα ιχνηλασίας
μας, η οποία με τη σειρά της θα εκτυπώνει τη νέα θέση.
Εάν τώρα τρέξετε την προσομοίωση, θα δείτε ότι οι αλλαγές πορείας εμφανίζονται καθώς συμβαίνουν.
'build' finished successfully (5.989s)
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.3841, y = 0.923277
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2049, y = 1.90708
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8136, y = 1.11368
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8452, y = 2.11318
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.9797, y = 3.10409
At time 2s client sent 1024 bytes to 10.1.2.4 port 9
At time 2.01796s server received 1024 bytes from 10.1.3.3 port 49153
At time 2.01796s server sent 1024 bytes to 10.1.3.3 port 49153
At time 2.03364s client received 1024 bytes from 10.1.2.4 port 9
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.3273, y = 4.04175
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.013, y = 4.76955
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.4317, y = 5.67771
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.4607, y = 5.91681
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.0155, y = 6.74878
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.0076, y = 6.62336
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.6285, y = 5.698
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.32, y = 4.97559
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.1134, y = 3.99715
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.8359, y = 4.68851
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.5953, y = 3.71789
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.7595, y = 4.26688
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.7629, y = 4.34913
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.2292, y = 5.19485
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2344, y = 5.09394
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.3601, y = 4.60846
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.40025, y = 4.32795
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.14292, y = 4.99761
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.08299, y = 5.99581
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.26068, y = 5.42677
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.35917, y = 6.42191
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.66805, y = 7.14466
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.71414, y = 6.84456
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42489, y = 7.80181
Συλλογή Δεδομένων
Το τελευταίο κεφάλαιο του οδηγού μας παρουσιάζει κάποια συστατικά μέρη που προστέθηκαν
στον ns-3 κατά την έκδοση 3.18, και τα οποία είναι ακόμα υπό ανάπτυξη. Όπως επίσης
είναι υπό ανάπτυξη και αυτό το μέρος του οδηγού.
Κίνηση
Ένας από τους κύριους στόχους της εκτέλεσης προσομοιώσεων είναι η δημιουργία δεδομένων
εξόδου, είτε για ερευνητικούς σκοπούς είτε απλά για την εκμάθηση του συστήματος.
Στο προηγούμενο κεφάλαιο, εισαγάγαμε το υποσύστημα ιχνηλασίας (tracing) και το παράδειγμα
sixth.cc από το οποίο παράγονται PCAP ή ASCII αρχεία ιχνών. Αυτά τα ίχνη
είναι πολύτιμα για την ανάλυση δεδομένων με χρήση ποικιλίας εξωτερικών εργαλείων, και
για πολλούς χρήστες, καθώς τα δεδομένα εξόδου είναι ένα μέσο που προτιμάται για
τη συλλογή δεδομένων (για ανάλυση από εξωτερικά εργαλεία).
Ωστόσο, υπάρχουν επίσης περιπτώσεις χρήσης που έχουν να κάνουν με περισσότερα
από την απλή δημιουργία αρχείων ιχνηλασίας, συμπεριλαμβανομένων και των ακόλουθων:
- δημιουργία δεδομένων, που δεν καταγράφονται καλά σε ίχνη PCAP ή ASCII, όπως
είναι τα δεδομένα εκτός των πακέτων (π.χ. μεταβάσεις καταστάσεων μηχανής σύμφωνα
με πρωτόκολλα)
- μεγάλες προσομοιώσεις, για τις οποίες οι απαιτήσεις εισόδου-εξόδου σε χωρητικότητα
για τη δημιουργία αρχείων ιχνηλασίας είναι απαγορευτικές ή επιβαρυντικές, και
- η ανάγκη για αναγωγή δεδομένων ή υπολογισμό σε πραγματικό χρόνο (online), κατά τη διάρκεια της
εκτέλεσης της προσομοίωσης. Ένα καλό παράδειγμα σχετικά με αυτό είναι ο ορισμός
μιας τερματικής συνθήκης για την προσομοίωση, ώστε να καθορίσετε το πότε να σταματήσει,
όταν έχει λάβει αρκετά δεδομένα ώστε να σχηματίσει ένα αρκετά περιορισμένο διάστημα
εμπιστοσύνης γύρω από την εκτίμηση κάποιας παραμέτρου.
Το πλαίσιο συλλογής δεδομένων του ns-3 έχει σχεδιαστεί ώστε να παρέχει αυτές τις
επιπρόσθετες δυνατότητες πέρα από αποτελέσματα που βασίζονται σε ίχνη. Συνιστούμε
στους αναγνώστες που ενδιαφέρονται για αυτό το θέμα να συμβουλευτούν το εγχειρίδιο
του ns-3 για μια πιο λεπτομερή εξέταση του πλαισίου αυτού. Για τώρα, συνοψίζουμε
μέσω ενός παραδείγματος κάποιες από τις δυνατότητες ανάπτυξης.
Παράδειγμα
Το παράδειγμα του οδηγού examples/tutorial/seventh.cc μοιάζει με το
παράδειγμα sixth.cc που εξετάσαμε προηγουμένως, πέρα από κάποιες αλλαγές.
Αρχικά, έχει ενεργοποιηθεί η υποστήριξη για IPv6 με μια επιλογή μέσω τερματικού:
CommandLine cmd;
cmd.AddValue ("useIpv6", "Use Ipv6", useV6);
cmd.Parse (argc, argv);
Αν ο χρήστης κάνει την επιλογή useIpv6, το πρόγραμμα θα εκτελεστεί χρησιμοποιώντας
το IPv6 αντί του IPv4. Η επιλογή help, διαθέσιμη σε όλα τα προγράμματα του ns-3
που υποστηρίζουν το αντικείμενο CommandLine όπως φαίνεται παραπάνω, μπορεί να
καλεστεί ως ακολούθως (παρακαλούμε προσέξτε τη χρήση των διπλών εισαγωγικών):
./waf --run "seventh --help"
η οποία παράγει:
ns3-dev-seventh-debug [Program Arguments] [General Arguments]
Program Arguments:
--useIpv6: Use Ipv6 [false]
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.
Αυτή η προεπιλογή (η χρήση του IPv4, καθώς η useIpv6 έχει τεθεί ως false)
μπορεί να αλλάξει μέσω εναλλαγής της δυαδικής τιμής της ως ακολούθως:
./waf --run "seventh --useIpv6=1"
και δείτε το PCAP αρχείο που έχει δημιουργηθεί, για παράδειγμα με την
εντολή tcpdump:
tcpdump -r seventh.pcap -nn -tt
Αυτή ήταν μια σύντομη παρέκβαση σχετικά με την υποστήριξη του IPv6 και την
γραμμή εντολών, η οποία επίσης παρουσιάστηκε νωρίτερα σε αυτόν τον οδηγό. Για
ένα παράδειγμα με εξ ολοκλήρου χρήση της γραμμής εντολών, σας παρακαλούμε να δείτε
το src/core/examples/command-line-example.cc.
Τώρα πίσω στη συλλογή δεδομένων. Στον κατάλογο examples/tutorial/,
πληκτρολογήστε την ακόλουθη εντολή: diff -u sixth.cc seventh.cc, και εξετάστε
κάποιες από τις νέες γραμμές αυτής της diff:
+ std::string probeType;
+ std::string tracePath;
+ if (useV6 == false)
+ {
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+ }
+ else
+ {
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+ }
...
+ // Use GnuplotHelper to plot the packet byte count over time
+ GnuplotHelper plotHelper;
+
+ // Configure the plot. The first argument is the file name prefix
+ // for the output files generated. The second, third, and fourth
+ // arguments are, respectively, the plot title, x-axis, and y-axis labels
+ plotHelper.ConfigurePlot ("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time (Seconds)",
+ "Packet Byte Count");
+
+ // Specify the probe type, trace source path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to plot. The fourth argument
+ // specifies the name of the data series label on the plot. The last
+ // argument formats the plot by specifying where the key should be placed.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
+
+ // Use FileHelper to write out the packet byte count over time
+ FileHelper fileHelper;
+
+ // Configure the file to be written, and the formatting of output data.
+ fileHelper.ConfigureFile ("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
+
+ // Set the labels for this formatted output file.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
+
+ // Specify the probe type, probe path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to write.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+
Simulator::Stop (Seconds (20));
Simulator::Run ();
Simulator::Destroy ();
Ο προσεκτικός αναγνώστης θα ‘χει ήδη παρατηρήσει ότι, όταν δοκιμάζαμε την
ιδιότητα σχετικά με το IPv6 στη γραμμή εντολών παραπάνω, εκείνο το αρχείο
seventh.cc είχε δημιουργήσει αρκετά νέα αρχεία εξόδου:
seventh-packet-byte-count-0.txt
seventh-packet-byte-count-1.txt
seventh-packet-byte-count.dat
seventh-packet-byte-count.plt
seventh-packet-byte-count.png
seventh-packet-byte-count.sh
Αυτά δημιουργήθηκαν από τις πρόσθετες δηλώσεις που εισήχθησαν παραπάνω. Πιο συγκεκριμένα,
από έναν GnuplotHelper και έναν FileHelper. Αυτά τα δεδομένα παρήχθησαν συνδέοντας
τα μέρη για τη συλλογή δεδομένων σε πηγές ιχνών του ns-3, και μέσω εισαγωγής των
δεδομένων σε ένα ήδη διαμορφωμένο gnuplot και σε ένα διαμορφωμένο αρχείο κειμένου.
Στα επόμενα τμήματα, θα εξετάσουμε κάθε ένα από αυτά.
GnuplotHelper
O GnuplotHelper είναι ένα αντικείμενο-βοηθός του ns-3 που στοχεύει στην
παραγωγή γραφικών παραστάσεων gnuplot με όσο το δυνατόν λιγότερες δηλώσεις γίνεται,
για συνηθισμένες περιπτώσεις. Συνδέει πηγές ιχνών του ns-3 με τύπους δεδομένων που
υποστηρίζονται από το σύστημα συλλογής δεδομένων. Δεν υποστηρίζονται όλοι οι τύποι
δεδομένων που αφορούν τις πηγές ιχνών του ns-3, αλλά υποστηρίζονται πολλοί από τους συνηθισμένους
τύπους ιχνηλασίας, συμπεριλαμβανομένων των TracedValues μαζί με
τύπους απλών παλιών δεδομένων (plain old data ή POD).
Ας δούμε την έξοδο που προκύπτει από αυτόν τον βοηθό:
seventh-packet-byte-count.dat
seventh-packet-byte-count.plt
seventh-packet-byte-count.sh
Το πρώτο είναι ένα αρχείο δεδομένων gnuplot με μια σειρά από χρονοσημάνσεις
διαχωρισμένες με κενά και καταμετρήσεις των byte των πακέτων. Θα καλύψουμε παρακάτω
το πως καθορίστηκε η συγκεκριμένη έξοδος δεδομένων, αλλά τώρα ας συνεχίσουμε με τα
αρχεία εξόδου. Το αρχείο seventh-packet-byte-count.plt είναι ένα αρχείο γραφικής
παράστασης gnuplot, που μπορεί να ανοιχτεί μέσω του gnuplot. Οι αναγνώστες που κατανοούν
τη σύνταξη του gnuplot μπορούν να δουν ότι αυτό θα παράξει ένα διαμορφωμένο PNG αρχείο ως
έξοδο με το όνομα seventh-packet-byte-count.png. Τέλος, ένα μικρό σενάριο κελύφους
seventh-packet-byte-count.sh εκτελεί αυτό το αρχείο γραφικής παράστασης μέσω του gnuplot
για να παράξει το επιθυμητό PNG (το οποίο μπορείτε να δείτε μέσω κάποιου επεξεργαστή εικόνων).
Πρόκειται για την εντολή:
sh seventh-packet-byte-count.sh
που θα παράξει το seventh-packet-byte-count.png. Γιατί δεν παρήχθη
εξαρχής αυτό το αρχείο PNG; Η απάντηση σε αυτό είναι ότι παρέχοντας το αρχείο
plot, ο χρήστης μπορεί να ρυθμίσει χειροκίνητα το αποτέλεσμα εάν το επιθυμεί,
πριν να παραχθεί το PNG.
Ο τίτλος της PNG εικόνας δηλώνει ότι η γραφική παράσταση είναι μια παράσταση
“Καταμέτρησης Byte Πακέτων προς Χρόνο”, και ότι σχεδιάζει τα δεδομένα που έχουν
ανιχνευθεί σε αντιστοιχία με το μονοπάτι της πηγής ιχνηλασίας:
/NodeList/*/$ns3::Ipv6L3Protocol/Tx
Σημειώστε τον χαρακτήρα-μπαλαντέρ στο μονοπάτι των ιχνών. Συνολικά, αυτό
που αποτυπώνει αυτή η γραφική παράσταση είναι η αναπαράσταση των byte των πακέτων
που παρατηρούνται στην πηγή ιχνών μετάδοσης του αντικειμένου Ipv6L3Protocol: σε
μεγάλο βαθμό TCP πακέτα των 596 byte στη μια κατεύθυνση, και TCP επιβεβαιώσεις των 60 byte
στην άλλη (σε αυτή την πηγή ιχνών αντιστοιχήθηκαν πηγές ιχνών από δύο κόμβους).
Πώς καθορίστηκε αυτό; Χρειάζονται μερικές δηλώσεις. Αρχικά, το αντικείμενο
GnuplotHelper πρέπει να δηλωθεί και να ρυθμιστεί:
+ // Use GnuplotHelper to plot the packet byte count over time
+ GnuplotHelper plotHelper;
+
+ // Configure the plot. The first argument is the file name prefix
+ // for the output files generated. The second, third, and fourth
+ // arguments are, respectively, the plot title, x-axis, and y-axis labels
+ plotHelper.ConfigurePlot ("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time (Seconds)",
+ "Packet Byte Count");
Μέχρι αυτό το σημείο, έχει ρυθμιστεί μια άδεια γραφική παράσταση. Το πρόθεμα του
ονόματος του αρχείου είναι το πρώτο όρισμα, ο τίτλος της γραφικής είναι το δεύτερο,
η ετικέτα του άξονα των Χ είναι το τρίτο, και η ετικέτα του άξονα των Υ το τέταρτο
όρισμα.
Το επόμενο βήμα είναι να καθορίσουμε τα δεδομένα, και εδώ είναι που συνδέεται
η πηγή ιχνών. Αρχικά, σημειώστε παραπάνω ότι στο πρόγραμμα δηλώσαμε μερικές
μεταβλητές για μετέπειτα χρήση:
+ std::string probeType;
+ std::string tracePath;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
Τις χρησιμοποιούμε εδώ:
+ // Specify the probe type, trace source path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to plot. The fourth argument
+ // specifies the name of the data series label on the plot. The last
+ // argument formats the plot by specifying where the key should be placed.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
Τα πρώτα δύο ορίσματα είναι το όνομα του τύπου probe και το μονοπάτι της πηγής ιχνών.
Αυτά τα δύο είναι μάλλον τα δυσκολότερα να οριστούν, όταν προσπαθείτε να χρησιμοποιήσετε
αυτό το πλαίσιο εργασίας για να σχεδιάσετε άλλα ίχνη. Το probe ίχνος εδώ είναι η Tx
πηγή ιχνών της κλάσης Ipv6L3Protocol. Αν εξετάσουμε την υλοποίηση αυτής της κλάσης
(src/internet/model/ipv6-l3-protocol.cc), θα παρατηρήσουμε το:
.AddTraceSource ("Tx", "Send IPv6 packet to outgoing interface.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))
Αυτό μας λέει ότι το Tx είναι ένα όνομα για τη μεταβλητή m_txTrace,
η οποία έχει μια δήλωση ως εξής:
/**
* \brief Callback to trace TX (transmission) packets.
*/
TracedCallback<Ptr<const Packet>, Ptr<Ipv6>, uint32_t> m_txTrace;
Προκύπτει ότι αυτή η συγκεκριμένη υπογραφή πηγής ιχνών υποστηρίζεται από μια
κλάση Probe (αυτό που χρειαζόμαστε εδώ) της κλάσης Ipv6PacketProbe. Δείτε τα
αρχεία src/internet/model/ipv6-packet-probe.{h,cc}.
Έτσι, στην παραπάνω δήλωση PlotProbe, βλέπουμε ότι η δήλωση συνδέει την πηγή
ιχνών (που ταυτοποιείται από την συμβολοσειρά του μονοπατιού) με έναν αντίστοιχο
τύπο ns-3 Probe του Ipv6PacketProbe. Εάν δεν υποστηρίζαμε αυτόν τον τύπο probe
(ώστε να αντιστοιχίζεται με την υπογραφή της πηγής ιχνών), δε θα μπορούσαμε
να χρησιμοποιήσουμε αυτή τη δήλωση (παρόλο που θα μπορούσαν να χρησιμοποιηθούν μερικές
πιο πολύπλοκες και χαμηλότερου επιπέδου δηλώσεις, όπως περιγράφεται στο εγχειρίδιο).
Η Ipv6PacketProbe εξάγει, η ίδια, μερικές πηγές ιχνών που συλλέγουν τα δεδομένα
από το ανιχνευθέν αντικείμενο Packet:
TypeId
Ipv6PacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent<Probe> ()
.AddConstructor<Ipv6PacketProbe> ()
.AddTraceSource ( "Output",
"The packet plus its IPv6 object and interface that serve as the output for this probe",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
;
return tid;
}
Το τρίτο όρισμα της PlotProbe δήλωσής μας προσδιορίζει ότι ενδιαφερόμαστε
για έναν αριθμό από byte σε αυτό το πακέτο: ειδικότερα, στην πηγή ιχνών
“OutputBytes” της Ipv6PacketProbe.
Τέλος, τα δύο τελευταία ορίσματα της δήλωσης παρέχουν το υπόμνημα της γραφικής παράστασης
για αυτή τη σειρά δεδομένων (“Packet Byte Count”), και μία προαιρετική δήλωση
μορφοποίησης του gnuplot (GnuplotAggregator::KEY_BELOW) ότι θέλουμε το υπόμνημα
της γραφικής παράστασης να εισαχθεί κάτω από την παράσταση. Άλλες επιλογές
περιλαμβάνουν τα NO_KEY, KEY_INSIDE, και KEY_ABOVE.
Υποστηριζόμενοι Τύποι Ιχνών
Οι ακόλουθες καταγεγραμμένες τιμές υποστηρίζονται από Probes έως και τη στιγμή που γράφεται
το παρόν κείμενο:
Τύπος TracedValue |
Τύπος Probe |
Αρχείο |
double |
DoubleProbe |
stats/model/double-probe.h |
uint8_t |
Uinteger8Probe |
stats/model/uinteger-8-probe.h |
uint16_t |
Uinteger16Probe |
stats/model/uinteger-16-probe.h |
uint32_t |
Uinteger32Probe |
stats/model/uinteger-32-probe.h |
bool |
BooleanProbe |
stats/model/uinteger-16-probe.h |
ns3::Time |
TimeProbe |
stats/model/time-probe.h |
Οι ακόλουθοι τύποι TraceSource υποστηρίζονται από τα Probes έως και τη στιγμή που γράφεται
το παρόν κείμενο:
Tύπος TracedSource |
Τύπος Probe |
Έξοδος Probe |
Αρχείο |
Ptr<const Packet> |
PacketProbe |
OutputBytes |
network/utils/packet-probe.h |
Ptr<const Packet>, Ptr<Ipv4>, uint32_t |
Ipv4PacketProbe |
OutputBytes |
internet/model/ipv4-packet-probe.h |
Ptr<const Packet>, Ptr<Ipv6>, uint32_t |
Ipv6PacketProbe |
OutputBytes |
internet/model/ipv6-packet-probe.h |
Ptr<const Packet>, Ptr<Ipv6>, uint32_t |
Ipv6PacketProbe |
OutputBytes |
internet/model/ipv6-packet-probe.h |
Ptr<const Packet>, const Address& |
ApplicationPacketProbe |
OutputBytes |
applications/model/application-packet-probe.h |
Όπως είναι φανερό, μόνο μερικές πηγές ιχνών υποστηρίζονται, και όλες προσανατολίζονται
στην εξαγωγή του μεγέθους του Packet (σε byte). Ωστόσο, οι περισσότεροι
από τους βασικούς τύπους δεδομένων που είναι διαθέσιμοι ως TracedValues μπορούν
να υποστηριχθούν από αυτούς τους βοηθούς.
FileHelper
Η κλάση FileHelper είναι απλά μια παραλλαγή του προηγούμενου παραδείγματος με
τον GnuplotHelper. Το εν λόγω πρόγραμμα παρέχει διαμορφωμένη έξοδο των
ίδιων χρονοσημασμένων δεδομένων, όπως η παρακάτω:
Time (Seconds) = 9.312e+00 Packet Byte Count = 596
Time (Seconds) = 9.312e+00 Packet Byte Count = 564
Δύο αρχεία παρέχονται, ένα για τον κόμβο “0” και ένα για τον κόμβο “1”, όπως
μπορείτε να δείτε στα ονόματα των αρχείων. Ας δούμε τον κώδικα κομμάτι-κομμάτι:
+ // Use FileHelper to write out the packet byte count over time
+ FileHelper fileHelper;
+
+ // Configure the file to be written, and the formatting of output data.
+ fileHelper.ConfigureFile ("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
Το πρόθεμα του αρχείου για τον βοηθό αρχείων είναι το πρώτο όρισμα, και ένας
προσδιοριστής της διαμόρφωσης είναι το επόμενο. Κάποιες άλλες επιλογές διαμόρφωσης
περιλαμβάνουν τα PACE_SEPARATED, COMMA_SEPARATED και TAB_SEPARATED. Οι χρήστες
μπορούν να αλλάξουν τη μορφοποίηση (εάν το FORMATTED καθορίζεται) με μια συμβολοσειρά
διαμόρφωσης όπως η παρακάτω:
+
+ // Set the labels for this formatted output file.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
Εν τέλει, πρέπει να προσδεθεί η πηγή ιχνών που μας ενδιαφέρει. Πάλι, χρησιμοποιούνται
οι μεταβλητές probeType και tracePath σε αυτό το παράδειγμα, και η έξοδος της πηγής
ιχνών “OutputBytes” του probe συνδέεται:
+
+ // Specify the probe type, trace source path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to write.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+
Τα πεδία χαρακτήρων-μπαλαντέρ σε αυτόν τον προσδιοριστή πηγής ιχνών αντιστοιχούν
σε δύο πηγές ιχνών. Εν αντιθέσει με το παράδειγμα του GnuplotHelper, στο οποίο
δύο σειρές δεδομένων παρατέθηκαν στην ίδια γραφική παράσταση, εδώ δύο ξεχωριστά
αρχεία αποθηκεύονται στον δίσκο.
Σύνοψη
Η υποστήριξη για τη συλλογή δεδομένων είναι καινούργια από την έκδοση ns-3.18, και
έχει προστεθεί η βασική υποστήριξη για την παροχή αποτελεσμάτων σε χρονικές σειρές (time series output).
Το βασικό πρότυπο που περιγράφεται παραπάνω μπορεί να αναπαραχθεί και μέσα στα
περιθώρια της υποστήριξης των υπάρχοντων probe και πηγών ιχνών. Περισσότερες δυνατότητες,
συμπεριλαμβανομένης της στατιστικής επεξεργασίας, θα προστεθούν σε μελλοντικές εκδόσεις.