Files
2026-09-27 19:39:00 +03:00

1506 lines
88 KiB
TeX
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
% !TeX document-id = {d31ec456-0f13-4d95-9fc2-bd99b70397a1}
% !TeX TXS-program:compile = txs:///xelatex/[-shell-escape]
% !TEX encoding = UTF-8 Unicode
% !TEX spellcheck = el-GR
%
% Compiter Networks II report
%
% Requires compilation with pdfLaTeX or XeLaTeX
%
% authors:
% Χρήστος Χουτουρίδης ΑΕΜ 8997
% cchoutou@ece.auth.gr
%
% Options:
%
% 1) mainlang=<language>
% Default: english
% Set the default language of the document which affects hyphenations,
% localization (section, dates, etc...)
%
% example: \documentclass[mainlang=greek]{AUThReport}
%
% 2) <language>
% Add hyphenation and typesetting support for other languages
% Currently supports: english, greek, german, frenc
%
% example: \documentclass[english, greek]{AUThReport}
%
% 3) short: Requests a shorter title for the document
% Default: no short
%
% example: \documentclass[short]{AUThReport}
%
\documentclass[a4paper, 11pt, mainlang=greek, english]{AUThReport/AUThReport}
\CurrentDate{\today}
% Document setup
%---------------------------------
% \WorkGroup{Ομάδα Χ}
\AuthorName{Χρήστος Χουτουρίδης}
\AuthorMail{cchoutou@ece.auth.gr}
\AuthorAEM{8997}
%\CoAuthorName{Όνομα Επίθετο}
%\CoAuthorAEM{AEM}
%\CoAuthorMail{xxx@ece.auth.gr}
\DocTitle{Αυτοματοποιημένη Ανάπτυξη Τοπολογίας και Ανάλυση Πρωτοκόλλων στο Mininet}
%\DocSubTitle{Ανάλυση και υλοποίηση του αλγόριθμου bitonic sort για υποσύστημα γραφικών με χρήση CUDA}
\Department{Τμήμα ΗΜΜΥ. Τομέας Ηλεκτρονικής}
\ClassName{Δίκτυα Υπολογιστών ΙΙ}
%
\InstructorName{Αναστάσιος Ντελόπουλος}
\InstructorMail{antelopo@ece.auth.gr}
\CoInstructorName{Εμανουήλ Τσαρδουλιάς}
\CoInstructorMail{etsardou@ece.auth.gr}
% Local package requirements
%---------------------------------
\usepackage{enumitem}
\usepackage{tabularx}
\usepackage{array}
\usepackage{multirow}
\usepackage{float}
\usepackage{xcolor}
\usepackage{soul}
\usepackage{amsmath}
\usepackage{footnote}
\usepackage{footmisc}
\usepackage{minted}
\usepackage{xcolor} %
\setminted[python]{
fontsize=\small,
breaklines,
autogobble,
baselinestretch=1.1,
obeytabs=true
tabsize=2,
numbersep=8pt,
startinline,
gobble=0
}
\setminted[json]{
fontsize=\small,
breaklines,
autogobble,
baselinestretch=1.1,
obeytabs=true
tabsize=2,
numbersep=8pt,
startinline,
gobble=0
}
\setminted[bash]{
fontsize=\small,
breaklines,
autogobble,
baselinestretch=1.1,
obeytabs=true
tabsize=2,
numbersep=8pt,
startinline,
gobble=0
}
%\definecolor{red-highlight}{rgb}{1.0, 0.11, 0.0}
\definecolor{red-highlight}{rgb}{1.0, 0.31, 0.0}
\definecolor{green-highlight}{rgb}{0.0, 0.62, 0.42}
\newcommand{\bxrd}[1]{\colorbox{red-highlight}{#1}}
\newcommand{\bxgr}[1]{\colorbox{green-highlight}{#1}}
\newcommand{\trd}[1]{\textcolor{red-highlight}{\textbf{#1}}}
\newcommand{\tgr}[1]{\textcolor{green-highlight}{\textbf{#1}}}
% “virtual” cites
% ----------------------------------------
%\newcommand{\citeKnuthACM}{%
% Donald E. Knuth, \emph{Structured Programming with go to Statements}, ACM Computing Surveys, vol. 6, no. 4, 1974
%}
% Links
% Repository links
% ----------------------------------------
\newcommand{\repoGithub}{https://github.com/hoo2/Computer-Networks-II}
\newcommand{\repoGitea}{https://git.hoo2.net/hoo2/Computer-Networks-II}
\newcommand{\topologyJsonUrl}{\repoGithub/blob/HEAD/exercise/topology.json}
\newcommand{\buildNetworkUrl}{\repoGithub/blob/HEAD/source/build_network.py}
\newcommand{\resultsUrl}{\repoGithub/tree/HEAD/exercise/results}
\newcommand{\dslDesignUrl}{\repoGithub/blob/HEAD/Mininet_DSL_Design.md}
% Experiment 1
\newcommand{\dhcpExecutionUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/execution.txt}
\newcommand{\dhcpDecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/dhcp-decoded.txt}
\newcommand{\dhcpPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/dhcp.pcap}
% Experiment 2
\newcommand{\arpExecutionUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/execution.txt}
\newcommand{\arpDecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/arp-decoded.txt}
\newcommand{\arpPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/arp.pcap}
% Experiment 3
\newcommand{\routingExecutionUrl}{\repoGithub/blob/HEAD/exercise/results/exp3-routing/execution.txt}
\newcommand{\icmpAPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp3-routing/icmp-A.pcap}
\newcommand{\icmpBPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp3-routing/icmp-B.pcap}
\newcommand{\icmpADecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp3-routing/icmp-A-decoded.txt}
\newcommand{\icmpBDecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp3-routing/icmp-B-decoded.txt}
\begin{document}
\InsertTitle
%\tableofcontents
\section{Εισαγωγή}
Η παρούσα εργασία έχει ως αντικείμενο την \textbf{αυτοματοποιημένη ανάπτυξη δικτυακών τοπολογιών στο περιβάλλον Mininet},
με βάση μια δηλωτική περιγραφή σε αρχείο JSON.
Στο πλαίσιο αυτό υλοποιείται εφαρμογή σε Python, η οποία διαβάζει περιγραφές της τοπολογίας σε μια πρότυπη \textbf{Domain-Specific
Language -- DSL}, και δημιουργεί δυναμικά τους αντίστοιχους hosts, μεταγωγείς, συνδέσμους και δρομολογητές και εφαρμόζει
τις απαιτούμενες ρυθμίσεις δικτύου.
Το Mininet χρησιμοποιείται ως περιβάλλον εξομοίωσης, ώστε η τοπολογία να μπορεί να κατασκευάζεται και να εξετάζεται
με χρήση των ίδιων εργαλείων και πρωτοκόλλων που χρησιμοποιούνται σε ένα πραγματικό σύστημα Linux.
Μετά την ανάπτυξη της τοπολογίας πραγματοποιούνται τρία πειράματα χαμηλού επιπέδου για τη μελέτη των πρωτοκόλλων
\textbf{DHCP} και \textbf{ARP}, καθώς και της \textbf{δρομολόγησης μεταξύ διαφορετικών υποδικτύων}.
Μέσω καταγραφών με το \texttt{tcpdump} εξετάζεται η διαδικασία D.O.R.A. του DHCP, η αντιστοίχιση διευθύνσεων IP σε
διευθύνσεις MAC μέσω του ARP και η μεταβολή των Ethernet διευθύνσεων και του TTL κατά τη διέλευση ενός IP πακέτου
από τον δρομολογητή.
Στόχος των πειραμάτων είναι η σύνδεση της θεωρητικής λειτουργίας των πρωτοκόλλων με την πραγματική μορφή των
πακέτων που ανταλλάσσονται στα διαφορετικά επίπεδα του δικτύου.
\subsection{Παραδοτέα}
Τα παραδοτέα της εργασίας αποτελούνται από:
\begin{itemize}
\item Την παρούσα τεχνική αναφορά.
\item Το αρχείο \href{\topologyJsonUrl}{\texttt{exercise/topology.json}}, το οποίο περιγράφει δηλωτικά την τοπολογία δικτύου που χρησιμοποιείται στην εργασία.
\item Τον κατάλογο \texttt{source/}, ο οποίος περιέχει το αρχείο \href{\buildNetworkUrl}{\texttt{build\_network.py}}, καθώς και τα υπόλοιπα αρχεία
Python που υλοποιούν την εφαρμογή.
\item Τον κατάλογο \href{\resultsUrl}{\texttt{exercise/results/}}, ο οποίος περιέχει τις μετρήσεις και τα παραγόμενα αρχεία των πειραμάτων της εργασίας.
\item Τους συνδέσμους προς τα αποθετήρια στο \href{\repoGithub}{GitHub} και στον \href{\repoGitea}{προσωπικό μου server}, τα οποία περιέχουν τον πηγαίο κώδικα,
τον κώδικα παραγωγής της αναφοράς και τα αποτελέσματα των πειραμάτων.
\end{itemize}
\section{Υλοποίηση}
% ========================= DSL =========================
\subsection{Δηλωτική γλώσσα περιγραφής τοπολογίας}
Για την περιγραφή των δικτυακών τοπολογιών σχεδιάστηκε μία μικρή \textbf{δηλωτική γλώσσα ειδικού σκοπού}
(Domain-Specific Language -- DSL), η οποία χρησιμοποιεί το JSON ως μορφή αναπαράστασης.
Στόχος της γλώσσας είναι να περιγράφει την \emph{επιθυμητή κατάσταση του δικτύου} και όχι τη σειρά των εντολών
που απαιτούνται για την κατασκευή του στο Mininet.
Με αυτόν τον τρόπο η περιγραφή της τοπολογίας παραμένει ανεξάρτητη από λεπτομέρειες της υλοποίησης, όπως τα
ονόματα των εικονικών διεπαφών ή η ακριβής ακολουθία κλήσεων προς το Mininet API.
Η αναλυτική σχεδίαση και η γραμματική της γλώσσας τεκμηριώνονται επίσης στο αρχείο
\href{\dslDesignUrl}{\texttt{Mininet\_DSL\_Design.md}} του αποθετηρίου.
\subsubsection{Σχεδιαστική προσέγγιση}
Ο σχεδιασμός της γλώσσας πραγματοποιήθηκε \textbf{από πάνω προς τα κάτω}, ξεκινώντας από τις έννοιες που είναι
φυσικό να χρησιμοποιούνται για την περιγραφή ενός δικτύου, όπως οι \emph{κόμβοι}, οι \emph{διεπαφές}, οι \emph{σύνδεσμοι} και οι
\emph{υπηρεσίες}.
Παράλληλα, κάθε αφηρημένη έννοια επιλέχθηκε έχοντας υπόψη τις διαθέσιμες πρωτογενείς λειτουργίες του Mininet και
του δικτυακού υποσυστήματος του Linux.
Η προσέγγιση αυτή επιτρέπει στη γλώσσα να παραμένει υψηλού επιπέδου, χωρίς να εισάγει κατασκευές που δεν μπορούν
να μεταφραστούν με σαφή και συστηματικό τρόπο στο υποκείμενο περιβάλλον εκτέλεσης.
Οι βασικές λειτουργίες που απαιτούνται από την εργασία μπορούν να αναχθούν σε ένα σχετικά μικρό σύνολο
\emph{πρωτογενών κατασκευών} του Mininet και του Linux.
Η δημιουργία hosts και switches, η σύνδεσή τους μέσω links και η εκτέλεση εντολών μέσα στους αντίστοιχους
network namespaces επαρκούν για την κατασκευή της απαιτούμενης τοπολογίας.
Ένας δρομολογητής μπορεί αντίστοιχα να μοντελοποιηθεί ως host με περισσότερες από μία διεπαφές, κατάλληλη
Layer-3 διευθυνσιοδότηση και ενεργοποιημένη προώθηση IP.
Ο DHCP server μπορεί να θεωρηθεί ως υπηρεσία που εκτελείται σε έναν κόμβο και συνδέεται με συγκεκριμένη διεπαφή.
Πριν οριστικοποιηθούν οι οντότητες της DSL, εξετάστηκαν οι βασικές λειτουργίες που παρέχει το Mininet και το
δικτυακό υποσύστημα του Linux για την κατασκευή και παραμετροποίηση μιας τοπολογίας.
Οι κύριες λειτουργίες που χρησιμοποιήθηκαν ως βάση είναι οι \texttt{addHost()}, \texttt{addSwitch()} και
\texttt{addLink()}, καθώς και η δυνατότητα εκτέλεσης εντολών μέσα σε κάθε network namespace μέσω του
\texttt{node.cmd()}.
Στις λειτουργίες αυτές προστίθενται η παραμετροποίηση διεπαφών και δρομολόγησης μέσω εργαλείων του Linux και η
εκκίνηση διεργασιών, όπως ο \texttt{dnsmasq}, μέσα στον αντίστοιχο κόμβο.
Η ανάλυση αυτή χρησιμοποιήθηκε για να \textbf{σταθεροποιηθεί το σύνολο των αφαιρέσεων της DSL}, έτσι ώστε κάθε
υψηλού επιπέδου κατασκευή να έχει σαφή δρόμο μετάφρασης προς τις διαθέσιμες λειτουργίες του backend.
Με βάση τις παρατηρήσεις αυτές επιλέχθηκε ένα σύνολο οντοτήτων ώστε η DSL να \textbf{καλύπτει τον χώρο των
κατασκευών που απαιτούνται από την εργασία}.
Αντίστοιχα, το σύνολο των primitives του Mininet και του Linux που χρησιμοποιείται είναι επαρκές ώστε κάθε
κατασκευή της DSL να μπορεί να μεταφραστεί σε συγκεκριμένες λειτουργίες του backend.
Με αυτή την έννοια, τόσο η γλώσσα ως προς τον χώρο του προβλήματος όσο και τα χρησιμοποιούμενα primitives ως
προς τον χώρο της υλοποίησης λειτουργούν \emph{«επί»}.
Δηλαδή, δεν παραμένει απαίτηση της εργασίας χωρίς αναπαράσταση στη DSL ούτε κατασκευή της DSL χωρίς αντίστοιχη
υλοποίηση στο Mininet και στο Linux.
Οι βασικές οντότητες της γλώσσας είναι οι \emph{κόμβοι}, οι \emph{διεπαφές}, οι \emph{σύνδεσμοι}, οι
\emph{ρυθμίσεις κόμβων} και οι \emph{υπηρεσίες}.
\subsubsection{Βασική γραμματική}
Η τοπολογία περιγράφεται από τρεις κύριες κατηγορίες αντικειμένων: \texttt{nodes}, \texttt{links} και
\texttt{services}.
Η βασική δομή της γλώσσας μπορεί να συνοψιστεί ως εξής:
\begin{verbatim}
Network
|-- Nodes
| |-- name
| |-- type
| |-- interfaces
| `-- settings
|
|-- Links
| |-- name
| |-- endpoints
| | |-- node
| | `-- interface
| `-- settings
|
`-- Services
|-- type
|-- node
|-- interface
`-- settings
\end{verbatim}
Κάθε κατηγορία έχει \textbf{διαφορετική σημασιολογική ευθύνη}.
Ένας κόμβος(node) αναπαριστά έναν συμμετέχοντα του δικτύου, μία διεπαφή(interface) ένα σημείο σύνδεσης που ανήκει σε έναν κόμβο
και ένας σύνδεσμος(link) συνδέει δύο τέτοια σημεία.
Οι ρυθμίσεις(settings) κόμβου περιγράφουν ιδιότητες του ίδιου του δικτυακού namespace, ενώ οι υπηρεσίες(services) αναπαριστούν
ανεξάρτητες διεργασίες που εκτελούνται μέσα σε αυτό.
\subsubsection{Κόμβοι και διεπαφές}
Οι κόμβοι δηλώνονται με ένα μοναδικό λογικό όνομα και έναν τύπο.
Οι τύποι που υποστηρίζονται στην παρούσα υλοποίηση είναι \texttt{host}, \texttt{switch} και \texttt{router}.
Ο τύπος εκφράζει τη \emph{σημασιολογία του κόμβου} και όχι απαραίτητα το συγκεκριμένο αντικείμενο του Mininet που
θα χρησιμοποιηθεί για την υλοποίησή του.
Οι διεπαφές \textbf{ανήκουν στους κόμβους} και προσδιορίζονται από λογικά ονόματα, τα οποία δεν απαιτείται να
ταυτίζονται με τα ονόματα που θα δημιουργηθούν τελικά στο Linux.
Για παράδειγμα, μία διεπαφή με λογικό όνομα \texttt{lan} μπορεί κατά την υλοποίηση να αντιστοιχιστεί στη
συγκεκριμένη διεπαφή Linux/Mininet \texttt{r0-eth0}.
Η επιλογή αυτή επιτρέπει στο αρχείο JSON να χρησιμοποιεί ονόματα που εκφράζουν τον ρόλο μιας διεπαφής και όχι
λεπτομέρειες της διαδικασίας δημιουργίας της.
Μία διεπαφή μπορεί να χρησιμοποιεί στατική διευθυνσιοδότηση, DHCP ή να μην διαθέτει καθόλου Layer-3
παραμετροποίηση.
Στην περίπτωση στατικής διευθυνσιοδότησης δηλώνεται η διεύθυνση μαζί με το prefix και, προαιρετικά, μία
προεπιλεγμένη πύλη.
Επιπλέον μπορούν να δηλωθούν ιδιότητες όπως η διεύθυνση MAC και το MTU.
Ιδιαίτερη σημασία έχει η διάκριση μεταξύ της \textbf{απουσίας} του πεδίου \texttt{interfaces} και της δήλωσης
ενός κενού αντικειμένου \texttt{interfaces}.
Όταν το πεδίο παραλείπεται, ο κόμβος θεωρείται ότι διαθέτει \emph{δυναμικό σύνολο διεπαφών} και νέες διεπαφές
μπορούν να δημιουργηθούν κατά την επίλυση των συνδέσμων.
Αντίθετα, όταν το πεδίο υπάρχει, ακόμη και αν είναι κενό, το σύνολο των διαθέσιμων διεπαφών θεωρείται
\emph{σταθερό}.
\subsubsection{Σύνδεσμοι και αυτόματη επιλογή διεπαφών}
Κάθε σύνδεσμος αποτελεί αυτοτελή οντότητα και συνδέει ακριβώς δύο endpoints.
Κάθε endpoint προσδιορίζει τον κόμβο στον οποίο ανήκει και τη λογική διεπαφή μέσω της οποίας πραγματοποιείται η
σύνδεση.
Η διεπαφή μπορεί να δηλωθεί ρητά ή να χρησιμοποιηθεί ο ειδικός επιλογέας \texttt{auto}.
Όταν χρησιμοποιείται το \texttt{auto} σε κόμβο με σταθερό σύνολο διεπαφών, επιλέγεται μία από τις δηλωμένες
διεπαφές που δεν έχει ήδη δεσμευτεί από άλλη σύνδεση.
Αν δεν υπάρχει ελεύθερη διεπαφή, η τοπολογία θεωρείται μη έγκυρη και \textbf{δεν δημιουργείται επιπλέον θύρα
σιωπηρά}.
Όταν αντίθετα το σύνολο διεπαφών έχει παραλειφθεί, το \texttt{auto} επιτρέπει τη δυναμική δημιουργία νέας λογικής
διεπαφής για τις ανάγκες του συνδέσμου.
Οι σύνδεσμοι μπορούν επίσης να περιλαμβάνουν παραμέτρους προσομοίωσης χαρακτηριστικών του φυσικού μέσου.
Η τρέχουσα γλώσσα υποστηρίζει περιορισμό εύρους ζώνης, καθυστέρηση, απώλεια πακέτων και jitter μέσω των πεδίων
\texttt{bandwidth\_mbps}, \texttt{delay\_ms}, \texttt{loss\_percent} και \texttt{jitter\_ms}.
\subsubsection{Ρυθμίσεις κόμβων και υπηρεσίες}
Οι ρυθμίσεις που αφορούν τη λειτουργία του ίδιου του κόμβου τοποθετούνται στο αντικείμενο \texttt{settings} του
αντίστοιχου node.
Για τον τύπο \texttt{router}, για παράδειγμα, υποστηρίζονται η ενεργοποίηση του IP forwarding και η
απενεργοποίηση του reverse path filtering.
Οι ιδιότητες αυτές αντιμετωπίζονται ως \emph{χαρακτηριστικά του network namespace} και όχι ως ανεξάρτητες
υπηρεσίες.
Οι υπηρεσίες μοντελοποιούνται ξεχωριστά επειδή αντιστοιχούν σε \textbf{διεργασίες που εκτελούνται πάνω σε έναν
κόμβο}.
Στην παρούσα εργασία υποστηρίζεται η υπηρεσία \texttt{dhcp-server}, η οποία συνδέεται με έναν κόμβο και μία από
τις διεπαφές του.
Οι παράμετροι της υπηρεσίας περιλαμβάνουν το εύρος διευθύνσεων που μπορούν να εκχωρηθούν και την προεπιλεγμένη
πύλη που διαφημίζεται στους DHCP clients.
Η θέση εκτέλεσης μιας υπηρεσίας και η διεπαφή στην οποία συνδέεται αποτελούν μέρος της ίδιας της ταυτότητάς της
και για τον λόγο αυτό δηλώνονται έξω από το αντικείμενο \texttt{settings}.
Με αυτόν τον διαχωρισμό, το \texttt{settings} περιγράφει αποκλειστικά τη συμπεριφορά της υπηρεσίας και όχι το
σημείο στο οποίο αυτή τοποθετείται μέσα στην τοπολογία.
\subsubsection{Αυστηρότητα της γραμματικής}
Η γραμματική σχεδιάστηκε ώστε να είναι \textbf{αυστηρή} και να μην αγνοεί άγνωστα πεδία ή μη υποστηριζόμενες
τιμές.
Ένα τυπογραφικό λάθος σε ένα όνομα ιδιότητας δεν αντιμετωπίζεται επομένως ως απουσία της ιδιότητας, αλλά ως
σφάλμα της περιγραφής.
Η επιλογή αυτή περιορίζει την πιθανότητα μία συντακτικά αποδεκτή αλλά διαφορετική από την επιθυμητή τοπολογία
να δημιουργηθεί χωρίς εμφανή προειδοποίηση.
Η γλώσσα διαχωρίζει επίσης τη \emph{δομική εγκυρότητα} μιας περιγραφής από τη \emph{σημασιολογική συνέπειά} της.
Ένα αντικείμενο μπορεί να ακολουθεί σωστά τη γραμματική αλλά να περιγράφει, για παράδειγμα, έναν σύνδεσμο προς
ανύπαρκτο κόμβο ή μία στατική πύλη εκτός του αντίστοιχου υποδικτύου.
Η διάκριση αυτή αξιοποιείται στη συνέχεια από την αρχιτεκτονική του builder, όπου η ανάλυση της γραμματικής και
ο σημασιολογικός έλεγχος πραγματοποιούνται σε \textbf{διαφορετικά στάδια}.
% ========================= Builder =========================
\subsection{Υλοποίηση του Builder}
Η υλοποίηση του builder ακολουθεί τον διαχωρισμό που εισάγει η DSL και οργανώνεται ως μία ακολουθία ανεξάρτητων
σταδίων, καθένα από τα οποία μετασχηματίζει την πληροφορία σε μία περισσότερο συγκεκριμένη αναπαράσταση.
Η δομή αυτή επιτρέπει τον σαφή διαχωρισμό ανάμεσα στην περιγραφή της τοπολογίας, στον έλεγχο της εγκυρότητάς της
και στην τελική δημιουργία και εκτέλεση του δικτύου στο Mininet.
\subsubsection{Δομή των αρχείων}
Ο πηγαίος κώδικας του builder βρίσκεται στον κατάλογο \texttt{source/}, ενώ η περιγραφή και τα αποτελέσματα της
συγκεκριμένης εργαστηριακής άσκησης διατηρούνται χωριστά στον κατάλογο \texttt{exercise/}.
Η βασική δομή του αποθετηρίου είναι η ακόλουθη:
\begin{verbatim}
.
|-- source/
| |-- build_network.py
| |-- topology_loader.py
| |-- topology_parser.py
| |-- topology_validator.py
| |-- topology_plan.py
| `-- topology_renderer.py
|
|-- exercise/
| |-- topology.json
| |-- topology.generated.py
| `-- results/
|
|-- Mininet_DSL_Design.md
`-- README.md
\end{verbatim}
\begin{itemize}
\item Το \texttt{topology\_loader.py} είναι υπεύθυνο αποκλειστικά για τη φόρτωση του αρχείου JSON από το σύστημα
αρχείων και την παραγωγή της αντίστοιχης ακατέργαστης Python δομής.
\item Το \texttt{topology\_parser.py} περιέχει τη γραμματική, τα \texttt{Enum} και τα \texttt{dataclass} αντικείμενα
που αποτελούν το τυποποιημένο σημασιολογικό μοντέλο της DSL.
\item Το \texttt{topology\_validator.py} ελέγχει τη σημασιολογική συνέπεια της τοπολογίας, χωρίς να πραγματοποιεί
οποιαδήποτε μεταβολή στο δίκτυο.
\item Το \texttt{topology\_plan.py} επιλύει τις αφηρημένες επιλογές της DSL και παράγει ένα πλήρως συγκεκριμένο
\texttt{ExecutionPlan}.
\item Το \texttt{topology\_renderer.py} μετατρέπει το σχέδιο αυτό σε εκτελέσιμο Python κώδικα για το Mininet, ο οποίος
εξάγεται σε ξεχωριστό αρχείο και αποτελεί το εκτελέσιμο Python listing της πλήρως επιλυμένης τοπολογίας.
\item Τέλος, το \texttt{build\_network.py} αποτελεί τον \textbf{coordinator} και το μοναδικό user-facing entry point,
συνδέοντας τα επιμέρους στάδια και αναλαμβάνοντας την τελική εκτέλεση του παραγόμενου προγράμματος.
\end{itemize}
\subsubsection{Χρήση}
Η κανονική χρήση του builder απαιτεί μόνο το αρχείο JSON που περιγράφει την επιθυμητή τοπολογία.
Για την τοπολογία της παρούσας εργασίας η πλήρης κατασκευή και εκτέλεση πραγματοποιείται με την εντολή:
\begin{minted}{bash}
sudo python3 source/build_network.py exercise/topology.json
\end{minted}
Η εκτέλεση αυτή μεταγλωττίζει πρώτα την τοπολογία, δημιουργεί το αρχείο
\texttt{exercise/topology.generated.py} και στη συνέχεια εκτελεί \textbf{το ίδιο ακριβώς παραγόμενο αρχείο}.
Μετά την κατασκευή και παραμετροποίηση του δικτύου ανοίγει το Mininet CLI, από το οποίο εκτελούνται τα πειράματα.
Κατά την ανάπτυξη είναι επίσης δυνατό να παραχθεί μόνο το ενδιάμεσο Python πρόγραμμα, χωρίς να δημιουργηθεί
κανένα network namespace ή άλλη κατάσταση στο σύστημα.
Για παράδειγμα:
\begin{minted}{bash}
python3 source/build_network.py exercise/topology.json --emit [Optional file name]
\end{minted}
Η μορφή αυτή δεν απαιτεί δικαιώματα root και είναι χρήσιμη για την επιθεώρηση του αποτελέσματος της
μεταγλώττισης ή για τον εντοπισμό σφαλμάτων πριν από την πραγματική εκτέλεση.
Το \texttt{--emit} μπορεί επιπλέον να δεχθεί συγκεκριμένο path για το παραγόμενο αρχείο.
Πριν από την εκτέλεση μπορεί επίσης να πραγματοποιηθεί έλεγχος του περιβάλλοντος με:
\begin{minted}{bash}
python3 source/build_network.py --env-check
\end{minted}
Ο έλεγχος επιβεβαιώνει την παρουσία του Mininet, του Open vSwitch και των εργαλείων Linux που απαιτούνται από
τον builder και τα πειράματα, όπως τα \texttt{ip}, \texttt{tc}, \texttt{sysctl}, \texttt{dnsmasq},
\texttt{dhclient}, \texttt{tcpdump} και \texttt{ping}.
Ο ίδιος έλεγχος πραγματοποιείται αυτόματα πριν από την πραγματική εκτέλεση μιας παραγόμενης τοπολογίας.
\subsubsection{Διαχωρισμός περιγραφής τοπολογίας και runtime κατάστασης}
Βασική σχεδιαστική επιλογή είναι ο \textbf{διαχωρισμός της δηλωμένης τοπολογίας από την κατάσταση που δημιουργείται
κατά την εκτέλεσή της}.
Το αρχείο JSON περιγράφει την επιθυμητή διαμόρφωση και τις πηγές από τις οποίες θα προκύψει η παραμετροποίηση,
χωρίς να επιχειρεί να αποθηκεύσει την παροδική κατάσταση ενός εκτελούμενου δικτύου.
Για παράδειγμα, η δήλωση:
\begin{minted}{json}
"net0": {
"addressing": "dhcp"
}
\end{minted}
δεν καθορίζει ποια διεύθυνση IP θα έχει τελικά ο host.
Δηλώνει ότι η διεύθυνση πρέπει να αποκτηθεί δυναμικά από μία υπηρεσία DHCP κατά την εκτέλεση της τοπολογίας.
Αντίστοιχα, ένας στατικός σύνδεσμος στο JSON οδηγεί στη δημιουργία πραγματικών virtual Ethernet interfaces,
χωρίς τα τελικά ονόματα αυτών των interfaces να χρειάζεται να εμφανίζονται στην αρχική περιγραφή.
Η ίδια διάκριση ισχύει για τις DHCP leases, τον ARP neighbor table, τους μετρητές πακέτων και τα αρχεία
\texttt{pcap}, τα οποία αποτελούν \emph{runtime state} και δεν ανήκουν στη δηλωτική γλώσσα.
Για τον ίδιο λόγο ο builder δεν εκκινεί αυτόματα το \texttt{dhclient} στους hosts που έχουν δηλωθεί ως DHCP
clients, καθώς η απόκτηση της διεύθυνσης αποτελεί μέρος της πειραματικής διαδικασίας της εργασίας.
Η αρχή αυτή αποτυπώνεται συνοπτικά ως:
\begin{verbatim}
Declarative topology Runtime state
static address -------> configured IP address
static gateway -------> routing-table entry
DHCP addressing -------> dynamically acquired lease
link declaration -------> veth / Mininet interfaces
service declaration -------> running process
ARP entries
packet captures
counters
\end{verbatim}
\subsubsection{Compiler-like αρχιτεκτονική}
Η εσωτερική αρχιτεκτονική του builder σχεδιάστηκε με λογική παρόμοια με αυτή ενός \textbf{μεταγλωττιστή}.
Αντί η εφαρμογή να διαβάζει ένα JSON και να καλεί άμεσα συναρτήσεις του Mininet, η περιγραφή περνά από
διαδοχικά στάδια, καθένα από τα οποία έχει σαφώς περιορισμένη ευθύνη.
Η συνολική ροή είναι:
\begin{verbatim}
topology.json
↓
[load]
↓
raw JSON dictionary
↓
[parse]
↓
typed Topology model
↓
[validate]
↓
validated Topology
↓
[plan]
↓
ExecutionPlan
↓
[render]
↓
topology.generated.py
↓
[execute]
↓
Mininet CLI
↓
[cleanup]
\end{verbatim}
Ο διαχωρισμός αυτός επιτρέπει σε κάθε στάδιο να εξετάζεται ανεξάρτητα και μεταφέρει σταδιακά την περιγραφή από
μία υψηλού επιπέδου δήλωση πρόθεσης σε μία πλήρως συγκεκριμένη ακολουθία ενεργειών Mininet και Linux.
Παράλληλα, κάθε κατηγορία σφάλματος ανήκει στο στάδιο που διαθέτει την απαραίτητη πληροφορία για να την εντοπίσει.
\paragraph{Φόρτωση -- \texttt{topology\_loader.py}.}
Το πρώτο στάδιο αφορά αποκλειστικά την πρόσβαση στο αρχείο και την ανάλυση της σύνταξης JSON.
Η δημόσια συνάρτηση \texttt{load\_topology()} διαβάζει το αρχείο και επιστρέφει ένα
\texttt{Dict[str, Any]}, χωρίς να γνωρίζει οτιδήποτε για τη σημασιολογία της DSL.
\begin{verbatim}
raw = load_topology("exercise/topology.json")
JSON file
|
`--> Dict[str, Any]
\end{verbatim}
Σφάλματα όπως ανύπαρκτο αρχείο, μη έγκυρο JSON ή root αντικείμενο διαφορετικό από JSON object αναφέρονται ως
\texttt{TopologyLoadError}.
Στο σημείο αυτό δεν εξετάζεται ακόμη αν ένα \texttt{type} είναι έγκυρο ή αν ένας σύνδεσμος αναφέρεται σε
υπαρκτό κόμβο.
\paragraph{Parsing -- \texttt{topology\_parser.py}.}
Το δεύτερο στάδιο μετατρέπει την ακατέργαστη δομή JSON στο \textbf{τυποποιημένο σημασιολογικό μοντέλο} της DSL.
Η δημόσια συνάρτηση \texttt{parse\_topology()} κατασκευάζει αντικείμενα όπως \texttt{Topology}, \texttt{Node},
\texttt{Interface}, \texttt{Link} και \texttt{Service}, χρησιμοποιώντας \texttt{Enum} για τα κλειστά σύνολα τιμών.
Για παράδειγμα, ένα τμήμα JSON όπως:
\begin{minted}{json}
{
"node": "s1",
"interface": "auto"
}
\end{minted}
δεν παραμένει ένα γενικό dictionary, αλλά μετατρέπεται εννοιολογικά σε:
\begin{minted}{python}
LinkEndpoint(
node="s1",
interface=LinkInterfaceSelector.AUTO
)
\end{minted}
Το στάδιο αυτό εφαρμόζει επίσης την \emph{αυστηρή γραμματική} της γλώσσας.
Άγνωστα πεδία ή μη υποστηριζόμενες τιμές προκαλούν \texttt{TopologyParseError}, αντί να αγνοούνται σιωπηρά.
\paragraph{Validation -- \texttt{topology\_validator.py}.}
Μετά το parsing η δομή είναι γραμματικά έγκυρη, αυτό όμως δεν συνεπάγεται ότι περιγράφει και συνεπές δίκτυο.
Η δημόσια συνάρτηση \texttt{validate()} πραγματοποιεί τους ελέγχους που απαιτούν γνώση περισσότερων από ενός
αντικειμένων της τοπολογίας.
Για παράδειγμα, το ακόλουθο JSON μπορεί να αναλυθεί συντακτικά, αλλά δεν περιγράφει έγκυρη στατική διεπαφή:
\begin{minted}{json}
"net0": {
"addressing": "static"
}
\end{minted}
Το validation θα απορρίψει τη συγκεκριμένη περιγραφή επειδή απουσιάζει η στατική διεύθυνση.
Αντίστοιχα ελέγχονται αναφορές σε ανύπαρκτους κόμβους, επαναχρησιμοποίηση interfaces, διευθύνσεις και gateways,
διαθεσιμότητα ports για \texttt{auto}, καθώς και η συνέπεια των ρυθμίσεων της υπηρεσίας DHCP.
Σε αντίθεση με ένα απλό fail-fast μοντέλο, ο validator συλλέγει τα προβλήματα σε αντικείμενα
\texttt{ValidationIssue} και τα επιστρέφει συγκεντρωτικά μέσω ενός \texttt{TopologyValidationError}.
Με αυτόν τον τρόπο ο χρήστης μπορεί να διορθώσει περισσότερα από ένα προβλήματα σε έναν κύκλο εκτέλεσης.
\paragraph{Planning -- \texttt{topology\_plan.py}.}
Το planning είναι το σημείο στο οποίο η έγκυρη πλέον περιγραφή μετατρέπεται σε μία
\textbf{πλήρως επιλυμένη ενδιάμεση αναπαράσταση}.
Η δημόσια συνάρτηση \texttt{plan()} παράγει ένα \texttt{ExecutionPlan}, στο οποίο δεν παραμένουν αφηρημένοι
selectors όπως \texttt{auto} ή άλλες αποφάσεις που πρέπει να ληφθούν από τον backend.
Για παράδειγμα, έστω ένας switch(node) με δύο ρητά δηλωμένες λογικές διεπαφές:
\begin{minted}{json}
{
"name": "s1",
"type": "switch",
"interfaces": {
"client": {},
"uplink": {}
}
}
\end{minted}
και δύο σύνδεσμοι, από τους οποίους ο πρώτος χρησιμοποιεί \texttt{auto}, ενώ ο δεύτερος ζητά ρητά τη διεπαφή
\texttt{uplink}:
\begin{minted}{json}
[{
"endpoints": [
{"node": "h1", "interface": "net0"},
{"node": "s1", "interface": "auto"}
]
},
{
"endpoints": [
{"node": "r0", "interface": "lan"},
{"node": "s1", "interface": "uplink"}
]
}]
\end{minted}
Πριν από την επίλυση των \texttt{auto}, ο planner εντοπίζει όλες τις ρητές αναφορές σε interfaces και δεσμεύει
τη \texttt{uplink}.
Το διαθέσιμο σύνολο διεπαφών του \texttt{s1} για αυτόματη επιλογή περιέχει επομένως μόνο τη \texttt{client}.
\begin{minted}{python}
reserved["s1"] = {"uplink"}
free_interfaces["s1"] = ["client"]
\end{minted}
Κατά το planning, το \texttt{auto} του πρώτου συνδέσμου επιλύεται συνεπώς στη λογική διεπαφή \texttt{client}.
Στο συγκεκριμένο παράδειγμα οι λογικές διεπαφές αντιστοιχίζονται στη συνέχεια και στα συγκεκριμένα ονόματα
διεπαφών που θα χρησιμοποιήσει το Mininet:
\begin{verbatim}
h1:net0 -> h1-eth0
s1:client -> s1-eth0
r0:lan -> r0-eth0
s1:uplink -> s1-eth1
\end{verbatim}
Με αυτόν τον τρόπο μία προηγούμενη αυτόματη επιλογή δεν μπορεί να καταλάβει interface που έχει ζητηθεί ρητά από
μεταγενέστερο link.
Το \texttt{auto} λειτουργεί επομένως ως \emph{επιλογέας διαθέσιμης λογικής διεπαφής} και όχι ως όνομα
διεπαφής.
Η συμπεριφορά είναι διαφορετική όταν το πεδίο \texttt{interfaces} έχει παραλειφθεί πλήρως από έναν κόμβο.
Σε αυτή την περίπτωση ο planner δημιουργεί συνθετικά λογικά ονόματα, όπως \texttt{auto0} και \texttt{auto1},
τα οποία αντιστοιχίζονται στη συνέχεια σε συγκεκριμένα ονόματα διεπαφών όπως \texttt{s1-eth0} και \texttt{s1-eth1}.
Στο ίδιο στάδιο αποφασίζονται και backend-specific λεπτομέρειες που δεν πρέπει να εμφανίζονται στη DSL.
Έτσι, η σημασιολογία ενός απλού Layer-2 switch μετατρέπεται από τον planner στην επιλογή
\texttt{switch\_fail\_mode = "standalone"} για το Open vSwitch.
Ένα απλοποιημένο τμήμα του \texttt{ExecutionPlan} για το προηγούμενο παράδειγμα μπορεί επομένως να θεωρηθεί ότι
έχει τη μορφή:
\begin{minted}{python}
PlannedLinkEndpoint(
node="s1",
logical_interface="client",
interface_name="s1-eth0"
)
PlannedLinkEndpoint(
node="s1",
logical_interface="uplink",
interface_name="s1-eth1"
)
PlannedNode(
name="s1",
type=NodeType.SWITCH,
switch_fail_mode="standalone"
)
\end{minted}
Ο planner δεν δημιουργεί interfaces και δεν τα εισάγει στο Mininet.
Η ευθύνη του τελειώνει όταν όλες οι αποφάσεις που απαιτούνται για την εκτέλεση έχουν αποτυπωθεί στο
\texttt{ExecutionPlan}.
\paragraph{Rendering -- \texttt{topology\_renderer.py}.}
Το renderer δέχεται το πλήρως επιλυμένο \texttt{ExecutionPlan} και το μετατρέπει σε ένα ολοκληρωμένο Python
πρόγραμμα μέσω της δημόσιας συνάρτησης \texttt{render\_python()}.
Σε αυτό το στάδιο \textbf{δεν πραγματοποιείται νέα σημασιολογική απόφαση}: ο renderer αποτυπώνει σε κώδικα τις
επιλογές που έχουν ήδη γίνει από τον planner.
Για το προηγούμενο παράδειγμα μπορούν να παραχθούν εντολές της μορφής:
\begin{minted}{python}
nodes['h1'] = net.addHost('h1', ip=None)
nodes['r0'] = net.addHost('r0', ip=None)
nodes['s1'] = net.addSwitch('s1', failMode='standalone')
net.addLink(
nodes['h1'],
nodes['s1'],
intfName1='h1-eth0',
intfName2='s1-eth0',
)
net.addLink(
nodes['r0'],
nodes['s1'],
intfName1='r0-eth0',
intfName2='s1-eth1',
)
\end{minted}
Παρατηρείται ότι στο παραγόμενο πρόγραμμα δεν υπάρχει πλέον ο selector \texttt{auto}.
Η επιλογή \texttt{s1:client} έχει ήδη πραγματοποιηθεί από τον planner και ο renderer γνωρίζει μόνο το πλήρως
επιλυμένο ζεύγος \texttt{s1:client} και \texttt{s1-eth0}.
Η χρήση του \texttt{ip=None} εμποδίζει το Mininet να εκχωρήσει τις δικές του προεπιλεγμένες διευθύνσεις στους
hosts, ώστε η διευθυνσιοδότηση να παραμένει αποκλειστικά υπό τον έλεγχο της DSL.
Ανάλογα με το σχέδιο, ο renderer παράγει επίσης εντολές για IP addresses, routes, sysctls, \texttt{TCLink} και
εκκίνηση του \texttt{dnsmasq}.
Το παραγόμενο πρόγραμμα περιλαμβάνει ακόμη το πλήρες lifecycle του δικτύου:
\begin{minted}{python}
net.build()
net.start()
# interface configuration
# routes
# sysctls
# services
CLI(net)
# finally:
# stop started services
# net.stop()
\end{minted}
\paragraph{Το παραγόμενο Python ως ενδιάμεση ``assembly''.}
Το αρχείο \texttt{topology.generated.py} έχει σκόπιμα κεντρικό ρόλο στην αρχιτεκτονική και δεν αποτελεί απλώς
ένα προσωρινό implementation detail.
Μπορεί να θεωρηθεί ως η \emph{``assembly'' της DSL}: είναι χαμηλότερου επιπέδου από το JSON, πλήρως συγκεκριμένο,
άμεσα εκτελέσιμο και ταυτόχρονα αρκετά αναγνώσιμο ώστε να μπορεί να επιθεωρηθεί από τον χρήστη.
Η αντιστοίχιση μπορεί να συνοψιστεί ως:
\begin{verbatim}
topology.json: declarative source
Topology: typed semantic representation
ExecutionPlan: resolved intermediate representation
topology.generated.py: executable "assembly"
Mininet / Linux: runtime
\end{verbatim}
Ο coordinator αποθηκεύει πάντοτε το παραγόμενο Python πριν από την εκτέλεση και στη συνέχεια εκτελεί ακριβώς
αυτό το αρχείο.
Δεν υπάρχει δεύτερος, ανεξάρτητος executor που να μεταφράζει απευθείας το \texttt{ExecutionPlan} σε Mininet
operations, αποφεύγοντας έτσι τον κίνδυνο διαφορετικής συμπεριφοράς μεταξύ του inspectable artifact και του
πραγματικού runtime.
\paragraph{Εκτέλεση και συντονισμός -- \texttt{build\_network.py}.}
Το \texttt{build\_network.py} συνθέτει τα προηγούμενα στάδια μέσω της συνάρτησης
\texttt{compile\_topology()}:
\begin{minted}{python}
topology = parse_topology(load_topology(path))
validate(topology)
execution_plan = plan(topology)
source = render_python(execution_plan)
\end{minted}
Το παραγόμενο source γράφεται στο \texttt{topology.generated.py} και, στην κανονική λειτουργία, εκτελείται ως
ξεχωριστό Python process με τα ίδια δικαιώματα με τον coordinator.
Η πραγματική εκτέλεση απαιτεί root privileges, ενώ η φόρτωση, το parsing, το validation, το planning και το
rendering μπορούν να πραγματοποιηθούν χωρίς αυτά.
Το generated πρόγραμμα δημιουργεί τους κόμβους και τα links, εφαρμόζει τη δικτυακή παραμετροποίηση, εκκινεί τις
προβλεπόμενες υπηρεσίες και παραδίδει τον έλεγχο στον χρήστη μέσω του Mininet CLI.
Η έξοδος από το CLI οδηγεί σε δομημένο cleanup μέσω \texttt{finally}, όπου τερματίζονται οι service processes που
ξεκίνησε το ίδιο το πρόγραμμα και στη συνέχεια καλείται το \texttt{net.stop()}.
\subsubsection{Έλεγχος των επιμέρους σταδίων}
Η ανεξαρτησία των σταδίων αξιοποιείται και κατά την ανάπτυξη και τον εντοπισμό σφαλμάτων.
Κάθε βασικό module του pipeline διαθέτει ένα μικρό \textbf{self-test του δημόσιου interface του}, το οποίο μπορεί
να εκτελεστεί χωρίς να δημιουργηθεί πραγματικό Mininet δίκτυο.
Για παράδειγμα:
\begin{minted}{bash}
python3 source/topology_loader.py
python3 source/topology_parser.py
python3 source/topology_validator.py
python3 source/topology_plan.py
python3 source/topology_renderer.py
\end{minted}
Μία επιτυχής εκτέλεση καταλήγει σε μήνυμα της μορφής:
\begin{verbatim}
topology_parser: self-test passed
\end{verbatim}
Τα tests δεν περιορίζονται στην απλή εισαγωγή των modules, αλλά ελέγχουν την κύρια συμπεριφορά του αντίστοιχου
δημόσιου API.
Ο parser, για παράδειγμα, ελέγχει τόσο σωστή μετατροπή σε typed objects όσο και απόρριψη άγνωστων πεδίων, ενώ ο
validator εξετάζει τόσο έγκυρες όσο και πολλαπλά λανθασμένες τοπολογίες.
Αντίστοιχα, ο planner ελέγχει την επίλυση του \texttt{auto}, την παραγωγή των physical interface names, την
επιλογή \texttt{standalone} για τους switches και την παραγωγή των απαιτούμενων sysctls.
Ο renderer ελέγχει ότι το παραγόμενο source είναι συντακτικά έγκυρο Python και ότι περιλαμβάνει τις αναμενόμενες
κλήσεις Mininet, τις υπηρεσίες και το cleanup.
Ο διαχωρισμός αυτός αποδείχθηκε ιδιαίτερα χρήσιμος κατά την ανάπτυξη, καθώς ένα σφάλμα μπορεί να απομονωθεί στο
στάδιο στο οποίο εμφανίζεται, χωρίς να απαιτείται κάθε φορά εκκίνηση του Mininet με δικαιώματα root.
Το \texttt{--emit} συμπληρώνει αυτή τη διαδικασία, επιτρέποντας την επιθεώρηση της τελικής
\emph{``assembly''} πριν από οποιαδήποτε μεταβολή της πραγματικής δικτυακής κατάστασης του συστήματος.
% ========================= Πείραμα 1 =========================
\section{Πείραμα 1 -- DHCP και διαδικασία D.O.R.A.}
\subsection{Σκοπός και πειραματική διαδικασία}
Σκοπός του πρώτου πειράματος είναι η παρατήρηση της διαδικασίας μέσω της οποίας ένας host χωρίς στατική
διευθυνσιοδότηση αποκτά τις απαραίτητες ρυθμίσεις δικτύου από έναν DHCP server.
Ειδικότερα, εξετάζεται η ακολουθία \textbf{Discover--Offer--Request--ACK (D.O.R.A.)} και τα αντίστοιχα πεδία των
Ethernet, IP και UDP headers.
Η τοπολογία εκκινήθηκε από τον κατάλογο \texttt{exercise/} με την εντολή:
\begin{minted}{bash}
sudo python3 ../source/build_network.py topology.json
\end{minted}
Πριν από την καταγραφή αφαιρέθηκε το αποθηκευμένο lease του \texttt{dhclient}, ώστε ο \texttt{h1} να ξεκινήσει
τη διαδικασία χωρίς να επιχειρήσει να επαναχρησιμοποιήσει διεύθυνση από προηγούμενη εκτέλεση.
Αφαιρέθηκε επίσης τυχόν προηγούμενο αρχείο καταγραφής και στη συνέχεια ξεκίνησε το \texttt{tcpdump} στη διεπαφή
\texttt{h1-eth0}.
Οι εντολές που εκτελέστηκαν στο Mininet CLI ήταν:
\begin{minted}{bash}
mininet> h1 rm -f /var/lib/dhcp/dhclient.leases
mininet> h1 rm -f /tmp/dhcp.pcap
mininet> h1 tcpdump -i h1-eth0 -n -w /tmp/dhcp.pcap &
mininet> h1 ps aux | grep tcpdump
mininet> h1 dhclient h1-eth0
mininet> h1 pkill -INT tcpdump
mininet> h1 tcpdump -n -e -vv -r /tmp/dhcp.pcap
\end{minted}
Η επιλογή \texttt{-e} κατά την ανάγνωση της καταγραφής επιτρέπει την εμφάνιση των Ethernet headers και επομένως
των MAC διευθύνσεων που απαιτούνται για την ανάλυση.
Η καταγραφή ολοκληρώθηκε χωρίς απώλειες από το \texttt{tcpdump}, με 12 πακέτα να έχουν καταγραφεί συνολικά.
Η πλήρης συνεδρία της εκτέλεσης βρίσκεται στο \href{\dhcpExecutionUrl}{\texttt{execution.txt}}.
Το αρχικό αρχείο καταγραφής διατίθεται στο \href{\dhcpPcapUrl}{\texttt{dhcp.pcap}}, ενώ η αναλυτικά
αποκωδικοποιημένη μορφή του βρίσκεται στο \href{\dhcpDecodedUrl}{\texttt{dhcp-decoded.txt}}.
\subsection{Αποτελέσματα καταγραφής -- Ζητούμενο 1.1}
Η καταγραφή περιλαμβάνει την αναμενόμενη ακολουθία
\textbf{Discover $\rightarrow$ Offer $\rightarrow$ Request $\rightarrow$ ACK}, η οποία ολοκληρώθηκε επιτυχώς.
Στην πραγματική εκτέλεση καταγράφηκαν δύο DHCP Discover με το ίδιο transaction ID πριν από το πρώτο Offer.
Η χρονική ακολουθία των σχετικών DHCP μηνυμάτων ήταν:
\begin{verbatim}
10:58:29.655251 DHCP Discover
10:58:32.214530 DHCP Discover
10:58:32.670897 DHCP Offer
10:58:32.671193 DHCP Request
10:58:32.673025 DHCP ACK
10:58:32.678132 DHCP Offer
\end{verbatim}
Μεταξύ του πρώτου Discover και του πρώτου Offer παρατηρήθηκαν τρία ARP probes από τον DHCP server για τη
διεύθυνση \texttt{192.168.1.131} και στη συνέχεια ένα ICMP Echo Request προς την ίδια διεύθυνση.
Ο έλεγχος αυτός εισήγαγε καθυστέρηση στην πρώτη απάντηση του server, με αποτέλεσμα ο \texttt{dhclient} να
επαναμεταδώσει το Discover περίπου τρία δευτερόλεπτα μετά το πρώτο.
Και τα δύο Discover χρησιμοποιούν το ίδιο transaction ID, \texttt{0x0ecb5a2e}, επομένως αποτελούν μέρος της
ίδιας προσπάθειας απόκτησης διεύθυνσης και όχι δύο ανεξάρτητες διαδικασίες DHCP.
Παρά την επαναμετάδοση, η διαδικασία ολοκληρώθηκε κανονικά με Offer, Request και ACK και ο \texttt{h1} έλαβε τη
διεύθυνση \texttt{192.168.1.131}.
Μετά το ACK καταγράφηκε ακόμη ένα Offer, χωρίς αυτό να επηρεάζει την ήδη ολοκληρωμένη παραχώρηση της διεύθυνσης.
Η βασική τετράδα D.O.R.A. δίνει τα ακόλουθα στοιχεία:
\begin{table}[H]
\centering
\small
\begin{tabularx}{\textwidth}{
>{\raggedright\arraybackslash}p{1.3cm}
>{\raggedright\arraybackslash}p{5.2cm}
>{\raggedright\arraybackslash}p{2.0cm}
>{\raggedright\arraybackslash}X
}
\textbf{Μήνυμα} &
\textbf{IP} &
\textbf{UDP port} &
\textbf{MAC} \\ \hline
% \textbf{Μήνυμα} &
% \textbf{από $\rightarrow$ προς} &
% \textbf{UDP port από $\rightarrow$ προς} &
% \textbf{MAC από $\rightarrow$ προς} \\ \hline
Discover &
\texttt{0.0.0.0 $\rightarrow$ 255.255.255.255} &
\texttt{68 $\rightarrow$ 67} &
\texttt{12:07:f8:bf:6e:ff $\rightarrow$ ff:ff:ff:ff:ff:ff} \\
Offer &
\texttt{192.168.1.1 $\rightarrow$ 192.168.1.131} &
\texttt{67 $\rightarrow$ 68} &
\texttt{82:3b:16:e9:bb:17 $\rightarrow$ 12:07:f8:bf:6e:ff} \\
Request &
\texttt{0.0.0.0 $\rightarrow$ 255.255.255.255} &
\texttt{68 $\rightarrow$ 67} &
\texttt{12:07:f8:bf:6e:ff $\rightarrow$ ff:ff:ff:ff:ff:ff} \\
ACK &
\texttt{192.168.1.1 $\rightarrow$ 192.168.1.131} &
\texttt{67 $\rightarrow$ 68} &
\texttt{82:3b:16:e9:bb:17 $\rightarrow$ 12:07:f8:bf:6e:ff} \\
\end{tabularx}
\caption{Διευθύνσεις και UDP θύρες των μηνυμάτων της διαδικασίας D.O.R.A.}
\end{table}
\subsection{Ανάλυση της διαδικασίας D.O.R.A.}
Στο \textbf{Discover} ο \texttt{h1} δεν διαθέτει ακόμη διεύθυνση IPv4 και αναζητά διαθέσιμο DHCP server στο
τοπικό δίκτυο.
Για τον λόγο αυτό χρησιμοποιεί ως source IP την \texttt{0.0.0.0} και μεταδίδει το μήνυμα προς την περιορισμένη
broadcast διεύθυνση \texttt{255.255.255.255}, με Ethernet destination \texttt{ff:ff:ff:ff:ff:ff}.
Στο \textbf{Offer} ο DHCP server του \texttt{r0}, με διεύθυνση \texttt{192.168.1.1}, προσφέρει στον client τη
διεύθυνση \texttt{192.168.1.131}.
Στο ίδιο μήνυμα περιλαμβάνονται επίσης η μάσκα \texttt{255.255.255.0}, η broadcast διεύθυνση
\texttt{192.168.1.255} και η προεπιλεγμένη πύλη \texttt{192.168.1.1}.
Ο \texttt{h1} απαντά με \textbf{Request}, στο οποίο δηλώνει τόσο τον server που επέλεξε όσο και τη διεύθυνση που
ζητά να του εκχωρηθεί.
Τα αντίστοιχα options που καταγράφηκαν είναι:
\begin{minted}{text}
Server-ID Option: 192.168.1.1
Requested-IP Option: 192.168.1.131
\end{minted}
Τέλος, με το \textbf{ACK} ο server επιβεβαιώνει την παραχώρηση της \texttt{192.168.1.131} και αποστέλλει τις
τελικές παραμέτρους του lease.
Στην καταγραφή το lease time είναι \texttt{43200} δευτερόλεπτα και η προεπιλεγμένη πύλη που παρέχεται στον
client είναι η \texttt{192.168.1.1}.
\subsection{Broadcast μετάδοση του DHCP Request -- Ζητούμενο 1.2}
Το DHCP Request της αρχικής διαδικασίας απόκτησης διεύθυνσης μεταδόθηκε ως \textbf{broadcast} τόσο στο επίπεδο
Ethernet όσο και στο επίπεδο IP.
Στην καταγραφή παρατηρούνται συγκεκριμένα:
\begin{minted}{text}
Ethernet destination: ff:ff:ff:ff:ff:ff
IP destination: 255.255.255.255
UDP ports: 68 -> 67
\end{minted}
Κατά τη στιγμή αποστολής του Request η παραχώρηση της διεύθυνσης δεν έχει ακόμη ολοκληρωθεί και ο client
συνεχίζει να χρησιμοποιεί την \texttt{0.0.0.0} ως source IP.
Η broadcast μετάδοση επιτρέπει επιπλέον σε όλους τους DHCP servers του τοπικού δικτύου να παρατηρήσουν ποια
προσφορά επέλεξε ο client.
Ο επιλεγμένος server αναγνωρίζεται από το \texttt{Server-ID} του Request, ενώ τυχόν άλλοι servers μπορούν να
διαπιστώσουν ότι οι δικές τους προσφορές δεν επιλέχθηκαν.
Το ACK του \texttt{192.168.1.1} ολοκληρώνει τελικά τη διαδικασία και επιβεβαιώνει ότι η
\texttt{192.168.1.131} μπορεί πλέον να χρησιμοποιηθεί από τον \texttt{h1}.
% ========================= Πείραμα 2 =========================
\section{Πείραμα 2 -- Πρωτόκολλο ARP}
\subsection{Σκοπός και πειραματική διαδικασία}
Σκοπός του δεύτερου πειράματος είναι η παρατήρηση της διαδικασίας αντιστοίχισης μιας γνωστής διεύθυνσης IPv4
στην αντίστοιχη διεύθυνση MAC μέσω του πρωτοκόλλου \textbf{ARP}.
Ειδικότερα, εξετάζεται η αρχική επίλυση της διεύθυνσης του \texttt{h2} από τον \texttt{h1} και η διαφορετική
μορφή μετάδοσης του ARP Request και του ARP Reply.
Η τοπολογία εκκινήθηκε εκ νέου και οι δύο hosts του Subnet A απέκτησαν διευθύνσεις μέσω DHCP.
Οι διευθύνσεις που εκχωρήθηκαν κατά τη συγκεκριμένη εκτέλεση ήταν:
\begin{itemize}
\item \texttt{\textbf{192.168.1.131/24}} για τον \texttt{\textbf{h1}} και
\item \texttt{\textbf{192.168.1.164/24}} για τον \texttt{\textbf{h2}}.
\end{itemize}
Οι αρχικές εντολές της εκτέλεσης ήταν:
\begin{minted}{bash}
sudo python3 ../source/build_network.py topology.json
mininet> h1 ip -4 -br addr
mininet> h2 ip -4 -br addr
mininet> h1 dhclient h1-eth0
mininet> h2 dhclient h2-eth0
mininet> h1 ip -4 -br addr
mininet> h2 ip -4 -br addr
\end{minted}
Πριν από το ping διαγράφηκε ο neighbor table του \texttt{h1}, ώστε να μην υπάρχει ήδη γνωστή αντιστοίχιση
μεταξύ της IP και της MAC διεύθυνσης του \texttt{h2}.
Η κενή κατάσταση του πίνακα επιβεβαιώθηκε με την εντολή \texttt{ip neigh show}.
\begin{minted}{bash}
mininet> h1 ip neigh flush all
mininet> h1 ip neigh show
mininet> h1 rm -f /tmp/arp.pcap
mininet> h1 tcpdump -i h1-eth0 -n arp -w /tmp/arp.pcap &
mininet> h1 ping -c 1 192.168.1.164
mininet> h1 ip neigh show
mininet> h1 pkill -INT tcpdump
mininet> h1 tcpdump -n -e -vv -r /tmp/arp.pcap
\end{minted}
Το φίλτρο \texttt{arp} του \texttt{tcpdump} περιορίζει την καταγραφή στα ARP frames, ενώ η επιλογή \texttt{-e}
κατά την ανάγνωση εμφανίζει τα Ethernet headers και επομένως τις MAC διευθύνσεις πηγής και προορισμού.
Η καταγραφή ολοκληρώθηκε χωρίς απώλειες, με τέσσερα ARP frames να έχουν καταγραφεί συνολικά.
Η πλήρης συνεδρία της εκτέλεσης βρίσκεται στο \href{\arpExecutionUrl}{\texttt{execution.txt}}.
Το αρχικό αρχείο καταγραφής διατίθεται στο \href{\arpPcapUrl}{\texttt{arp.pcap}}, ενώ η αποκωδικοποιημένη μορφή του βρίσκεται στο
\href{\arpDecodedUrl}{\texttt{arp-decoded.txt}}.
\subsection{Αποτελέσματα καταγραφής}
Μετά την εκκαθάριση του neighbor table, το πρώτο ping από τον \texttt{h1} προς τον \texttt{h2} απαίτησε την
επίλυση της MAC διεύθυνσης που αντιστοιχεί στην \texttt{192.168.1.164}.
Το πρώτο ζεύγος πακέτων της καταγραφής ήταν:
\begin{minted}{text}
4a:6f:2a:18:f4:80 > ff:ff:ff:ff:ff:ff
Request who-has 192.168.1.164 tell 192.168.1.131
82:c0:6d:ae:3f:56 > 4a:6f:2a:18:f4:80
Reply 192.168.1.164 is-at 82:c0:6d:ae:3f:56
\end{minted}
Από την καταγραφή προκύπτει επομένως ότι στη συγκεκριμένη εκτέλεση οι δύο hosts είχαν τα ακόλουθα στοιχεία:
\begin{table}[H]
\centering
\begin{tabular}{lll}
\textbf{Host} & \textbf{IPv4} & \textbf{MAC} \\ \hline
\texttt{h1} & \texttt{192.168.1.131} & \texttt{4a:6f:2a:18:f4:80} \\
\texttt{h2} & \texttt{192.168.1.164} & \texttt{82:c0:6d:ae:3f:56} \\
\end{tabular}
\caption{Διευθύνσεις των hosts που συμμετέχουν στο πείραμα ARP.}
\end{table}
Το ping ολοκληρώθηκε επιτυχώς και, μετά την ανταλλαγή ARP, ο neighbor table του \texttt{h1} περιείχε (λογικά) την
αντιστοίχιση:
\begin{minted}{text}
192.168.1.164 dev h1-eth0 lladdr 82:c0:6d:ae:3f:56 REACHABLE
\end{minted}
Το αποτέλεσμα αυτό επιβεβαιώνει ότι ο \texttt{h1} έμαθε τη MAC διεύθυνση του \texttt{h2} μέσω της προηγούμενης
ανταλλαγής ARP και μπορεί πλέον να δημιουργεί απευθείας Ethernet frames προς αυτόν.
\subsection{Ανάλυση του ARP Request και Reply -- Ζητούμενο 2.1}
Κατά την αποστολή του αρχικού ARP Request ο \texttt{h1} γνωρίζει τη διεύθυνση IP του προορισμού, αλλά
\textbf{δεν γνωρίζει ακόμη τη MAC διεύθυνσή του}.
Δεν μπορεί επομένως να δημιουργήσει ένα unicast Ethernet frame προς τον \texttt{h2}.
Για τον λόγο αυτό το ARP Request μεταδίδεται προς την Ethernet broadcast διεύθυνση:
\begin{minted}{text}
Source MAC: 4a:6f:2a:18:f4:80
Destination MAC: ff:ff:ff:ff:ff:ff
Who has 192.168.1.164?
Tell 192.168.1.131
\end{minted}
Όλοι οι κόμβοι του ίδιου Layer-2 broadcast domain μπορούν να λάβουν το Request, αλλά μόνο ο host στον οποίο
ανήκει η \texttt{192.168.1.164} πρέπει να απαντήσει.
Στην συγκεκριμένη περίπτωση ο host αυτός είναι ο \texttt{h2}.
Το ARP Reply, αντίθετα, μεταδίδεται ως \textbf{unicast}:
\begin{minted}{text}
Source MAC: 82:c0:6d:ae:3f:56
Destination MAC: 4a:6f:2a:18:f4:80
192.168.1.164 is-at 82:c0:6d:ae:3f:56
\end{minted}
Ο \texttt{h2} μπορεί να στείλει την απάντηση απευθείας στον \texttt{h1}, επειδή το ARP Request περιλαμβάνει τα
στοιχεία του αποστολέα και επομένως παρέχει στον \texttt{h2} τη MAC διεύθυνση στην οποία πρέπει να απαντήσει.
Δεν υπάρχει συνεπώς ανάγκη το Reply να μεταδοθεί σε όλους τους κόμβους του broadcast domain.
\textbf{Η MAC προορισμού του αρχικού ARP Request είναι επομένως \texttt{ff:ff:ff:ff:ff:ff},
ενώ το ARP Reply επιστρέφει ως unicast στη MAC \texttt{4a:6f:2a:18:f4:80} του \texttt{h1}.}
\subsection{Πρόσθετη παρατήρηση}
Στην καταγραφή εμφανίστηκε περίπου πέντε δευτερόλεπτα αργότερα και ένα δεύτερο ζεύγος ARP Request/Reply προς
την αντίθετη κατεύθυνση:
\begin{minted}{text}
82:c0:6d:ae:3f:56 > 4a:6f:2a:18:f4:80
Request who-has 192.168.1.131 tell 192.168.1.164
4a:6f:2a:18:f4:80 > 82:c0:6d:ae:3f:56
Reply 192.168.1.131 is-at 4a:6f:2a:18:f4:80
\end{minted}
Σε αντίθεση με το αρχικό Request, το δεύτερο Request έχει ήδη ως Ethernet destination τη MAC του
\texttt{h1} και επομένως είναι unicast.
Η ανταλλαγή αυτή σχετίζεται με τη διαχείριση και επιβεβαίωση της κατάστασης του neighbor cache από το Linux και
δεν αποτελεί την αρχική επίλυση που προκαλεί το ping.
Για το ζητούμενο του πειράματος εξετάζεται συνεπώς το \textbf{πρώτο ζεύγος Request/Reply}, στο οποίο φαίνεται
καθαρά η μετάβαση από broadcast αναζήτηση σε unicast απάντηση.
Παρόλα αυτά το γεγονός ότι υπήρχε δεύτερο ζεύγος μας προβλημάτισε ιδιαίτερα μέχρι να ανακαλύψουμε τον λόγο ύπαρξής του!
% ========================= Πείραμα 3 =========================
\section{Πείραμα 3 -- Δρομολόγηση L3 και αλλαγή MAC}
\subsection{Σκοπός και πειραματική διαδικασία}
Σκοπός του τρίτου πειράματος είναι η παρατήρηση της προώθησης ενός IP πακέτου μεταξύ δύο διαφορετικών
υποδικτύων μέσω του δρομολογητή \texttt{r0}.
Ειδικότερα, εξετάζεται ο τρόπος με τον οποίο ο \texttt{h1} αποφασίζει ότι ο \texttt{h3} βρίσκεται σε διαφορετικό
υποδίκτυο, καθώς και οι μεταβολές των MAC διευθύνσεων και του TTL κατά τη διέλευση από τον router.
Το πείραμα εκτελέστηκε στην ήδη ενεργή τοπολογία, στην οποία ο \texttt{h1} είχε αποκτήσει μέσω DHCP τη διεύθυνση
\texttt{192.168.1.131/24}, ενώ ο \texttt{h3} χρησιμοποιούσε τη στατική διεύθυνση
\texttt{192.168.2.10/24}.
Πριν από την καταγραφή εκκαθαρίστηκαν οι neighbor tables των δύο hosts και του router, ώστε να απομακρυνθεί
προϋπάρχουσα κατάσταση ARP.
Οι πρώτες εντολές της εκτέλεσης ήταν:
\begin{minted}{bash}
mininet> h1 ip neigh flush all
mininet> h3 ip neigh flush all
mininet> r0 ip neigh flush all
mininet> h1 ip -4 -br addr
mininet> h1 ip route
mininet> r0 ip -4 -br addr
mininet> r0 ip route
mininet> h3 ip -4 -br addr
mininet> h3 ip route
\end{minted}
Η κατάσταση διευθυνσιοδότησης και δρομολόγησης που επιβεβαιώθηκε ήταν:
\begin{minted}{text}
h1:
192.168.1.131/24
default via 192.168.1.1 dev h1-eth0
r0:
r0-eth0: 192.168.1.1/24
r0-eth1: 192.168.2.1/24
h3:
192.168.2.10/24
default via 192.168.2.1 dev h3-eth0
\end{minted}
Στη συνέχεια ξεκίνησαν \textbf{δύο ταυτόχρονες καταγραφές ICMP}, μία στο Subnet A μέσω του \texttt{h1} και μία
στο Subnet B μέσω του \texttt{h3}.
Έτσι, το ίδιο ICMP Echo Request μπορούσε να παρατηρηθεί πριν και μετά την προώθησή του από τον \texttt{r0}.
\begin{minted}{bash}
mininet> h1 rm -f /tmp/icmp-A.pcap
mininet> h3 rm -f /tmp/icmp-B.pcap
mininet> h1 tcpdump -i h1-eth0 -n icmp -w /tmp/icmp-A.pcap &
mininet> h3 tcpdump -i h3-eth0 -n icmp -w /tmp/icmp-B.pcap &
mininet> h1 ps aux | grep tcpdump
mininet> h3 ps aux | grep tcpdump
mininet> h1 ping -c 1 192.168.2.10
mininet> h1 pkill -INT tcpdump
mininet> h3 pkill -INT tcpdump
\end{minted}
Το ping ολοκληρώθηκε επιτυχώς:
\begin{minted}{text}
64 bytes from 192.168.2.10: icmp_seq=1 ttl=63 time=1.66 ms
1 packets transmitted, 1 received, 0% packet loss
\end{minted}
Μετά την καταγραφή εμφανίστηκαν οι MAC διευθύνσεις των τεσσάρων interfaces που συμμετέχουν στη διαδρομή και
διαβάστηκαν τα δύο αρχεία \texttt{pcap} με εμφάνιση των Ethernet headers:
\begin{minted}{bash}
mininet> h1 ip link show h1-eth0
mininet> h3 ip link show h3-eth0
mininet> r0 ip link show r0-eth0
mininet> r0 ip link show r0-eth1
mininet> h1 tcpdump -n -e -vv -r /tmp/icmp-A.pcap
mininet> h3 tcpdump -n -e -vv -r /tmp/icmp-B.pcap
\end{minted}
Η πλήρης συνεδρία της εκτέλεσης βρίσκεται στο \href{\routingExecutionUrl}{\texttt{execution.txt}}.
Οι αρχικές καταγραφές διατίθενται στα \href{\icmpAPcapUrl}{\texttt{icmp-A.pcap}} και
\href{\icmpBPcapUrl}{\texttt{icmp-B.pcap}}, ενώ οι αποκωδικοποιημένες μορφές τους βρίσκονται στα
\href{\icmpADecodedUrl}{\texttt{icmp-A-decoded.txt}} και \href{\icmpBDecodedUrl}{\texttt{icmp-B-decoded.txt}}.
\subsection{Απόφαση δρομολόγησης μέσω bitwise AND -- Ζητούμενο 3.1}
Ο \texttt{h1} πρέπει αρχικά να αποφασίσει αν η διεύθυνση προορισμού \texttt{192.168.2.10} ανήκει στο ίδιο
υποδίκτυο με τη δική του διεύθυνση \texttt{192.168.1.131/24}.
Για τον σκοπό αυτό εφαρμόζεται bitwise AND μεταξύ κάθε διεύθυνσης και της μάσκας
\texttt{255.255.255.0}.
Για τη διεύθυνση του \texttt{h1} προκύπτει:
\[
192.168.1.131
\mathbin{\&}
255.255.255.0
=
192.168.1.0
\]
ενώ για τη διεύθυνση προορισμού:
\[
192.168.2.10
\mathbin{\&}
255.255.255.0
=
192.168.2.0
\]
Η διαφορά φαίνεται ήδη στο τρίτο octet:
\begin{minted}{text}
h1:
00000001
AND 11111111
= 00000001
h3:
00000010
AND 11111111
= 00000010
\end{minted}
Εφόσον \texttt{192.168.1.0} και \texttt{192.168.2.0} είναι διαφορετικές network addresses, ο \texttt{h1}
συμπεραίνει ότι ο προορισμός \textbf{δεν βρίσκεται στο τοπικό του subnet}.
Συμβουλεύεται επομένως τον πίνακα δρομολόγησης και χρησιμοποιεί την προεπιλεγμένη διαδρομή:
\begin{minted}{text}
default via 192.168.1.1 dev h1-eth0
\end{minted}
Το IP packet εξακολουθεί να έχει ως τελικό προορισμό την \texttt{192.168.2.10}, αλλά το Ethernet frame που
δημιουργεί ο \texttt{h1} αποστέλλεται στη MAC διεύθυνση του gateway \texttt{r0-eth0}.
\subsection{Σύγκριση του ICMP Echo Request στα δύο υποδίκτυα -- Ζητούμενο 3.2}
Οι MAC διευθύνσεις των interfaces που συμμετέχουν στη διαδρομή καταγράφηκαν πριν από την ανάλυση των πακέτων.
Οι τιμές που προέκυψαν κατά τη συγκεκριμένη εκτέλεση ήταν:
\begin{table}[H]
\centering
\begin{tabular}{lll}
\textbf{Interface} & \textbf{IPv4} & \textbf{MAC} \\ \hline
\texttt{h1-eth0} & \texttt{192.168.1.131} & \texttt{4a:6f:2a:18:f4:80} \\
\texttt{h3-eth0} & \texttt{192.168.2.10} & \texttt{2e:ef:81:65:2c:c9} \\
\texttt{r0-eth0} & \texttt{192.168.1.1} & \texttt{ea:2e:7b:6d:78:82} \\
\texttt{r0-eth1} & \texttt{192.168.2.1} & \texttt{7e:41:8e:cb:65:05} \\
\end{tabular}
\caption{Διευθύνσεις των interfaces που συμμετέχουν στη δρομολόγηση.}
\end{table}
Στο Subnet A το ICMP Echo Request καταγράφηκε στη διεπαφή \texttt{h1-eth0} ως:
\begin{minted}{text}
4a:6f:2a:18:f4:80 > ea:2e:7b:6d:78:82
ttl 64
192.168.1.131 > 192.168.2.10
ICMP echo request, id 4650, seq 1
\end{minted}
Η source MAC είναι επομένως η MAC του \texttt{h1-eth0}, ενώ η destination MAC είναι εκείνη του
\texttt{r0-eth0}.
Το Ethernet frame στο Subnet A παραδίδεται δηλαδή από τον \texttt{h1} στην τοπική διεπαφή του gateway.
Μετά την προώθηση του IP packet από τον \texttt{r0}, το ίδιο Echo Request καταγράφηκε στη διεπαφή
\texttt{h3-eth0} του Subnet B ως:
\begin{minted}{text}
7e:41:8e:cb:65:05 > 2e:ef:81:65:2c:c9
ttl 63
192.168.1.131 > 192.168.2.10
ICMP echo request, id 4650, seq 1
\end{minted}
Στο δεύτερο subnet η source MAC είναι πλέον η MAC του \texttt{r0-eth1}, ενώ η destination MAC είναι η MAC του
\texttt{h3-eth0}.
Ο router έχει επομένως δημιουργήσει νέο Ethernet frame για το επόμενο Layer-2 τμήμα της διαδρομής.
Οι δύο καταγραφές επιτρέπουν την άμεση σύγκριση των πεδίων του ίδιου ICMP Echo Request:
\begin{table}[H]
\centering
\small
\begin{tabularx}{\textwidth}{
>{\raggedright\arraybackslash}p{3.0cm}
>{\raggedright\arraybackslash}X
>{\raggedright\arraybackslash}X
}
\textbf{Πεδίο} & \textbf{Subnet A} & \textbf{Subnet B} \\ \hline
Source IP & \texttt{192.168.1.131} & \texttt{192.168.1.131} \\
Destination IP & \texttt{192.168.2.10} & \texttt{192.168.2.10} \\
Source MAC & \texttt{4a:6f:2a:18:f4:80} (\texttt{h1-eth0}) & \texttt{7e:41:8e:cb:65:05} (\texttt{r0-eth1}) \\
Destination MAC & \texttt{ea:2e:7b:6d:78:82} (\texttt{r0-eth0}) & \texttt{2e:ef:81:65:2c:c9} (\texttt{h3-eth0}) \\
TTL & \texttt{64} & \texttt{63} \\
\end{tabularx}
\caption{Σύγκριση του ICMP Echo Request στα δύο υποδίκτυα.}
\end{table}
Η διαδρομή του Ethernet frame μπορεί επομένως να αποδοθεί συνοπτικά ως:
\begin{minted}{text}
Subnet A ---- → | r0 | ← ---- Subnet Β
h1-eth0 → [r0-eth0 → routing → r0-eth1] → h3-eth0
\end{minted}
Οι IP διευθύνσεις, το ICMP identifier \texttt{4650} και το sequence number \texttt{1} επιβεβαιώνουν ότι οι δύο
καταγραφές αφορούν το \textbf{ίδιο ICMP Echo Request}.
Οι IP διευθύνσεις παραμένουν ίδιες, ενώ οι MAC διευθύνσεις αντικαθίστανται από εκείνες των interfaces που
συμμετέχουν στο εκάστοτε Layer-2 segment.
Παράλληλα, το TTL μειώνεται από \texttt{64} σε \texttt{63}.
Η μεταβολή αυτή αποτελεί άμεση ένδειξη ότι το IP packet προωθήθηκε από έναν router, καθώς το TTL μειώνεται κατά
μία μονάδα σε κάθε Layer-3 hop.
\subsection{Μεταβολή των MAC διευθύνσεων και διατήρηση των IP}
Η διαφορετική συμπεριφορά των IP και MAC διευθύνσεων οφείλεται στο διαφορετικό πεδίο ισχύος των δύο επιπέδων.
Οι IP διευθύνσεις χαρακτηρίζουν τους \textbf{τελικούς endpoints της επικοινωνίας}, ενώ οι MAC διευθύνσεις
χρησιμοποιούνται για την παράδοση ενός Ethernet frame μέσα σε ένα συγκεκριμένο Layer-2 δίκτυο.
Στο Subnet A ο \texttt{h1} δημιουργεί ένα IP packet με source \texttt{192.168.1.131} και destination
\texttt{192.168.2.10}.
Επειδή ο προορισμός βρίσκεται σε διαφορετικό subnet, το packet τοποθετείται σε Ethernet frame με destination
τη MAC του \texttt{r0-eth0}, δηλαδή τη MAC της διεπαφής του gateway που βρίσκεται στο ίδιο subnet με τον
\texttt{h1}.
Ο \texttt{r0} παραλαμβάνει το Ethernet frame από το \texttt{r0-eth0}, αφαιρεί το Layer-2 header και εξετάζει
το IP packet.
Με βάση τον πίνακα δρομολόγησής του επιλέγει ως εξερχόμενη διεπαφή το \texttt{r0-eth1}, μειώνει το TTL κατά μία
μονάδα και δημιουργεί \textbf{νέο Ethernet frame} για το Subnet B.
Στο νέο frame source MAC είναι η MAC του \texttt{r0-eth1} και destination MAC η MAC του \texttt{h3-eth0}.
Η διαδικασία αποτυπώνεται στις πραγματικές τιμές της καταγραφής ως:
\begin{minted}{text}
Subnet A:
4a:6f:2a:18:f4:80 -> ea:2e:7b:6d:78:82
h1-eth0 r0-eth0
IP: 192.168.1.131 -> 192.168.2.10
TTL: 64
Subnet B:
7e:41:8e:cb:65:05 -> 2e:ef:81:65:2c:c9
r0-eth1 h3-eth0
IP: 192.168.1.131 -> 192.168.2.10
TTL: 63
\end{minted}
Επομένως, οι MAC διευθύνσεις έχουν \emph{hop-by-hop} σημασία και αλλάζουν όταν το IP packet προωθείται από τον
δρομολογητή σε διαφορετικό Layer-2 δίκτυο.
Αντίθετα, οι IP διευθύνσεις έχουν \emph{end-to-end} σημασία και παραμένουν ίδιες από τον αρχικό αποστολέα μέχρι
τον τελικό προορισμό, καθώς στην τοπολογία δεν πραγματοποιείται μετάφραση διευθύνσεων NAT.
Η ίδια συμπεριφορά παρατηρείται και στην αντίστροφη κατεύθυνση.
Στο Subnet B το ICMP Echo Reply καταγράφηκε ως:
\begin{minted}{text}
2e:ef:81:65:2c:c9 > 7e:41:8e:cb:65:05
ttl 64
192.168.2.10 > 192.168.1.131
ICMP echo reply, id 4650, seq 1
\end{minted}
Μετά την προώθησή του από τον \texttt{r0}, το ίδιο Reply εμφανίζεται στο Subnet A ως:
\begin{minted}{text}
ea:2e:7b:6d:78:82 > 4a:6f:2a:18:f4:80
ttl 63
192.168.2.10 > 192.168.1.131
ICMP echo reply, id 4650, seq 1
\end{minted}
Η αντίστροφη πορεία επιβεβαιώνει το ίδιο αποτέλεσμα: οι IP διευθύνσεις παραμένουν σταθερές, οι MAC διευθύνσεις
προσαρμόζονται στο εκάστοτε Layer-2 segment και το TTL μειώνεται κατά μία μονάδα κατά τη διέλευση από τον
\texttt{r0}.
\section{Συμπεράσματα}
Στην παρούσα εργασία υλοποιήθηκε ένας γενικός builder δικτυακών τοπολογιών για το Mininet, βασισμένος σε μία
δηλωτική γλώσσα περιγραφής σε JSON.
Η σχεδίαση της DSL βασίστηκε στον διαχωρισμό της επιθυμητής τοπολογίας από τις λεπτομέρειες της εκτέλεσης και
στην αντιστοίχιση των αφαιρέσεων της γλώσσας σε συγκεκριμένες δυνατότητες του Mininet και του Linux.
Η υλοποίηση οργανώθηκε με \textbf{compiler-like αρχιτεκτονική}, στην οποία η αρχική περιγραφή περνά διαδοχικά
από τα στάδια φόρτωσης, parsing, validation, planning και rendering.
Ο διαχωρισμός αυτός επέτρεψε κάθε στάδιο να έχει σαφή ευθύνη, ενώ το \texttt{ExecutionPlan} λειτουργεί ως
πλήρως επιλυμένη ενδιάμεση αναπαράσταση πριν από την παραγωγή του τελικού κώδικα.
Το παραγόμενο \texttt{topology.generated.py} αποτελεί την εκτελέσιμη ``assembly'' της DSL και ταυτόχρονα ένα
ανθρώπινα αναγνώσιμο artifact, το οποίο μπορεί να επιθεωρηθεί ανεξάρτητα πριν από την πραγματική εκτέλεση.
Η τοπολογία της εργασίας δημιουργήθηκε αποκλειστικά από το αντίστοιχο \texttt{topology.json}, χωρίς να απαιτείται
ειδική λογική στον builder για το συγκεκριμένο δίκτυο.
Η ίδια περιγραφή χρησιμοποιήθηκε για την αυτόματη δημιουργία των hosts, switches και links, την παραμετροποίηση
του router και την εκκίνηση της υπηρεσίας DHCP.
Τα τρία πειράματα επέτρεψαν την παρατήρηση της λειτουργίας του δικτύου σε διαφορετικά επίπεδα.
Στο πρώτο πείραμα καταγράφηκε η διαδικασία D.O.R.A. του DHCP και επιβεβαιώθηκε η απόκτηση δυναμικής διεύθυνσης
από τον \texttt{h1}, καθώς και η broadcast φύση του αρχικού DHCP Request.
Στο δεύτερο πείραμα παρατηρήθηκε η επίλυση μιας IPv4 διεύθυνσης σε MAC μέσω ARP, με broadcast Request και
unicast Reply.
Τέλος, στο τρίτο πείραμα καταγράφηκε το ίδιο ICMP Echo Request στις δύο πλευρές του router και επιβεβαιώθηκε
πειραματικά ότι οι IP διευθύνσεις παραμένουν σταθερές end-to-end, ενώ οι MAC διευθύνσεις μεταβάλλονται
hop-by-hop και το TTL μειώνεται κατά μία μονάδα κατά τη δρομολόγηση.
Ιδιαίτερη σημασία είχε το γεγονός ότι οι πραγματικές καταγραφές δεν περιορίστηκαν πάντα στην ελάχιστη
θεωρητική ακολουθία μηνυμάτων.
Στο DHCP, για παράδειγμα, παρατηρήθηκε επαναμετάδοση του Discover πριν από την ολοκλήρωση της διαδικασίας, ενώ
στο ARP εμφανίστηκε επιπλέον ανταλλαγή σχετική με τη διαχείριση του neighbor cache.
Οι παρατηρήσεις αυτές δείχνουν τη διαφορά ανάμεσα στην αφαιρετική περιγραφή ενός πρωτοκόλλου και στη συμπεριφορά
ενός πραγματικού δικτυακού stack.
Συνολικά, η εργασία συνέδεσε δύο διαφορετικά επίπεδα αφαίρεσης: από τη μία τη δηλωτική περιγραφή και αυτόματη
κατασκευή της υποδομής και από την άλλη την παρατήρηση των πραγματικών πακέτων που παράγονται κατά τη λειτουργία
της.
Ο διαχωρισμός αυτός καθιστά τον builder επαναχρησιμοποιήσιμο για διαφορετικές τοπολογίες, ενώ παράλληλα
διατηρεί τη δυνατότητα λεπτομερούς ελέγχου της συμπεριφοράς του δικτύου μέσω των συνηθισμένων εργαλείων Linux.
Η ίδια αρχιτεκτονική μπορεί να επεκταθεί με νέα είδη services, περισσότερες παραμέτρους συνδέσμων ή διαφορετικά
backend-specific settings, χωρίς να απαιτείται αλλαγή της βασικής ροής του builder.
\end{document}