Implementați, în nucleul Linux, un protocol numit STP (SO2 Transport Protocol) de nivel rețea și transport care funcționează pe bază de datagrame (nu este orientat conexiune și nu deține elemente de control al fluxului).
Protocolul STP are rolul unui protocol de nivel transport (multiplexare pe bază de porturi) dar funcționează la nivelul 3 (Rețea) din stiva OSI, peste nivelul Legătură de Date.
Antetul STP este definit de structura struct stp_header
:
struct stp_header { __be16 dst; __be16 src; __be16 len; __u8 flags; __u8 csum; };
unde
len
este lungimea pachetului în octeți (inclusiv header-ul);dst
și src
sunt porturile destinație, respectiv sursă;flags
conține diverse flag-uri, pe moment nefolosite (marcate reserved);csum
este suma de control (checksum) a întregului pachet incluzând headerul; suma de control este calculată prin SAU exclusiv (XOR) între toți octeții.
Sockeții care folosesc acest protocol vor folosi familia AF_STP
.
Protocolul trebuie să funcționeze direct peste Ethernet. Porturile folosite sunt între 1 si 65535. Portul 0 nu este folosit.
Definiția structurilor și macro-urilor aferente STP se găsesc în header-ul temei.
Modulul de kernel va avea numele af_stp.ko.
Trebuie înregistrată o structură de tip net_proto_family, care să ofere operația de creat sockeți de tip STP. Sockeții proaspăt creați nu sunt asociați cu niciun port și nicio interfață și nu pot primi/trimite pachete. În această funcție, trebuie inițializat câmpul ops al socket-ului cu lista de operații specifice familiei STP. Acest câmp referă o structură proto_ops care trebuie să includă urmatoarele funcții:
release
: eliberează un socket de tip STPbind
: asociază un socket cu un port (eventual și o interfață) pe care se vor primi/trimite pachete:connect
: asociază un socket cu un port și o adresă hardware (adresă MAC) remote către care se vor trimite/dinspre care se vor primi pachete:send
/recv
pe socket în loc de sendmsg
/recvmsg
sau sendto
/recvfrom
sendmsg
, recvmsg
: se trimite, respectiv se primește o datagramă pe un socket STP:poll
: va trebui folosită funcția predefinită datagram_poll
sock_no_*
)static const struct proto_ops stp_ops = { .family = PF_STP, .owner = THIS_MODULE, .release = stp_release, .bind = stp_bind, .connect = stp_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = sock_no_getname, .poll = datagram_poll, .ioctl = sock_no_ioctl, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, .sendmsg = stp_sendmsg, .recvmsg = stp_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, };
Operațiile pe sockeți folosesc un tip de adrese numit sockaddr_stp
, tip definit în header-ul temei. Pentru operația de bind se vor lua în considerare doar portul și indexul interfeței pe care se bind-uiește socketul. Pentru operația de receive se vor completa doar câmpurile addr
și port
din structură cu adresa MAC a host-ului care a trimis pachetul și cu portul de pe care a fost trimis. De asemenea, la trimiterea unui pachet, host-ul destinație se va obține din câmpurile addr
și port
ale acestei structuri.
Trebuie să înregistrați o structură packet_type, folosind apelul dev_add_pack pentru a putea primi pachete STP de pe layer-ul de rețea.
Protocolul va trebui să ofere o interfață prin sistemul de fișiere procfs
pentru statistici despre pachetele trimise/primite. Fișierul trebuie să se numească /proc/net/stp_stats
, specificat prin macro-ul STP_PROC_FULL_FILENAME
din header-ul temei. Formatul trebuie să fie de tip tabel simplu cu 2 rânduri: pe primul rând header-ul tabelului, iar pe al doilea rând statisticile corespunzătoare coloanelor. Coloanele tabelului trebuie să fie, în ordine:
RxPkts HdrErr CsumErr NoSock NoBuffs TxPkts
unde:
RxPkts
- numărul de pachete primiteHdrErr
- numărul de pachete primite cu erori în header (pachete prea scurte sau cu porturi sursă sau destinație 0)CsumErr
- numărul de pachete primite cu erori de checksumNoSock
- numărul de pachete primite pentru care nu s-a găsit un socket destinațieNoBuffs
- numărul de pachete primite care nu au putut fi recepționate pentru că coada de receive a socket-ului era plinăTxPkts
- numărul de pachete trimise
Pentru crearea, respectiv ștergerea intrării precizate de STP_PROC_FULL_FILENAME
recomandăm folosirea funcțiilor proc_create și proc_remove.
Pentru exemple de implementare de protocoale, vă sugerăm în special implementarea de sockeți PF_PACKET și diversele funcții din implementarea UDP sau implementarea IP.
Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea temelor se va face automat cu ajutorul testelor publice care se găsesc în noua infrastructură. Pentru testarea locală folosiți următoarele comezi:
$ git clone https://github.com/linux-kernel-labs/linux.git $ cd linux/tools/labs $ LABS=assignments/4-stp make skels # dezvoltarea temei se va efectua în directorul 4-stp/ $ make build $ make copy $ make boot
Pentru depanarea pachetelor trimise, puteți folosi utilitarul tcpdump
. Testele folosesc interfața de loopback; pentru a urmări pachetele trimise puteți folosi o linie de comandă de forma:
tcpdump -i lo -XX
Puteți folosi o versiune statică de tcpdump. Pentru a o avea în PATH în mașina virtuală, copiați acest fișier în qemu-so2/fsimg/bin
. Creați directorul dacă nu există. Nu uitați să dați fișierului tcpdump permisiuni de execuție:
# În directorul qemu-so2 mkdir fsimg/bin wget http://elf.cs.pub.ro/so2/res/teme/tcpdump -O fsimg/bin/tcpdump chmod 755 fsimg/bin/tcpdump
Pentru a vă mări șansele de a obține nota maximă, citiți și respectați coding style-ul kernelului Linux descris din documentul Coding Style.
De asemenea, folosiți următoarele tool-uri de analiza statică pentru a verifica codul:
/path/to/linux-4.9.11/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/src-file.c
sudo apt-get install sparse
cd /path/to/linux-4.9.11 make C=2 /path/to/your/src-file.c
sudo apt-get install cppcheck
cppcheck /path/to/your/src-file.c
Tema valorează 1.5 puncte.
Depunctările generale pentru teme se găsesc pe pagina de Indicații generale.
În cazuri excepționale (tema trece testele prin nerespectarea cerințelor) și în cazul în care tema nu trece toate testele se poate scădea mai mult decât este menționat mai sus.
Arhiva temei va fi submisă pe vmchecker, în conformitate cu precizările din pagina de reguli.
Din interfața vmchecker alegeți opțiunea Transport protocol
, aferentă acestei teme.
Pentru întrebări legate de temă puteți consulta arhivele listei de discuții sau puteți trimite un e-mail (trebuie să fiți înregistrați). Vă rugăm să urmăriți și să respectați indicațiile de utilizare a listei.