=============================================== Zadanie 3: sterownik urządzenia ZSONet =============================================== Data ogłoszenia: 30.04.2024 Termin oddania: 04.06.2024 (ostateczny 18.06.2024) .. contents:: .. toctree:: :hidden: z3-zsonet Materiały dodatkowe =================== - :ref:`z3-zsonet` - Symulator urządzenia: https://gitlab.uw.edu.pl/zso/2024z/qemu-zsonet.git (branch ``zsonet``) - Do rozwiązania przydatny jest plik zsonet.h z powyższego repozytorium - Obraz maszyny: https://students.mimuw.edu.pl/ZSO/PUBLIC-SO/zso2024_debian12.qcow2.xz - :download:`z3-tst-2024.tar.gz` testy do zadania Wprowadzenie ============ Zadanie polega na napisaniu sterownika do urządzenia ZSONet - prostej karty sieciowej - oraz programu pozwalającego na użycie urządzenia do wysyłania danych do wielu odbiorców z wykorzystaniem io_uring. Urządzenie powinno być dostępne dla użytkownika jako interfejs sieciowy - w szczególności po jego podłączeniu zgodnie z instrukcjami i załadowaniu modułu system powinien mieć dostęp do internetu. Interfejs sterownika ==================== Urządzenie ZSONet powinno implementować następujące operacje, o których przeznaczeniu można przeczytać w dokumentacji struktur ``pci_driver`` i ``net_device_ops``: - ``pci_driver.probe`` - ``pci_driver.remove`` - ``net_device_ops.ndo_open`` - ``net_device_ops.ndo_stop`` - ``net_device_ops.ndo_get_stats64``: powinno udostępniać następujące statystyki: - ``rx_packets`` - ``tx_packets`` - ``rx_bytes`` - ``tx_bytes`` - ``rx_dropped`` - ``tx_dropped`` - ``rx_missed_errors`` - ``net_device_ops.ndo_start_xmit`` Za zadanie można uzyskać do 10 punktów. Na ocenę zadania składają się dwie części: - wynik testów (od 0 do 10 punktów) - ocena kodu rozwiązania (od 0 do -10 punktów) Program io_uring - transmiter ============================= Program ma służyć do wysyłania danych do wielu odbiorców. Program dostaje adresy odbiorców w argumentach w formacie ``:``, a następnie każdą linię z stdin (wraz ze znakiem nowej linii) wysyła po TCP do każdego z odbiorców za pomocą io_uring (liburing). Jeśli wysyłamy dane do n odbiorców, program powinien na każdą linię wykonywac o(n) syscalli --- należy wykorzystać dawaną przez io_uring możliwość przygotowania wielu komend i przekazania ich do wykonania jednym syscallem. Program powinien zakończyć działanie po napotkaniu końca stdin. Program powinien ponownie nawiązywać zerwane połączenia w następujący sposób: jeśli wysyłanie ostatniej linii X do danego odbiorcy się nie powiodło, po odczytaniu następnej linii Y program jednokrotnie próbuje utworzyć socket, połączyć się z tym odbiorcą oraz wysłać do niego linię Y. Jeśli się to uda, dalsza komunikacja z tym odbiorcą przebiega standardowo; w przeciwnym wypadku kolejna próba połączenia powinna nastąpić przy wysyłaniu kolejnej linii Z. Tworzenie socketów, nawiązywanie połączenia, wysyłanie danych oraz zamykanie socketów powinno odbywać się poprzez io_uring. W przypadku błędu przy tworzeniu socketa, nawiązywaniu połączenia, wysyłaniu danych lub zamykaniu socketa program powinien wypisać na stderr następujący komunikat:: : - error: Program powinien w szczególności działać ze sterownikiem ZSONet. Forma rozwiązania ================= Jako rozwiązanie należy dostarczyć paczkę o nazwie ``ab123456.tar.gz`` (gdzie ``ab123456`` jest loginem na students). Po rozpakowaniu paczka powinna tworzyć katalog ``ab123456`` z dwoma podkatalogami: ``zsonet`` i ``transmitter``. Sterownik powinien zostać zrealizowany jako moduł jądra Linux w wersji 6.7.6. Moduł zawierający sterownik powinien nazywać się ``zsonet.ko``. W katalogu ``zsonet`` powinny znajdować się: - źródła modułu - pliki Makefile i Kbuild pozwalające na zbudowanie modułu - krótki opis rozwiązania Transmiter należy napisać w C lub C++. Po kompilacji powinien znajdować się w pliku wykonywalnym o nazwie ``transmitter``. Program powinien kompilować się na dostarczonej maszynie wirtualnej. W katalogu ``transmitter`` powinny znajdować się: - źródła programu - plik Makefile kompilujący rozwiązanie Rozwiązania prosimy nadsyłać na adres ``w.ciszewski@mimuw.edu.pl`` z kopią do ``a.jackowski@mimuw.edu.pl`` oraz ``m.matraszek@mimuw.edu.pl``. Prosimy o umieszczenie ``[ZSO]`` w tytule wiadomości. .. _z3-qemu: QEMU ==== Do użycia urządzenia ZSONet wymagana jest zmodyfikowana wersja qemu, dostępna w wersji źródłowej. Aby skompilować zmodyfikowaną wersję qemu, należy: 1. Sklonować repozytorium https://gitlab.uw.edu.pl/zso/2024z/qemu-zsonet.git 2. ``git checkout zsonet`` 3. Upewnić się, że są zainstalowane zależności: ``ncurses``, ``libsdl``, ``curl``, a w niektórych dystrybucjach także ``ncurses-dev``, ``libsdl-dev``, ``curl-dev`` (nazwy pakietów mogą się nieco różnić w zależności od dystrybucji) 4. Uruchomić ``./configure`` z opcjami wedle uznania (patrz ``./configure --help``). Zalecamy flagi:: --target-list=x86_64-softmmu --enable-virtfs --enable-gtk 5. ``cd build`` 6. Wykonać ``make`` (lub ``ninja``, jeśli mamy zainstalowane) 7. Zainstalować wykonując ``make install``, lub uruchomić bezpośrednio (binarka to ``build/qemu-system-x86_64``). Aby zmodyfikowane qemu emulowało urządzenie ZSONet, należy przekazać mu opcje ``-netdev user,id=net_backend -device zsonet,netdev=net_backend``. Warto ponadto użyć do tego zadania innego obrazu maszyny: https://students.mimuw.edu.pl/ZSO/PUBLIC-SO/zso2024_debian12.qcow2.xz. Na obrazie używanym dotychczas jest zainstalowany Debian 11, w którym dostępna jest stara wersja liburing bez możliwości tworzenia socketów. Wskazówki ========= Ze względu na charakter komunikacji sieciowej interfejs pliku nie pasuje dobrze do urządzeń sieciowych. Z tego powodu w Linuksie dla urządzeń sieciowych nie tworzy się pliku w ``/dev``. Urządzenie sieciowe jest reprezentowane przez strukturę ``net_device``. Następujące funkcje i makra mogą się przydać podczas jego inicjalizacji: - ``alloc_etherdev`` - alokuje strukturę ``net_device`` - ``free_netdev`` - zwalnia strukturę ``net_device`` - ``SET_NETDEV_DEV`` - pozwala powiązać ``net_device`` z fizycznym urządzeniem (``pci_dev.dev``) - ``eth_hw_addr_set`` - ustawia adres MAC - ``register_netdev`` - rejestruje urządzenie sieciowe w systemie - ``unregister_netdev`` - wyrejestrowuje urządzenie sieciowe z systemu - warto też ustawić pola ``min_mtu`` oraz ``max_mtu`` - ``netdev_priv`` - daje dostęp do prywatnych danych sterownika Oprócz tego istotne są funkcje: - ``netif_start_queue`` - informuje system podczas włączania interfejsu, że sterownik może przyjmować ramki do wysyłania - ``netif_stop_queue`` - wstrzymuje przekazywanie do sterownika ramek do wysłania - ``netif_wake_queue`` - wznawia przekazywanie do sterownika ramek do wysłania Podczas wysyłania przydatne mogą być: - ``skb_copy_and_csum_dev`` - wpisuje do bufora dane ze struktury ``sk_buff`` wraz z sumą kontrolną (FCS) - ``dev_kfree_skb_any``, ``dev_consume_skb_any``, ``dev_consume_skb_any_reason`` - zwalnia wykorzystany ``sk_buff`` - do sterownika należy zapewnienie, by wysyłane ramki nie miały rozmiaru mniejszego niż minimalny dla Ethernetu (60 bajtów nie licząc) - mniejsze ramki należy uzupełnić zerami Podczas odbierania przydatne mogą być: - ``netdev_alloc_skb`` - alokuje ``sk_buff`` - ``skb_copy_to_linear_data``, ``skb_copy_to_linear_data_offset`` - wpisuje do ``sk_buff`` dane z bufora (należy tam umieścić również sumę kontrolną) - ``skb_put`` - oznacza obszar ``sk_buff`` zawierający ramkę - należy też uzupełnić pole ``skb.protocol`` używając ``eth_type_trans`` - ``netif_rx`` - przekazuje ramkę do systemu