This shows you the differences between two versions of the page.
so2:teme:tema4 [2018/01/05 20:52] adrian.stanciu [Enunț] |
so2:teme:tema4 [2020/05/03 22:28] (current) constantin.ghioc [Tema 4 - Transport protocol] |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | |||
~~NOTOC~~ | ~~NOTOC~~ | ||
- | ====== Tema 4 - Driver de sistem de fișiere ====== | + | ====== Tema 4 - Transport protocol ====== |
- | * Termen de predare: ** TBA ** | + | * Termen de predare: **Duminică, 17 Mai 2020, ora 23:00 ** |
+ | ===== Obiectivele temei ===== | ||
+ | |||
+ | * Dobândirea de cunoștințe legate de funcționarea subsistemului de networking în nucleul Linux. | ||
+ | * Obținerea de deprinderi de lucru cu structurile de bază din subsistemul de networking în Linux. | ||
+ | * Aprofundarea noțiunilor legate de protocoale de comunicație și rețelistică prin implementarea unui protocol într-o stivă de protocoale existentă. | ||
===== Enunț ===== | ===== Enunț ===== | ||
- | Să se scrie un modul de kernel care să implementeze sistemul de fișiere ''PITIX'', versiunea 2. Acest sistem de fișiere va oferi suport doar pentru fișiere și directoare. Nu se vor implementa operațiile de suport pentru link-uri hard sau simbolice. De asemenea, nu se vor implementa operațiile de suport pentru fișiere speciale (pipe-uri, dispozitive caracter sau bloc). Practic va trebui să implementați următoarele operații: | + | 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). |
- | * pentru directoare: ''lookup'', ''unlink'', ''mkdir'', ''rmdir'', ''iterate'' | + | |
- | * pentru fișiere: ''create'', ''truncate'', funcția de bitmap (vezi [[http://lxr.free-electrons.com/source/fs/minix/inode.c?v=4.9#L375| minix_get_block]]) | + | |
- | Restul funcțiilor fie au implementări generice în kernel, fie nu trebuie să le implementați. | + | Protocolul STP are rolul unui protocol de nivel transport (multiplexare pe bază de porturi) dar funcționează la nivelul 3 (Rețea) din [[http://en.wikipedia.org/wiki/OSI_model | stiva OSI]], peste nivelul Legătură de Date. |
- | Structura pe disk a sistemului de fișiere este: | + | Antetul STP este definit de structura ''struct stp_header'': |
- | {{ http://elf.cs.pub.ro/so2/res/teme/pitix-layout.png }} | ||
- | unde: | + | struct stp_header { |
- | * ''Superblock'' conține superblocul (4096 octeți) | + | __be16 dst; |
- | * ''Imap'' conține harta de biți (bitmap) a blocurilor ocupate de inode-uri (1 bloc) | + | __be16 src; |
- | * ''Dmap'' conține harta de biți (bitmap) a blocurilor ocupate de date (1 bloc) | + | __be16 len; |
- | * ''Izone'' conține inode-urile (32 blocuri) | + | __u8 flags; |
- | * ''Dzone'' conține datele (conținutul efectiv al fișierelor) (8*block_size blocuri) | + | __u8 csum; |
+ | }; | ||
- | |||
- | Superblocul (**pe disc**) este descris de următoarea structură: | ||
- | <code cpp> | ||
- | struct pitix_super_block { | ||
- | unsigned long magic; | ||
- | __u8 version; | ||
- | __u8 block_size_bits; | ||
- | __u8 imap_block; | ||
- | __u8 dmap_block; | ||
- | __u8 izone_block; | ||
- | __u8 dzone_block; | ||
- | __u16 bfree; | ||
- | __u16 ffree; | ||
- | }; | ||
- | </code> | ||
unde | 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. | ||
- | * ''magic'' trebuie să fie inițializat cu ''PITIX_MAGIC'' | + | Sockeții care folosesc acest protocol vor folosi familia ''AF_STP''. |
- | * ''version'' trebuie să fie inițializat cu 2 (''PITIX_VERSION'') | + | |
- | * ''block_size_bits'' este dimensiunea blocului în puteri ale lui doi; dimensiunea blocului poate să fie 512, 1024, 2048, sau 4096 | + | |
- | * ''imap_block'' este numărul blocului (relativ la dispozitiv) pentru vectorul de biți folosit pentru alocarea/eliberarea inode-urilor | + | |
- | * ''dmap_block'' este numărul blocului (relativ la dispozitiv) pentru vectorul de biți folosit pentru alocarea/eliberarea blocurilor de date | + | |
- | * ''izone_block'' este numărul primului bloc (relativ la dispozitiv) al zonei de inode-uri | + | |
- | * ''dzone_block'' este numărul primului bloc (relativ la dispozitiv) al zonei de date | + | |
- | * ''bfree'' este numărul de blocuri libere (nealocate) | + | |
- | * ''ffree'' este numărul de inode-uri libere (nealocate) | + | |
- | Inode-urile vor fi stocate în zona de inode-uri și sunt descrise de următoarea structură: | + | Protocolul trebuie să funcționeze direct peste Ethernet. Porturile folosite sunt între 1 si 65535. Portul 0 nu este folosit. |
- | <code cpp> | + | |
- | struct pitix_inode { | + | |
- | __u32 mode; | + | |
- | uid_t uid; | + | |
- | gid_t gid; | + | |
- | __u32 size; | + | |
- | __u32 time; | + | |
- | __u16 direct_data_blocks[INODE_DIRECT_DATA_BLOCKS]; | + | |
- | __u16 indirect_data_block; | + | |
- | }; | + | |
- | </code> | + | |
- | unde | + | Definiția structurilor și macro-urilor aferente STP se găsesc în [[http://elf.cs.pub.ro/so2/res/teme/stp.h | header-ul temei]]. |
- | * ''mode'' reprezintă drepturile de acces și tipul inode-ului (fișier sau director) așa cum sunt reprezentate în kernel | + | ==== Detalii de implementare ==== |
- | * ''uid'' reprezintă UID-ul așa cum este el reprezentat în kernel | + | |
- | * ''gid'' reprezintă GID-ul așa cum este el reprezentat în kernel | + | |
- | * ''size'' reprezintă dimensiunea fișierului/directorului | + | |
- | * ''time'' reprezintă timpul de modificare așa cum este el reprezentat în kernel | + | |
- | * ''direct_data_blocks'' este un vector (de dimensiune ''INODE_DIRECT_DATA_BLOCKS'') ce conține indecșii blocurile de date directe | + | |
- | * ''indirect_data_block'' este indexul unui bloc de date indirect | + | |
- | Indexul unui bloc de date (direct sau indirect) indică numărul acelui bloc de date relativ la zona de date (''Dzone''). | + | Modulul de kernel va avea numele **af_stp.ko**. |
- | Intrările nefolosite trebuie setate pe 0. Primul bloc, cel cu index 0, este tot timpul alocat când se face formatarea. Acest bloc nu va putea fi folosit și, în consecință, valoarea 0 într-un element din vectorul ''direct_data_blocks'' înseamnă bloc liber. | + | |
- | Directoarele au asociate un singur bloc de date în care vor fi stocate intrările de director. Acestea sunt descrise de următoarea structură: | + | Trebuie înregistrată o structură de tip [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L200 | 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 [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L124 | câmpul ops al socket-ului]] cu lista de operații specifice familiei STP. Acest câmp referă o structură [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L136 | proto_ops]] care trebuie să includă urmatoarele funcții: |
- | <code cpp> | + | * ''release'': eliberează un socket de tip STP |
- | struct pitix_dir_entry { | + | * ''bind'': asociază un socket cu un port (eventual și o interfață) pe care se vor primi/trimite pachete: |
- | __u32 ino; | + | * pot exista sockeți bind-uiți doar pe un port (nu și pe o interfață) |
- | char name[PITIX_NAME_LEN]; | + | * sockeții asociați doar cu un port vor putea primi pachetele trimise către acel port pe toate interfețele (analog cu sockeții UDP asociați doar cu un port); acești sockeți nu pot trimite pachete pentru că nu se poate specifica interfața de pe care să fie trimise prin API-ul standard de sockeți |
+ | * nu se pot bind-ui doi sockeți pe aceeași combinație port-interfață: | ||
+ | * dacă există un socket deja bind-uit cu un port și o interfață atunci nu se poate bind-ui un al doilea socket pe același port și aceeași interfață sau fără o interfață specificată | ||
+ | * dacă există un socket deja bind-uit cu un port dar fără o interfață specificată atunci nu se poate bind-ui un al doilea socket pe același port (cu sau fără o interfață specificată) | ||
+ | * recomandăm folosirea unui hash table pentru bind în loc de alte structuri de date (listă, array); în nucleu există o implementare de hash table în [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/hashtable.h | header-ul hashtable.h]] | ||
+ | * ''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: | ||
+ | * acest lucru ar trebui să permită operații de ''send''/''recv'' pe socket în loc de ''sendmsg''/''recvmsg'' sau ''sendto''/''recvfrom'' | ||
+ | * odată conectați cu un host, sockeții nu vor mai accepta pachete decât de la host-ul respectiv | ||
+ | * odată conectați, sockeții nu mai pot fi deconectați | ||
+ | * ''sendmsg'', ''recvmsg'': se trimite, respectiv se primește o datagramă pe un socket STP: | ||
+ | * pentru partea de //receive//, metainformații despre host-ul care a trimis pachetul se pot păstra în [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/skbuff.h#L650 | câmpul cb din sk_buff]] | ||
+ | * ''poll'': va trebui folosită funcția predefinită ''datagram_poll'' | ||
+ | * pentru restul operațiilor vor trebui folosite stub-urile predefinite în kernel (''sock_no_*'') | ||
+ | |||
+ | <code> | ||
+ | |||
+ | 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, | ||
}; | }; | ||
+ | |||
</code> | </code> | ||
+ | Operațiile pe sockeți folosesc un tip de adrese numit ''sockaddr_stp'', tip definit în [[http://elf.cs.pub.ro/so2/res/teme/stp.h | 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. | ||
- | unde | + | Trebuie să înregistrați o structură [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/netdevice.h#L2222 | packet_type]], folosind apelul [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/core/dev.c#L386 | dev_add_pack]] pentru a putea primi pachete STP de pe layer-ul de rețea. |
- | * ''ino'' reprezintă numărul inode-ului fișierului sau directorului; acest număr este un index în zona de inode-uri | + | 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 [[http://elf.cs.pub.ro/so2/res/teme/stp.h | 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:<code> |
- | * ''name'' reprezintă numele fișierului sau al directorului; lungimea maximă a numelui este 16 octeți (''PITIX_NAME_LEN''); dacă lungimea numelui e mai mică decât 16 octeți, atunci numele va fi terminat cu caracterul ASCII ce are codul 0 (la fel ca la șirurile de caractere) | + | RxPkts HdrErr CsumErr NoSock NoBuffs TxPkts |
+ | </code> | ||
+ | unde: | ||
+ | * ''RxPkts'' - numărul de pachete primite | ||
+ | * ''HdrErr'' - 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 checksum | ||
+ | * ''NoSock'' - numărul de pachete primite pentru care nu s-a găsit un socket destinație | ||
+ | * ''NoBuffs'' - 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 [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/proc_fs.h#L30 | proc_create]] și [[http://elixir.free-electrons.com/linux/v4.9.11/source/fs/proc/generic.c#L636 | proc_remove]]. | ||
- | Toate valorile numerice sunt stocate pe disc în CPU byte-order. | + | ===== Exemple de implementări de protocoale ===== |
- | Directorul rădăcină va avea alocat inode-ul 0 și blocul de date 0. | + | Pentru exemple de implementare de protocoale, vă sugerăm în special implementarea de sockeți [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/packet/af_packet.c | PF_PACKET]] și diversele funcții din [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/udp.c| implementarea UDP]] sau [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/af_inet.c | implementarea IP]]. |
- | Pentru simplificare, la ''mkdir'' nu este necesară crearea intrărilor ''.'' (dot) și ''..'' (dot dot) în noul director; checker-ul se folosește de această presupunere. | + | ===== Testare ===== |
+ | /* | ||
+ | Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea temelor se va face automat cu ajutorul unor [[http://elf.cs.pub.ro/so2/res/teme/5-stp.zip| teste publice]]. | ||
+ | Indicații despre utilizarea suitei de teste se găsesc în fișierul ''README'' din cadrul arhivei. | ||
+ | */ | ||
+ | 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: | ||
+ | <code bash> | ||
+ | $ 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 | ||
+ | </code> | ||
- | În [[http://elf.cs.pub.ro/so2/res/teme/pitix.h| header-ul temei]] găsiți structurile descrise anterior împreună cu unele macro-uri utile și declarațiile principalelor funcții de implementat. | ||
- | Modulul de kernel va avea numele **pitix.ko**. | + | ==== tcpdump ==== |
- | ===== Testare ===== | + | 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:<code> |
+ | tcpdump -i lo -XX | ||
+ | </code> | ||
- | Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea temelor se va face automat cu ajutorul unor [[http://elf.cs.pub.ro/so2/res/teme/4-pitix.zip|teste publice]]. Indicații despre utilizarea suitei de teste se găsesc în fișierul ''README'' din cadrul arhivei. | + | Puteți folosi o versiune statică de [[http://elf.cs.pub.ro/so2/res/teme/tcpdump | 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:<code> |
+ | # Î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 | ||
+ | </code> | ||
==== Sfaturi ==== | ==== Sfaturi ==== | ||
Line 126: | Line 158: | ||
==== Notare ==== | ==== Notare ==== | ||
- | Datorită nivelului de dificultate mai ridicat, tema valorează două puncte. | + | Tema valorează 1.5 puncte. |
==== Depunctări ==== | ==== Depunctări ==== | ||
Line 138: | Line 170: | ||
Arhiva temei va fi submisă pe vmchecker, în conformitate cu [[:so2:reguli-notare#reguli_de_trimitere_a_temelor|precizările din pagina de reguli]]. | Arhiva temei va fi submisă pe vmchecker, în conformitate cu [[:so2:reguli-notare#reguli_de_trimitere_a_temelor|precizările din pagina de reguli]]. | ||
- | Din interfața vmchecker alegeți opțiunea ''Sistem de fișiere'', aferentă acestei teme. | + | Din interfața vmchecker alegeți opțiunea ''Transport protocol'', aferentă acestei teme. |
===== Resurse ===== | ===== Resurse ===== | ||
- | * [[http://elf.cs.pub.ro/so2/res/teme/pitix.h| header-ul temei]] | + | * Cursuri |
- | * [[so2:laboratoare:lab08|Laboratorul 8. Drivere sisteme de fișiere (partea întăi)]] | + | * [[http://ocw.cs.pub.ro/so2/cursuri/curs10 | Curs 10 - Gestiunea rețelei]] |
- | * [[so2:laboratoare:lab09|Laboratorul 9. Drivere sisteme de fișiere (partea a doua)]] | + | * Laboratoare |
- | * [[http://lxr.free-electrons.com/source/fs/minix/?v=4.9|Sursele sistemului de fișiere Minix]] | + | * [[http://ocw.cs.pub.ro/so2/laboratoare/lab10 | Laborator 10 - Networking]] |
+ | * Sursele nucleului Linux | ||
+ | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/packet/af_packet.c | Implementarea sockeților PF_PACKET]] | ||
+ | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/udp.c | Implementarea protocolului UDP]] | ||
+ | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/af_inet.c | Implementarea protocolului IP]] | ||
+ | * Understanding Linux Network Internals | ||
+ | * capitolele 8-13 | ||
+ | * [[http://elf.cs.pub.ro/so2/res/teme/stp.h | Header-ul temei]] | ||
<note important> | <note important> | ||
- | Resursele temei ([[https://github.com/systems-cs-pub-ro/so2-assignments/tree/master/4-pitix-v2|4-pitix-v2]]) se găsesc și în repo-ul [[https://github.com/systems-cs-pub-ro/so2-assignments|so2-assignments]] de pe GitHub. Repo-ul conține și un [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh|script Bash]] care vă ajută să vă creați un repository privat pe instanța de [[https://gitlab.cs.pub.ro|GitLab]] a facultății. Urmăriți indicațiile din [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md|README]] și de pe [[:so2:teme:folosire-gitlab| pagina de Wiki dedicată pentru git]]. | + | Resursele temei se găsesc și în repo-ul [[https://github.com/systems-cs-pub-ro/so2-assignments|so2-assignments]] de pe GitHub. Repo-ul conține și un [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh|script Bash]] care vă ajută să vă creați un repository privat pe instanța de [[https://gitlab.cs.pub.ro|GitLab]] a facultății. Urmăriți indicațiile din [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md|README]] și de pe [[:so2:teme:folosire-gitlab| pagina de Wiki dedicată pentru git]]. |
</note> | </note> | ||
- | |||
===== Întrebări ===== | ===== Întrebări ===== | ||
- | |||
Pentru întrebări legate de temă puteți consulta [[http://cursuri.cs.pub.ro/pipermail/so2/ | arhivele]] listei de discuții sau puteți trimite un [[so2@cursuri.cs.pub.ro |e-mail]] (trebuie să fiți [[http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2 | înregistrați]]). | Pentru întrebări legate de temă puteți consulta [[http://cursuri.cs.pub.ro/pipermail/so2/ | arhivele]] listei de discuții sau puteți trimite un [[so2@cursuri.cs.pub.ro |e-mail]] (trebuie să fiți [[http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2 | înregistrați]]). | ||
- | |||
Vă rugăm să urmăriți și să respectați [[http://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines | indicațiile de utilizare a listei]]. | Vă rugăm să urmăriți și să respectați [[http://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines | indicațiile de utilizare a listei]]. | ||
- |