Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00745 010216 10704482 na godz. na dobę w sumie
Linux. Mechanizmy sieciowe - książka
Linux. Mechanizmy sieciowe - książka
Autor: Liczba stron: 1000
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-0462-6 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> systemy operacyjne >> linux
Porównaj ceny (książka, ebook, audiobook).

Kompletny przewodnik po mechanizmach sieciowych Linuksa

Sieci, a szczególnie internet, to jeden z filarów współczesnej informatyki. Niemal każdy elektroniczny gadżet może pracować w sieci za pośrednictwem różnych metod komunikacji. Ogromna ilość produkowanych dziś urządzeń sieciowych opiera się na różnych dystrybucjach systemu operacyjnego Linux. Ten dostępny nieodpłatnie system operacyjny od początku tworzony był z uwzględnieniem roli, jaką mógłby odgrywać w świecie sieci komputerowych, więc zaimplementowano w nim niemal wszystkie możliwe mechanizmy sieciowe. Dodatkowo filozofia, jaką przyjęto przy rozwoju tego systemu operacyjnego, pozwala wszystkim jego użytkownikom na dodawanie do jądra Linuksa własnych modułów zapewniających obsługę niestandardowych urządzeń i protokołów.

Książka 'Linux. Mechanizmy sieciowe' to szczegółowe omówienie rozwiązań sieciowych, jakie zostały zastosowane w tym systemie operacyjnym. Opisuje sposoby, w jakie jądro Linuksa realizuje zadania przydzielane mu przez protokoły IP. Czytając ją, można poznać współczesną łączność sieciową na wziętych z życia przykładach. Pozycja ta jest doskonałym przewodnikiem po kodzie źródłowym funkcji sieciowych jądra systemu Linux. Przedstawia kod w języku C z obszernymi komentarzami i wyjaśnieniami zastosowanych mechanizmów.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREœCI SPIS TREœCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOœCIACH O NOWOœCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Koœciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl Linux. Mechanizmy sieciowe Autor: Christian Benvenuti T³umaczenie: Jaromir Senczyk, Grzegorz Werner ISBN: 83-246-0462-6 Tytu³ orygina³u: Understanding Linux Network Internals Format: B5, stron: 1000 Kompletny przewodnik po mechanizmach sieciowych Linuksa (cid:129) Inicjalizacja urz¹dzeñ sieciowych. (cid:129) Interfejsy pomiêdzy urz¹dzeniami i protoko³ami. (cid:129) Rozwi¹zania specyficzne dla protoko³ów. Sieci, a szczególnie internet, to jeden z filarów wspó³czesnej informatyki. Niemal ka¿dy elektroniczny gad¿et mo¿e pracowaæ w sieci za poœrednictwem ró¿nych metod komunikacji. Ogromna iloœæ produkowanych dziœ urz¹dzeñ sieciowych opiera siê na ró¿nych dystrybucjach systemu operacyjnego Linux. Ten dostêpny nieodp³atnie system operacyjny od pocz¹tku tworzony by³ z uwzglêdnieniem roli, jak¹ móg³by odgrywaæ w œwiecie sieci komputerowych, wiêc zaimplementowano w nim niemal wszystkie mo¿liwe mechanizmy sieciowe. Dodatkowo filozofia, jak¹ przyjêto przy rozwoju tego systemu operacyjnego, pozwala wszystkim jego u¿ytkownikom na dodawanie do j¹dra Linuksa w³asnych modu³ów zapewniaj¹cych obs³ugê niestandardowych urz¹dzeñ i protoko³ów. Ksi¹¿ka „Linux. Mechanizmy sieciowe” to szczegó³owe omówienie rozwi¹zañ sieciowych, jakie zosta³y zastosowane w tym systemie operacyjnym. Opisuje sposoby, w jakie j¹dro Linuksa realizuje zadania przydzielane mu przez protoko³y IP. Czytaj¹c j¹, mo¿na poznaæ wspó³czesn¹ ³¹cznoœæ sieciow¹ na wziêtych z ¿ycia przyk³adach. Pozycja ta jest doskona³ym przewodnikiem po kodzie Ÿród³owym funkcji sieciowych j¹dra systemu Linux. Przedstawia kod w jêzyku C z obszernymi komentarzami i wyjaœnieniami zastosowanych mechanizmów. (cid:129) Struktury danych (cid:129) Rejestracja i inicjalizowanie urz¹dzeñ sieciowych (cid:129) Powiadamianie j¹dra o odbiorze ramki (cid:129) Obs³uga protoko³ów (cid:129) Implementacja mostkowania (cid:129) Obs³uga IPv4 (cid:129) Podsystem s¹siedztwa (cid:129) Routing Wstęp ........................................................................................................................................13 Część I Podstawy 21 1. Wprowadzenie ............................................................................................................. 23 23 24 36 37 38 Podstawowa terminologia Typowe wzorce kodowania Narzędzia dostępne w przestrzeni użytkownika Przeglądanie kodu źródłowego Opcje oferowane w postaci łat 2. Najważniejsze struktury danych ................................................................................. 41 41 60 73 Bufor gniazda: struktura sk_buff Struktura net_device Pliki występujące w tym rozdziale 3. Interfejs użytkownik – jądro ........................................................................................ 75 Informacje ogólne 75 77 procfs kontra sysctl 84 Interfejs ioctl 86 Netlink Serializacja zmian konfiguracji 87 Część II Inicjalizacja systemu 89 4. Łańcuchy powiadomień ............................................................................................... 91 91 93 93 94 Przyczyny wprowadzenia łańcuchów powiadomień Informacje ogólne Definiowanie łańcucha Rejestracja w łańcuchu 3 Powiadamianie o zdarzeniach Łańcuchy powiadomień w podsystemach sieciowych Strojenie za pośrednictwem systemu plików /proc Funkcje i zmienne występujące w tym rozdziale Pliki i katalogi występujące w tym rozdziale 95 96 97 97 98 5. Inicjalizacja urządzeń sieciowych ............................................................................... 99 99 Ogólne informacje na temat inicjalizacji systemu 101 Rejestracja i inicjalizacja urządzeń 101 Podstawowe cele inicjalizacji kart sieciowych Interakcje pomiędzy urządzeniami i jądrem 102 107 Opcje inicjalizacji 108 Opcje modułów 109 Inicjalizacja warstwy obsługi urządzeń: net_dev_init Kod pomocniczy w przestrzeni użytkownika 111 114 Urządzenia wirtualne 117 Strojenie za pośrednictwem systemu plików /proc Funkcje i zmienne występujące w tym rozdziale 118 118 Pliki i katalogi występujące w tym rozdziale 6. Warstwa PCI i karty sieciowe ..................................................................................... 119 119 121 122 123 125 125 127 127 Struktury danych występujące w tym rozdziale Rejestracja sterownika karty sieciowej PCI Zarządzanie zasilaniem i Wake-on-LAN Przykład rejestracji sterownika karty sieciowej PCI Ogólny schemat Strojenie za pośrednictwem systemu plików /proc Funkcje i zmienne występujące w tym rozdziale Pliki i katalogi występujące w tym rozdziale 7. Infrastruktura jądra związana z inicjacją komponentów ........................................ 129 129 Opcje uruchamiania jądra Kod inicjacji modułu 135 138 Optymalizacja etykiet opartych na makrach 140 Procedury inicjacji wykonywane podczas uruchamiania systemu 142 Optymalizacja pamięci Strojenie za pośrednictwem systemu plików /proc 146 146 Funkcje i zmienne występujące w tym rozdziale Pliki i katalogi występujące w tym rozdziale 147 4 | Spis treści 8. Rejestracja i inicjacja urządzeń .................................................................................. 149 150 151 151 152 154 158 160 162 166 168 172 173 177 180 182 183 183 184 Kiedy urządzenie zostaje zarejestrowane Kiedy urządzenie zostaje wyrejestrowane Przydział struktur net_device Szkielet zarejestrowania i wyrejestrowania karty sieciowej Inicjacja urządzenia Organizacja struktur net_device Stan urządzenia Rejestrowanie i wyrejestrowywanie urządzeń Rejestracja urządzenia Wyrejestrowanie urządzenia Włączanie i wyłączanie urządzenia sieciowego Aktualizacja stanu reguły kolejkowania Konfigurowanie urządzeń z przestrzeni użytkownika Urządzenia wirtualne Blokowanie Strojenie za pośrednictwem systemu plików /proc Funkcje i zmienne występujące w tym rozdziale Pliki i katalogi występujące w tym rozdziale Część III Wysyłanie i odbieranie 185 9. Przerwania i sterowniki sieciowe ..............................................................................187 187 189 192 213 Decyzje i kierunki ruchu Powiadamianie sterownika o odebraniu ramki Procedury obsługi przerwań Struktura danych softnet_data 10. Odbiór ramki ................................................................................................................217 218 Interakcje z innymi opcjami 218 Włączanie i wyłączanie urządzenia 219 Kolejki 219 Powiadamianie jądra o odbiorze ramki: NAPI i netif_rx Stary interfejs pomiędzy sterownikami urządzeń i jądrem: pierwsza część netif_rx 225 231 Zarządzanie obciążeniem Obsługa przerwania NET_RX_SOFTIRQ: net_rx_action 234 11. Wysyłanie ramki .........................................................................................................245 247 Włączanie i wyłączanie wysyłania Spis treści | 5 12. Informacje o przerwaniach ........................................................................................ 265 265 Dane statystyczne Strojenie za pośrednictwem systemów plików /proc i sysfs 266 267 Funkcje i zmienne występujące w tej części książki Pliki i katalogi występujące w tej części książki 268 13. Procedury obsługi protokołów ...................................................................................271 271 279 283 284 286 296 297 297 Przegląd stosu protokołowego Wykonanie odpowiedniej procedury obsługi protokołu Organizacja procedur obsługi protokołów Rejestracja procedury obsługi protokołu Ethernet i ramki IEEE 802.3 Strojenie za pośrednictwem systemu plików /proc Funkcje i zmienne występujące w tym rozdziale Pliki i katalogi występujące w tym rozdziale Część IV Mostkowanie 299 14. Mostkowanie: podstawowe koncepcje .................................................................... 301 301 303 304 304 305 306 308 Wtórniki, mosty i routery Mosty i przełączniki Hosty Łączenie sieci lokalnych za pomocą mostów Mostkowanie różnych technologii sieci lokalnych Uczenie się adresów Sieci z wieloma mostami 15. Mostkowanie: protokół drzewa częściowego .......................................................... 315 316 316 320 325 327 332 339 344 348 348 351 353 354 Podstawowa terminologia Przykład hierarchicznej topologii L2 zawierającej mosty Podstawowe elementy protokołu Spanning Tree Protocol Identyfikatory portów i mostów Ramki BPDU Definiowanie aktywnej topologii Liczniki czasu Zmiany topologii Kapsułkowanie ramek BPDU Wysyłanie konfiguracyjnych ramek BPDU Przetwarzanie ramek wejściowych Czas konwergencji Przegląd nowych wersji protokołu STP 6 | Spis treści 16. Mostkowanie: implementacja w Linuksie ................................................................359 359 362 364 365 365 366 367 367 370 370 371 373 373 375 378 382 383 390 Abstrakcja urządzenia mostkującego Ważne struktury danych Inicjalizacja kodu mostkowania Tworzenie urządzeń i portów mostkujących Tworzenie nowego urządzenia mostkującego Procedura inicjalizacyjna urządzenia mostkującego Usuwanie mostu Dodawanie portów do mostu Usuwanie portu mostu Włączanie i wyłączanie urządzenia mostkującego Włączanie i wyłączanie portu mostu Zmiana stanu portu Panorama Baza przekazywania Obsługa ruchu wejściowego Wysyłanie danych z urządzenia mostkującego Spanning Tree Protocol (STP) Łańcuch powiadomień netdevice 17. Mostkowanie: zagadnienia różne .............................................................................393 393 398 398 399 400 404 405 Narzędzia konfiguracyjne działające w przestrzeni użytkownika Dostrajanie za pomocą systemu plików /proc Dostrajanie za pomocą systemu plików /sys Statystyka Struktury danych przedstawione w tej części książki Funkcje i zmienne przedstawione w tej części książki Pliki i katalogi przedstawione w tej części książki Część V Internet Protocol Version 4 (IPv4) 407 18. Internet Protocol Version 4 (IPv4): pojęcia ...............................................................409 Protokół IP: panorama 409 411 Nagłówek IP 414 Opcje IP 420 Fragmentacja i defragmentacja pakietów Sumy kontrolne 430 19. Internet Protocol Version 4 (IPv4): funkcje i cechy jądra Linuksa ........................... 437 437 Główne struktury danych IPv4 Ogólna obsługa pakietów 441 450 Opcje IP Spis treści | 7 20. Internet Protocol Version 4 (IPv4): przekazywanie i lokalne dostarczanie ........... 461 461 Przekazywanie Dostarczanie lokalne 466 21. Internet Protocol Version 4 (IPv4): transmisja .........................................................469 470 Kluczowe funkcje transmisyjne Interfejs do podsystemu sąsiedztwa 504 22. Internet Protocol Version 4 (IPv4): obsługa fragmentacji .......................................505 506 Fragmentacja IP Defragmentacja IP 514 23. Internet Protocol Version 4 (IPv4): zagadnienia różne ............................................ 527 527 Długo przechowywane informacje o partnerze IP Wybór wartości identyfikatora w nagłówku IP 531 532 Statystyka IP 535 Konfiguracja IP 540 IP-over-IP Protokół IPv4: co z nim jest nie tak? 541 542 Dostrajanie za pomocą systemu plików /proc 545 Struktury danych opisywane w tej części książki Funkcje i zmienne wspomniane w tej części książki 554 556 Pliki i katalogi wspomniane w tej części książki 24. Protokół warstwy czwartej i obsługa Raw IP ........................................................... 557 557 558 562 569 569 570 570 Dostępne protokoły L4 Rejestracja protokołu L4 Dostarczanie danych L3 do L4: ip_local_deliver_finish IPv4 a IPv6 Dostrajanie za pomocą systemu plików /proc Funkcje i zmienne przedstawione w tym rozdziale Pliki i katalogi przedstawione w tym rozdziale 25. Internet Control Message Protocol (ICMPv4) ............................................................571 572 Nagłówek ICMP 573 Treść ICMP Typy komunikatów ICMP 574 580 Zastosowania protokołu ICMP 583 Panorama 584 Inicjalizacja protokołu Struktury danych opisywane w tym rozdziale 585 587 Wysyłanie komunikatów ICMP 8 | Spis treści Odbieranie komunikatów ICMP Statystyka ICMP Przekazywanie powiadomień o błędach do warstwy transportu Dostrajanie za pomocą systemu plików /proc Funkcje i zmienne przedstawione w tym rozdziale Pliki i katalogi przedstawione w tym rozdziale Część VI Podsystem sąsiedztwa 594 601 603 604 605 605 607 26. Podsystem sąsiedztwa: pojęcia .................................................................................609 609 612 617 619 622 625 Co to jest sąsiad? Do czego potrzebne są protokoły sąsiedztwa? Implementacja w Linuksie Pośredniczenie w protokole sąsiedztwa Wysyłanie i przetwarzanie żądań odwzorowania adresu Stany sąsiadów i wykrywanie nieosiągalności sieci 27. Podsystem sąsiedztwa: infrastruktura .....................................................................633 633 636 646 650 651 653 658 662 666 667 670 671 Główne struktury danych Wspólny interfejs między protokołami L3 a protokołami sąsiedztwa Ogólne zadania infrastruktury sąsiedztwa Liczniki referencji do struktur neighbour Tworzenie wpisu sąsiada Usuwanie sąsiada Działanie w charakterze pośrednika Buforowanie nagłówków L2 Inicjalizacja i finalizacja protokołu Interakcja z innymi podsystemami Interakcja między protokołami sąsiedztwa a funkcjami transmisyjnymi L3 Kolejkowanie 28. Podsystem sąsiedztwa: Address Resolution Protocol (ARP) ................................... 677 678 680 681 683 685 691 693 698 703 710 Format pakietu ARP Przykład transakcji ARP Spontaniczny ARP Odpowiedzi z wielu interfejsów Konfigurowalne opcje ARP Inicjalizacja protokołu ARP Inicjalizacja struktury neighbour Wysyłanie i odbieranie pakietów ARP Przetwarzanie wejściowych pakietów ARP Pośredniczenie ARP Spis treści | 9 Przykłady Zdarzenia zewnętrzne ARPD Reverse Address Resolution Protocol (RARP) Ulepszenia w ND (IPv6) w stosunku do ARP (IPv4) 715 717 719 722 722 29. Podsystem sąsiedztwa: zagadnienia różne .............................................................. 723 723 726 731 744 745 Zarządzanie sąsiadami przez administratora systemu Dostrajanie za pomocą systemu plików /proc Struktury danych przedstawione w tej części książki Funkcje i zmienne przedstawione w tej części książki Pliki i katalogi przedstawione w tej części książki Część VII Routing 747 30. Routing: pojęcia .......................................................................................................... 749 750 754 764 768 770 Routery, trasy i tablice tras Podstawowe elementy routingu Tablica tras Wyszukiwania Odbieranie pakietów a wysyłanie pakietów 31. Routing: zagadnienia zaawansowane ..................................................................... 773 773 778 784 789 791 791 796 Zasady routingu opartego na polityce Zasady routingu wielościeżkowego Interakcje z innymi podsystemami jądra Demony protokołów routingu Szczegółowe monitorowanie Komunikaty ICMP_REDIRECT Filtrowanie ścieżek odwrotnych 32. Routing: implementacja w Linuksie .......................................................................... 799 799 802 806 808 809 811 811 813 824 Opcje jądra Główne struktury danych Zasięgi tras i adresów Podstawowe i wtórne adresy IP Uniwersalne procedury pomocnicze i makra Globalne blokady Inicjalizacja podsystemu routingu Zdarzenia zewnętrzne Interakcje z innymi podsystemami 10 | Spis treści 33. Routing: bufor tras ..................................................................................................... 827 827 828 829 838 843 849 850 860 Inicjalizacja bufora tras Organizacja tablicy tras Podstawowe operacje na buforze Buforowanie wielościeżkowe Interfejs między DST a wywołującymi protokołami Opróżnianie bufora tras Odśmiecanie Ograniczanie częstotliwości wyjściowych komunikatów ICMP 34. Routing: tablice tras ................................................................................................... 861 861 867 868 873 Organizacja tablic mieszających w podsystemie routingu Inicjalizacja tablicy tras Dodawanie i usuwanie tras Routing oparty na polityce i jego wpływ na definicje tablic tras 35. Routing: wyszukiwania ............................................................................................. 875 875 876 877 882 882 885 887 895 902 905 908 909 Panorama funkcji wyszukiwawczych Procedury pomocnicze Przeszukiwanie tablicy: fn_hash_lookup Funkcja fib_lookup Ustawianie funkcji odbiorczych i transmisyjnych Ogólna struktura procedur routingu wejściowego i wyjściowego Routing wejściowy Routing wyjściowy Wpływ routingu wielościeżkowego na wybór następnego przeskoku Routing oparty na polityce Routing źródłowy Routing oparty na polityce i klasyfikator oparty na tablicy tras 36. Routing: zagadnienia różne ....................................................................................... 913 913 919 919 926 928 944 946 Narzędzia konfiguracyjne działające w przestrzeni użytkownika Statystyka Dostrajanie za pomocą systemu plików /proc Włączanie i wyłączanie przekazywania Struktury danych przedstawione w tej części książki Funkcje i zmienne przedstawione w tej części książki Pliki i katalogi przedstawione w tej części książki Skorowidz ...................................................................................................................949 Spis treści | 11 ROZDZIAŁ 5. Elastyczność współczesnych systemów operacyjnych komplikuje proces inicjalizacji. Sterownik urządzenia może zostać załadowany jako moduł lub statyczny komponent jądra. Co więcej, urządzenia mogą być obecne podczas uruchamiania systemu albo podłączane (i odłączane) w czasie jego pracy. Do tych ostatnich należą między innymi urządzenia USB, PCI CardBus, IEEE 1394 (przez Apple zwane również FireWire). W tym rozdziale pokażę, w jaki sposób możliwość podłączania urządzeń w czasie pracy systemu wpływa na działanie kodu jądra i przestrzeni użytkownika. W rozdziale omawiam: · · · · · · fragmentu kodu sieciowego odpowiedzialnego za jego inicjalizację; inicjalizację karty sieciowej; sposób wykorzystania przerwań przez karty sieciowe, sposób przydzielania i zwalniania procedur obsługi przerwań, a także możliwość współdzielenia przerwań przez sterowniki urządzeń; sposób określania przez użytkownika parametrów konfiguracyjnych sterowników urzą- dzeń ładowanych jako moduły; interakcję pomiędzy przestrzenią użytkownika i jądrem podczas inicjalizacji i konfiguracji urządzeń. Pokażę, w jaki sposób jądro może użyć pomocniczego kodu działającego w prze- strzeni użytkownika w celu załadowania właściwego sterownika karty sieciowej lub za- stosowania konfiguracji pochodzącej z przestrzeni użytkownika. W szczególności zajmę się też opcją Hotplug; różnice pomiędzy wirtualnymi i rzeczywistymi urządzeniami w odniesieniu do ich kon- figuracji i interakcji z jądrem. Ogólne informacje na temat inicjalizacji systemu Ważne jest, aby wiedzieć dokładnie, gdzie i kiedy następuje inicjalizacja głównych podsys- temów związanych z działaniem sieci, włączając w to sterowniki urządzeń. Ponieważ jednak w zakresie tematycznym tej książki leży jedynie sieciowy aspekt inicjalizacji, to nie będziemy się zajmować ogólnym przypadkiem inicjalizacji sterowników urządzeń czy ogólnymi usłu- gami jądra (np. zarządzaniem pamięcią). Zagadnieniom tym poświęcone są książki Linux Device Drivers i Understanding the Linux Kernel, obie wydane przez O’Reilly. 99 Rysunek 5.1 przedstawia w skrócie, gdzie i w jakiej kolejności zostają zainicjowane niektóre z podsystemów jądra podczas uruchamiania systemu (init/main.c). Rysunek 5.1. Inicjalizacja jądra Podczas uruchamiania jądro wywołuje funkcję start_kernel inicjującą wiele podsystemów, z których część została przedstawiona na rysunku 5.1. Zanim funkcja start_kernel zakończy swoje działanie, wywołuje najpierw wątek init jądra, który zajmuje się resztą inicjalizacji. Większość akcji związanych z inicjalizacją omawianą w tym rozdziale wykonywanych jest przez funkcję do_basic_setup. Spośród wielu różnych zadań związanych z inicjalizacją najbardziej będą nas interesować na- stępujące trzy: Opcje uruchamiania Dwa wywołania funkcji parse_args, jedno bezpośrednie, a drugie pośrednie przez funk- cję parse_early_param, obsługują parametry konfiguracyjne przekazane jądru podczas uruchamiania przez procedurę startu LILO lub GRUB. Sposób tej obsługi przedstawiono w podrozdziale „Opcje uruchamiania jądra”. Przerwania i liczniki czasu Przerwania sprzętowe i programowe są inicjowane za pomocą funkcji odpowiednio: init_IRQ i softirq_init. Przerwania zostaną omówione w rozdziale 9. W tym rozdziale pokażę, w jaki sposób sterownik urządzenia rejestruje procedurę obsługi przerwania i w jaki sposób procedury takie są zorganizowane w pamięci. Liczniki czasu zostają zainicjowane we wczesnej fazie uruchamiania systemu, aby mogły zostać użyte przez inne zadania. Procedury inicjalizacji Podsystemy jądra oraz wbudowane sterowniki urządzeń są inicjowane przez do_initcalls. Funkcja free_init_mem zwalnia fragment pamięci, który zawiera niepotrzebny kod. Opty- malizacja taka jest możliwa dzięki zastosowaniu inteligentnych etykiet procedur. Więcej informacji na ten temat w rozdziale 7. Procedura run_init_process określa pierwszy proces wykonywany w systemie, będący procesem nadrzędnym wszystkich innych procesów. Proces ten otrzymuje identyfikator PID równy 1 i działa tak długo jak system. Zwykle wykonuje on program init będący częścią pakietu SysVinit. Administrator może jednak podać inny program, używając opcji startowej init=. Jeśli opcja taka nie zostanie podana, to jądro próbuje wykonać polecenie init, korzystając ze zbioru znanych lokalizacji tego programu. Użytkownik może również podać opcje przekazywane programowi init podczas uruchamiania systemu (podrozdział „Opcje uruchamiania jądra”). 100 | Rozdział 5. Inicjalizacja urządzeń sieciowych Rejestracja i inicjalizacja urządzeń Aby urządzenie sieciowe mogło być używane, musi najpierw być rozpoznane przez jądro i związane z odpowiednim sterownikiem. Sterownik ten przechowuje w swoich prywatnych strukturach wszystkie informacje potrzebne do sterowania urządzeniem oraz do interakcji z innymi komponentami jądra, które żądają urządzenia. Zadania rejestracji i inicjalizacji wy- konywane są częściowo przez podstawową część jądra i częściowo przez sterownik urządzenia. A oto kolejne fazy inicjalizacji: Inicjalizacja sprzętowa Wykonywana jest przez sterownik urządzenia we współpracy z warstwą magistrali (PCI lub USB). Sterownik, czasami samodzielnie, a innym razem za pomocą parametrów do- starczonych przez użytkownika, konfiguruje przerwanie oraz adres wejścia i wyjścia po- zwalające na komunikację z jądrem. Ponieważ ta część inicjalizacji jest bardziej związana z samym sterownikiem urządzenia niż warstwami protokołowymi, nie będziemy poświęcać jej zbyt wiele uwagi. Ograniczę się do przedstawienia jednego przykładu dla warstwy PCI. Inicjalizacja programowa Zanim urządzenia będzie można użyć, konfiguracja protokołów może wymagać od użyt- kownika dostarczenia dodatkowych parametrów konfiguracyjnych, takich jak na przykład adres IP. Zadanie to zostanie omówione w innych rozdziałach. Inicjalizacja opcji sieciowych Jądro systemu Linux dostarczane jest z wieloma różnymi opcjami sieciowymi. Ponieważ niektóre z tych opcji wymagają konfiguracji dla poszczególnych urządzeń, to ich istnienie musi zostać uwzględnione podczas inicjalizacji urządzenia. Przykładem może być opcja Traffic Control będąca podsystemem implementującym usługę QoS (Quality of Service) decydującą o sposobie umieszczania i usuwania pakietów w kolejce wyjściowej urządzenia (i z pewnymi ograniczeniami podobnie dla kolejki wejściowej). W rozdziale 2. pokazano już, że struktura danych net_device zawiera zbiór wskaźników funkcji używanych przez jądro podczas interakcji ze sterownikiem urządzenia i specjalnymi opcjami jądra. Inicjalizacja tych wskaźników zależy częściowo od typu urządzenia (np. Ether- net) i częściowo od jego modelu. Ze względu na popularność sieci Ethernet w tym rozdziale skoncentrujemy się na inicjalizacji urządzeń Ethernet (inne urządzenia są obsługiwane w bar- dzo podobny sposób). W rozdziale 8. zajmiemy się szczegółowo sposobem rejestrowania urządzeń w kodzie sie- ciowym przez sterowniki urządzeń. Podstawowe cele inicjalizacji kart sieciowych Każde urządzenie sieciowe jest reprezentowane w jądrze systemu Linux przez instancję struktury danych net_device. W rozdziale 8. pokazano, w jaki sposób struktury te są przy- dzielane i w jaki sposób są inicjowane ich pola, częściowo przez sterownik urządzenia i czę- ściowo przez podstawowe procedury jądra. W tym rozdziale skoncentrujemy się na sposobie, w jaki sterowniki urządzeń przydzielają zasoby potrzebne do komunikacji pomiędzy jądrem i urządzeniem: Podstawowe cele inicjalizacji kart sieciowych | 101 Linii IRQ W podrozdziale „Interakcja pomiędzy urządzeniami i jądrem” pokażę, że karty sieciowe muszą otrzymać odpowiednie przerwanie IRQ, którego używają do wywoływania jądra. Nie jest to natomiast potrzebne w przypadku urządzeń wirtualnych: przykładem może być urządzenie pseudosieci, którego działanie odbywa się całkowicie wewnątrz jądra (podrozdział „Urządzenia wirtualne” w dalszej części tego rozdziału). Dwie funkcje używane do przydziału i zwalniania linii IRQ zostaną omówione w pod- rozdziale „Przerwania sprzętowe” zamieszczonym w dalszej części tego rozdziału. W pod- rozdziale „Strojenie za pośrednictwem systemu plików /proc” omówiony zostanie plik /proc/interrupts pozwalający sprawdzić aktualny przydział przerwań. Porty I/O i rejestracja pamięci Często sterownik tworzy odwzorowanie obszaru pamięci urządzenia (na przykład jego rejestrów konfiguracyjnych) w pamięci systemu, dzięki czemu operacje odczytu i zapisu przez sterownik mogą odbywać się bezpośrednio przy użyciu adresów pamięci systemowej, co pozwala uprościć kod. Porty I/O i pamięć są przydzielane i zwalniane za pomocą funkcji request_region i release_region. Interakcje pomiędzy urządzeniami i jądrem Interakcje prawie wszystkich urządzeń (włączając w to karty sieciowe) z jądrem odbywają się na dwa sposoby: Odpytywanie Wykonywane po stronie jądra. Jądro sprawdza status urządzenia w regularnych odstę- pach czasu. Przerwania Wykonywane po stronie urządzenia. Urządzenie wysyła sprzętowy sygnał (generując prze- rwanie), gdy chce zwrócić uwagę jądra. W rozdziale 9. można znaleźć szczegółowe omówienie alternatywnych rozwiązań sterowników kart sieciowych oraz przerwań programowych. Pokażę również, w jaki sposób system Linux może używać kombinacji odpytywania i przerwań w celu zwiększenia efektywności. W tym rozdziale natomiast zajmiemy się tylko przypadkiem bazującym wyłącznie na samych przerwaniach. Nie będę omawiać szczegółów związanych ze zgłaszaniem przerwań na poziomie sprzętu, różnic pomiędzy przerwaniami sprzętowymi i programowymi ani rozwiązań zastosowanych w infrastrukturach jądra związanych ze sterownikiem i magistralą. Wszystkie te zagadnienia można odnaleźć w książkach Linux Device Drivers i Understanding the Linux Kernel. Tutaj do- konam jedynie krótkiego wprowadzenia w tematykę przerwań, które pomoże zrozumieć, w jaki sposób sterowniki urządzeń inicjują i rejestrują urządzania. Specjalną uwagę poświęcę aspek- towi sieciowemu tego zagadnienia. Przerwania sprzętowe Znajomość obsługi przerwań sprzętowych na niskim poziomie nie będzie nam potrzebna. Warto jednak wspomnieć o niektórych szczegółach, ponieważ ułatwiają one zrozumienie sposobu implementacji sterowników kart sieciowych i tym samym sposobu ich interakcji z wyższymi warstwami protokołowymi. 102 | Rozdział 5. Inicjalizacja urządzeń sieciowych Każde przerwanie powoduje wykonanie funkcji zwanej procedurą obsługi przerwania, która musi pasować do konkretnego urządzenia i dlatego jest instalowana przez jego sterownik. Zwykle podczas rejestracji urządzenia jego sterownik żąda linii IRQ i przydziela mu ją. Na- stępnie rejestruje i (jeśli sterownik jest wyładowywany) wyrejestrowuje procedurę obsługi danego IRQ za pomocą dwóch funkcji zależnych od architektury systemu. Funkcje te są zde- finiowane w pliku kernel/irq/manage.c i są zastępowane funkcjami specyficznymi dla danej ar- chitektury umieszczonymi w pliku arch/XXX/kernel/irq.c, gdzie XXX jest nazwą katalogu dla tej architektury: int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs*), unsigned long irqflags, const char * devname, void *dev_id) Funkcja ta rejestruje procedurę obsługi przerwania, upewniając się najpierw, że podane przerwanie jest poprawne i nie jest już przydzielone innemu urządzeniu, chyba że oba urządzenia współdzielą to samo IRQ (podrozdział „Współdzielenie przerwania” w dalszej części tego rozdziału). void free_irq(unsigned int irq, void *dev_id) Dla urządzenia identyfikowanego przez dev_id funkcja free_irq usuwa procedurę obsługi przerwania i wyłącza linię IRQ, jeśli nie używa jej żadne inne urządzenie. Zwróćmy uwagę, że do identyfikacji procedury obsługi jądro wymaga zarówno numeru IRQ, jak i identyfi- katora urządzenia. Jest to szczególnie ważne w przypadku współdzielenia jednego IRQ przez kilka urządzeń, co zostanie wytłumaczone w podrozdziale „Współdzielenie przerwania”. Gdy jądro zostaje powiadomione o przerwaniu, używa numeru IRQ w celu znalezienia pro- cedury obsługi związanej z danym sterownikiem i następnie wykonuje ją. Jądro przechowuje związki pomiędzy numerami IRQ i procedurami obsługi w specjalnej, globalnej tabeli. Związki te mogą być typu „jeden do jednego” lub „jeden do wielu”, ponieważ jądro systemu Linux pozwala wielu urządzeniom używać tego samego IRQ, co zostanie omówione w podrozdziale „Współdzielenie przerwania”. W kolejnych podrozdziałach pokazano wiele przykładów wymiany informacji pomiędzy urządzeniami i sterownikami za pomocą przerwań, a także sposób współdzielenia jednego IRQ przez wiele urządzeń. Typy przerwań Za pomocą przerwania karta sieciowa może poinformować swój sterownik o kilku różnych rzeczach. Wśród nich są: Odebranie ramki Jest to chyba najczęstsza i najbardziej standardowa sytuacja, w której stosowane jest przerwanie. Błąd transmisji Ten rodzaj powiadomienia jest generowany przez urządzenia sieciowe Ethernet tylko w sytuacji, gdy binarne odczekiwanie wykładnicze (zaimplementowane sprzętowo w karcie sieciowej) wykaże błąd. Powiadomienie to nie jest przekazywane przez sterownik do wyższych warstw protokołowych, które dowiedzą się o błędzie w inny sposób (upływ czasu mierzonego przez licznik, negatywne potwierdzenie itd.). Interakcje pomiędzy urządzeniami i jądrem | 103 Pomyślne zakończenie transferu DMA Bufor, w którym umieszczona została ramka do wysłania, będzie zwolniony przez sterow- nik, gdy ramka zostanie załadowana do pamięci karty sieciowej. W przypadku transmisji synchronicznej (bez DMA) sterownik „wie” od razu, że ramka została umieszczona w pa- mięci karty. Natomiast w przypadku transmisji asynchronicznej (z użyciem DMA) ste- rownik musi zaczekać na przerwanie pochodzące od karty. Przykład obu przypadków można znaleźć w miejscach wywołania funkcji dev_kfree_skb1 wewnątrz kodu sterownika w pliku drivers/net/3c59x.c (DMA) i drivers/net/3c509.c (bez DMA). Urządzenie ma wystarczająco pamięci do obsługi nowej transmisji Sterownik karty sieciowej blokuje dostęp do kolejki wyjściowej, gdy nie ma ona już miejsca, aby przyjąć ramkę maksymalnego rozmiaru (czyli 1536 bajtów w przypadku karty sieciowej Ethernet). Dostęp do kolejki zostaje przywrócony, gdy dostępny jest odpowiedni obszar pamięci. Omówieniu tego przypadku poświęcimy resztę tego podrozdziału. Ostatni z przypadków wymienionych na powyższej liście dotyczy zaawansowanego sposobu dławienia transmisji, który jeśli jest prawidłowo zastosowany, może poprawić efektywność. Gdy kolejka jest pełna, sterownik blokuje możliwość transmisji, równocześnie zlecając karcie sieciowej powiadomienie go za pomocą przerwania, gdy zwiększy się obszar dostępnej pa- mięci (zwykle do wartości odpowiadającej MTU). Gdy przerwanie zostanie wygenerowane, sterownik odblokuje możliwość transmisji. Sterownik może również wyłączyć kolejkę wyjściową przed transmisją (aby zapobiec wyge- nerowaniu kolejnego żądania transmisji przez jądro) i włączyć ją z powrotem tylko wtedy, gdy karta sieciowa dysponuje odpowiednio dużym obszarem pamięci. W przeciwnym razie urządzenie wymaga przerwania, które pozwoli mu później wznowić transmisję. Oto przykład takiego działania zaczerpnięty z procedury el3_start_xmit, którą sterownik drivers/net/3c509.c instaluje jako swoją funkcję hard_start_xmit2 we własnej strukturze net_device: static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { ... ... ... netif_stop_queue (dev); ... ... ... if (inw(ioaddr + TX_FREE) 1536) netif_start_queue(dev); else outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); ... ... ... } Sterownik zatrzymuje kolejkę za pomocą funkcji netif_stop_queue, uniemożliwiając tym samym jądru generowanie kolejnych żądań transmisji. Następnie sterownik sprawdza, czy wolna pamięć urządzenia pomieści pakiet o rozmiarze 1536 bajtów. Jeśli tak, to sterownik odblokowuje kolejkę, umożliwiając jądru wysyłanie kolejnych żądań transmisji. W przeciwnym razie instruuje urządzenie (poprzez zapis do rejestru konfiguracyjnego za pomocą wywołania outw), aby wygenerowało przerwanie, gdy warunek zostanie spełniony. Procedura obsługi przerwania przywróci wtedy działanie kolejki za pomocą funkcji netif_start_queue i jądro będzie mogło przywrócić transmisję. 1 Funkcja ta jest omówiona szczegółowo w rozdziale 11. 2 Funkcja wirtualna hard_start_xmit jest omówiona w rozdziale 11. 104 | Rozdział 5. Inicjalizacja urządzeń sieciowych Funkcje netif_xxx_queue zostaną omówione w podrozdziale „Włączanie i wyłączanie transmisji” zamieszczonym w rozdziale 11. Współdzielenie przerwania Linie IRQ są zasobem o ograniczonej dostępności. Prosty sposób pozwalający na zwiększenie liczby urządzeń w systemie polega na umożliwieniu wielu urządzeniom wspólnego korzy- stania z jednego IRQ. Każdy sterownik rejestruje własną procedurę obsługi tego IRQ. Nato- miast jądro zamiast odbierać powiadomienie o przerwaniu, odnajdywać właściwe urządzenie i wywoływać należącą do niego procedurę obsługi przerwania, po prostu wywołuje wszystkie procedury obsługi należące do urządzeń, które zarejestrowały się dla tego samego IRQ. Od- filtrowanie niepotrzebnych powiadomień należy już do procedur obsługi i może odbywać się na przykład poprzez odczyt rejestru w urządzeniu. Aby grupa urządzeń mogła współdzielić linię IRQ, wszystkie należące do niej urządzenia muszą mieć sterowniki urządzeń umożliwiające obsługę współdzielonego IRQ. Innymi sło- wy, za każdym razem, gdy urządzenie rejestruje się dla danej linii IRQ, musi jawnie określić, czy obsługuje współdzielone przerwanie. Na przykład pierwsze urządzenie rejestrujące dla pewnego IRQ n procedurę obsługi fn musi również określić, czy może współdzielić to IRQ z innymi urządzeniami. Gdy kolejny sterownik urządzenia próbuje się zarejestrować dla tego samego IRQ, to żądanie rejestracji zostanie odrzucone, jeśli sterownik ten lub sterownik, do którego przypisano IRQ, nie potrafi obsługiwać współdzielenia przerwań. Organizacja odwzorowania pomiędzy liniami IRQ i procedurami obsługi Odwzorowanie przerwań IRQ na procedury ich obsługi przechowywane jest w postaci wektora list zawierającego po jednej liście procedur obsługi dla każdej linii IRQ (rysunek 5.2). Lista taka zawiera więcej niż jeden element tylko wtedy, gdy dane przerwanie jest współ- dzielone przez wiele urządzeń. Rozmiar wektora (czyli liczba linii IRQ) zależy od konkretnej architektury i może wynosić od 15 (w przypadku procesorów rodziny x86) do ponad 200. Wprowadzenie współdzielenia przerwań umożliwia pracę odpowiednio większej liczby urzą- dzeń w jednym systemie. Rysunek 5.2. Organizacja procedur obsługi IRQ Interakcje pomiędzy urządzeniami i jądrem | 105 W podrozdziale „Przerwania sprzętowe” wprowadzone zostały dwie funkcje służące do za- rejestrowania i wyrejestrowania procedur obsługi. Teraz przyjrzymy się strukturom danych służącym do reprezentacji odwzorowań pomiędzy przerwaniami i procedurami ich obsługi. Odwzorowania zostają zdefiniowane za pomocą struktur danych typu irqaction. Funkcja request_irq wprowadzona we wcześniejszym podrozdziale „Przerwania sprzętowe” obu- dowuje funkcję setup_irq, której parametrem wejściowym jest struktura irqaction umiesz- czana następnie w globalnym wektorze irq_desc. Struktura irq_desc jest zdefiniowana w pliku kernel/irq/handler.c, który może zostać zastąpiony plikiem arch/XXX/kernel/irq.c dla konkretnej architektury. Funkcja setup_irq jest zdefiniowana w pliku kernel/irq/manage.c, który również może zostać zastąpiony plikiem arch/XXX/kernel/irq.c dla konkretnej architektury. Funkcja jądra obsługująca przerwania i przekazująca je sterownikom zależy od konkretnej architektury. W większości przypadków nosi nazwę handle_IRQ_event. Na rysunku 5.2 przedstawiony został sposób przechowywania instancji irqaction: dla każdej linii IRQ istnieje instancja struktury irq_desc, a dla każdej pomyślnie zarejestrowanej proce- dury obsługi IRQ istnieje instancja struktury irqaction. Wektor instancji irq_desc również nosi nazwę irq_desc, a jego rozmiar jest określony symbolem NR_IRQS, którego wartość za- leży od konkretnej architektury. Zwróćmy uwagę, że gdy dla danego numeru IRQ (czyli danego elementu wektora irq_desc) istnieje więcej niż jedna instancja struktury irqaction, to wymagana jest obsługa współ- dzielenia przerwania (każda struktura musi mieć ustawiony znacznik SA_SHIRQ). Przyjrzyjmy się teraz, jakie informacje o procedurach obsługi IRQ są przechowywane w po- lach struktury irqaction: void (*handler)(int irq, void *dev_id, struct pt_regs *regs) Funkcja dostarczana przez sterownik urządzenia do obsługi powiadomień o przerwaniach: za każdym razem, gdy jądro odbierze przerwanie na linii irq wywoła funkcję handler. A oto parametry wejściowe tej funkcji: int irq Numer linii IRQ, która wygenerowała powiadomienie. W większości przypadków in- formacja ta nie jest używana przez sterowniki kart sieciowych, którym wystarcza identyfikator urządzenia. void *dev_id Identyfikator urządzenia. Ten sam sterownik urządzenia może być odpowiedzialny za działanie wielu urządzeń. Poprawna obsługa powiadomienia wymaga więc identyfi- katora konkretnego urządzenia. struct pt_regs *regs Struktura używana do przechowania zawartości rejestrów procesora w momencie przerwania bieżącego procesu. Zwykle nie jest używana przez funkcję obsługi prze- rwania. unsigned long flags Zbiór znaczników. Wartości SA_XXX są zdefiniowane w pliku nagłówkowym include/asm- XXX/signal.h. Oto najważniejsze z nich, dla architektury x86: SA_SHIRQ Gdy znacznik ten jest ustawiony, to sterownik urządzenia może obsługiwać współ- dzielone przerwanie. 106 | Rozdział 5. Inicjalizacja urządzeń sieciowych SA_SAMPLE_RANDOM Gdy znacznik ten jest ustawiony, to urządzenie może zostać użyte jako źródło zdarzeń losowych. Pomaga to jądru generować losowe wartości przeznaczone do wewnętrznego użytku w celu zwiększenia entropii systemu. Zagadnienie to zostanie rozwinięte w pod- rozdziale „Inicjalizacja warstwy obsługi urządzeń: net_dev_init”. SA_INTERRUPT Gdy znacznik ten jest ustawiony, to podczas wykonywania procedury obsługi wyłą- czone są przerwania na lokalnym procesorze. Znacznik ten powinno się ustawiać tylko w przypadku procedur, które bardzo szybko kończą swoje działanie. Warto przeanali- zować jedną z instancji handle_IRQ_event (na przykład /kernel/irq/handle.c). Istnieją również wartości reprezentujące inne znaczniki, ale są one albo przestarzałe, albo używane wyłącznie przez poszczególne architektury. void *dev_id Wskaźnik struktury net_device związanej z urządzeniem. Wskaźnik ten zadeklarowano jako void *, ponieważ karty sieciowe nie są jedynymi urządzeniami używającymi linii IRQ. Ponieważ różne typy urządzeń używają różnych struktur danych w celu identyfikacji i reprezentacji instancji urządzeń, stąd taki ogólny sposób deklaracji wskaźnika. struct irqaction *next Wszystkie urządzenia współdzielące to samo IRQ są połączone w listę za pomocą tego wskaźnika. const char *name Nazwa urządzenia. Można ją odczytać, wyświetlając zawartość pliku /proc/interrupts. Opcje inicjalizacji Zarówno komponenty wbudowane w jądro, jak i ładowane jako moduły mogą otrzymywać parametry wejściowe pozwalające użytkownikom stroić działanie tych komponentów, mody- fikować ich domyślne parametry lub zmieniać je podczas każdego uruchamiania systemu. Jądro udostępnia dwa rodzaje makr umożliwiających definiowanie opcji: Opcje modułów (makra rodziny module_param) Makra te definiują opcje, których można użyć podczas ładowania modułu. Gdy kompo- nent jest wbudowany w jądro, to wartości tych opcji nie mogą zostać użyte podczas uru- chamiania jądra. Jednak dzięki wprowadzeniu systemu plików /sys opcje te można konfi- gurować za pośrednictwem plików podczas działania systemu. Interfejs /sys jest stosunkowo nowym rozwiązaniem w porównaniu z interfejsem /proc. Więcej szczegółów na temat tych opcji można znaleźć w podrozdziale „Opcje modułów” zamieszczonym w dalszej części tego rozdziału. Opcje uruchamiania jądra (makra rodziny __setup) Makra te definiują opcje, których używamy podczas uruchamiania systemu. Wykorzy- stywane są głównie przez moduły, które użytkownik może wbudować w jądro syste- mu, oraz komponenty jądra, których nie można skompilować jako moduły. Zastosowa- nie tych makr pokazano w podrozdziale „Opcje uruchamiania jądra” zamieszczonym w rozdziale 7. Opcje inicjalizacji | 107 Warto zauważyć, że moduł może definiować opcje inicjalizacji na dwa sposoby: jeden efek- tywny w przypadku modułu wbudowanego w jądro i drugi, działający dla modułów łado- wanych oddzielnie. Sytuacja taka może być nieco myląca, zwłaszcza że różne moduły mogą definiować przekazywanie parametrów o tej samej nazwie podczas ich ładowania bez jakie- gokolwiek ryzyka kolizji nazw (ponieważ parametry są przekazywane właśnie ładowanemu modułowi). Natomiast jeśli przekazujemy te parametry podczas uruchamiania jądra, to mu- simy upewnić się, że nie ma kolizji nazw pomiędzy opcjami różnych modułów. Nie będziemy tutaj omawiać zalet i wad obu rozwiązań. Czytelny przykład użycia opcji ro- dziny module_param, jak i __setup można znaleźć w pliku sterownika drivers/block/loop.c. Opcje modułów Moduły jądra definiują swoje parametry za pomocą makr rodziny module_param, których listę można znaleźć w pliku nagłówkowym include/linux/moduleparam.h. Makro module_param wyma- ga trzech parametrów, co ilustruje poniższy przykład zaczerpnięty z pliku drivers/net/sis900.c: ... module_param(multicast_filter_limit, int, 0444); module_param(max_interrupt_work, int, 0444); module_param(debug, int, 0444); ... Pierwszy z nich jest nazwą parametru przeznaczoną dla użytkownika. Drugi określa typ pa- rametru (np. int), a trzeci reprezentuje prawa dostępu do pliku w /sys, do którego zostanie wyeksportowany parametr. Na skutek wyświetlenia zawartości katalogu modułów w /sys uzyskano by w tym przypadku następujące informacje: [root@localhost src]# ls -la /sys/modules/sis900/parameters/ total 0 drwxr-xr-x 2 root root 0 Apr 9 18:31 . drwxr-xr-x 4 root root 0 Apr 9 18:31 .. -r--r--r-- 1 root root 0 Apr 9 18:31 debug -r--r--r-- 1 root root 4096 Apr 9 18:31 max_interrupt_work -r--r--r-- 1 root root 4096 Apr 9 18:31 multicast_filter_limit [root@localhost src]# Każdemu modułowi przypisany jest katalog w /sys/modules. W podkatalogu /sys/modules/module/ parameters znajduje się plik dla każdego z parametrów eksportowanych przez moduł module. Ostatni przykład pochodzący z pliku drivers/net/sis900.c pokazuje trzy pliki reprezentujące parametry, które mogą być odczytywane przez każdego użytkownika, ale nie mogą być mo- dyfikowane. Prawa dostępu do plików w katalogu /sys (a przy okazji również do plików w /proc) są defi- niowane w taki sam sposób jak dla zwykłych plików. Możemy więc definiować prawo od- czytu, zapisu i wykonania dla właściciela pliku, grupy i wszystkich użytkowników. Na przy- kład wartość 400 oznacza prawo odczytu pliku przez właściciela pliku (którym jest użytkownik root) i żadnego dostępu dla nikogo więcej. Gdy wartość wynosi 0, to nikt nie ma żadnych uprawnień do tego pliku i nie jest on nawet widoczny w /sys. Jeśli programista komponentu chce umożliwić użytkownikowi odczyt parametru, to musi przydzielić mu co najmniej prawo odczytu. Może również przydzielić prawo zapisu, jeśli użytkownik ma modyfikować wartość parametru. Jednak należy pamiętać, że moduł, który 108 | Rozdział 5. Inicjalizacja urządzeń sieciowych wyeksportował parametr, nie jest powiadamiany o zmianach w pliku i musi dysponować wła- snym mechanizmem ich wykrywania. Szczegółowy opis interfejsu /sys można znaleźć w książce Linux Device Drivers. Inicjalizacja warstwy obsługi urządzeń: net_dev_init Ważna część inicjalizacji kodu sieciowego, w tym sterowania ruchem i kolejek wejściowych dla poszczególnych procesorów, wykonywana jest podczas uruchamiania systemu przez funkcję net_dev_init zdefiniowaną w pliku net/core/dev.c: static int __init net_dev_init(void) { ... } subsys_initcall(net_dev_init); W rozdziale 7. pokazano, w jaki sposób makro subsys_initcall gwarantuje wykonanie funkcji net_dev_init, zanim jakikolwiek sterownik karty sieciowej zostanie wywołany, oraz wyjaśniono, dlaczego jest to tak ważne. Wyjaśniono również, dlaczego funkcja net_dev_init jest oznaczona makrem __init. Przeanalizujmy główne kroki podejmowane przez funkcję net_dev_init: · · · · · · · Funkcja inicjuje struktury danych dla poszczególnych procesorów używane przez dwa sieciowe przerwania programowe. W rozdziale 9. wyjaśniono, czym są przerwania pro- gramowe i w jaki sposób są używane przez kod sieciowy. Jeśli jądro zostało skompilowane z obsługą systemu plików /proc (co jest domyślną konfi- guracją jądra), to w /proc zostaje umieszczonych kilka plików przez funkcje dev_proc_init i dev_mcast_init. Więcej szczegółów można znaleźć w podrozdziale „Strojenie za po- średnictwem systemu plików /proc” zamieszczonym w dalszej części tego rozdziału. Funkcja netdev_sysfs_init rejestruje klasę net w sysfs. W ten sposób powstaje katalog /sys/class/net, w którym znajdzie się osobny podkatalog dla każdego zarejestrowanego urządzenia sieciowego. Katalogi te będą zawierać sporo plików, niektóre z nich znane również z /proc. Funkcja net_random_init inicjuje dla każdego procesora wektor posiewów, które będą używane podczas generowania liczb losowych za pomocą funkcji net_random. Funkcja net_random jest używana w różnych kontekstach omówionych w dalszej części tego pod- rozdziału. Funkcja dst_init inicjuje bufor DST omówiony w rozdziale 33. Zainicjowany zostaje wektor procedur obsługi protokołów ptype_base używany do de- multipleksowania ruchu wejściowego. Więcej informacji na ten temat w rozdziale 13. Gdy zdefiniowany jest symbol OFFLINE_SAMPLE, jądro konfiguruje funkcję wykonywaną w regularnych odstępach czasu w celu zbierania danych statystycznych o długości kolejek urządzeń. Funkcja net_dev_init musi utworzyć licznik czasu, który pozwoli regularnie wywoływać wspomnianą funkcję. Więcej informacji na ten temat można znaleźć w pod- rozdziale „Średnia długość kolejki i wyznaczanie poziomu przeciążenia” zamieszczonym w rozdziale 10. Inicjalizacja warstwy obsługi urządzeń: net_dev_init | 109 · Funkcja zwrotna dev_cpu_callback zostaje zarejestrowana w łańcuchu powiadomień o zdarzeniach związanych z dołączaniem kolejnych procesorów podczas pracy systemu. Obecnie przetwarzane jest jedynie zdarzenie polegające na zatrzymaniu pracy procesora. Gdy odebrane zostanie powiadomienie o tym zdarzeniu, z kolejki wejściowej procesora usuwane są bufory, które następnie są przekazywane funkcji netif_rx. Więcej informacji na temat działania kolejek wejściowych dla poszczególnych procesorów można znaleźć w rozdziale 9. Generowanie liczb losowych wykorzystywane jest przez jądro w celu nadania losowości nie- którym jego działaniom. Podczas lektury tej książki Czytelnik dowie się, że wiele podsystemów sieciowych używa wartości wygenerowanych w sposób losowy. Na przykład często dodają losowo wybrany składnik do wartości liczników czasu, zmniejszając w ten sposób prawdopo- dobieństwo równoczesnego wykonania zbyt wielu operacji i związanego z tym nadmiernego obciążenia procesora. Zastosowanie wartości losowych pozwala również zapobiegać atakom typu DoS (Denial of Service) próbującym odgadnąć sposób organizacji pewnych struktur danych. Stopień, w jakim wartości używane przez jądro mogą zostać uznane za rzeczywiście losowe, nazywany jest entropią systemu. Do jego poprawy wykorzystywane są komponenty jądra, których działanie ma aspekt niedeterministyczny. Do kategorii tej często należą właśnie urządze- nia sieciowe. W obecnej wersji systemu tylko kilka sterowników kart sieciowych może być używanych w celu zwiększenia entropii systemu (o czym wspomina wcześniejsze omówie- nie znacznika SA_SAMPLE_RANDOM). Łata jądra 2.4 wprowadza opcję kompilacji, która włącza lub wyłącza wkład kart sieciowych do entropii systemu. Szukając w sieci słowa kluczowego „SA_SAMPLE_NET_RANDOM”, można znaleźć informacje na temat aktualnej wersji. Kod tradycyjny W poprzednim podrozdziale wspomniałem, że makra subsys_initcall gwarantują wyko- nanie funkcji net_dev_init, zanim jakikolwiek sterownik urządzenia zdoła zarejestrować swoje urządzenie. Przed wprowadzeniem tego mechanizmu porządek wykonania był wymuszany w inny sposób, poprzez użycie przestarzałego mechanizmu jednorazowego znacznika. Globalna zmienna dev_boot_phase była używana jako znacznik logiczny informujący o tym, czy funkcja net_dev_init ma być wykonana. Znacznik ten był inicjowany wartością 1 (funkcja net_dev_init nie była jeszcze wykonana), a następnie był kasowany przez funkcję net_dev_init. Za każdym razem, gdy funkcja register_netdevice była wywoływana przez sterownik urządzenia, sprawdzała wartość znacznika dev_boot_phase i jeśli był on ustawiony, wyko- nywała funkcję net_dev_init. Mechanizm ten nie jest już potrzebny, ponieważ funkcja register_netdevice nie może zo- stać wywołana przed funkcją net_dev_init, jeśli tylko zastosowano właściwe oznaczenie kluczowych procedur sterowników (rozdział 7.). Jednak aby wykryć błędy w oznaczeniach tych procedur lub błędy kodu, funkcja net_dev_init nadal kasuje znacznik dev_boot_phase, a funkcja register_netdevice używa makra BUG_ON gwarantującego, że nie zostanie wywoła- na, gdy znacznik dev_boot_phase jest ustawiony3. 3 Zastosowanie makr BUG_ON i BUG_TRAP jest typowym przykładem mechanizmu gwarantującego spełnienie koniecznych warunków w określonych punktach kodu. Mechanizm taki jest przydatny podczas przechodze- nia do nowego rozwiązania pewnego problemu. 110 | Rozdział 5. Inicjalizacja urządzeń sieciowych Kod pomocniczy w przestrzeni użytkownika Istnieją przypadki, że wywołanie przez jądro aplikacji działających w przestrzeni użytkow- nika w celu obsługi zdarzeń rzeczywiście ma sens. Szczególnie ważne są dwa z nich: /sbin/modprobe Wywoływany, gdy jądro ładuje moduł. Program ten stanowi część pakietu module-init-tools. /sbin/hotplug Wywoływany, gdy jądro wykryje, że nowe urządzenie zostało włączone do systemu (lub wyłączone z niego). Zadaniem tego programu jest załadowanie właściwego sterownika urządzenia na podstawie identyfikatora urządzenia. Urządzenia są identyfikowane na podstawie magistrali, do której są przyłączone (np. PCI) i identyfikatora zdefiniowanego przez specyfikację danej magistrali4. Program ten jest częścią pakietu hotplug. Jądro posiada funkcję call_usermodehelper pozwalającą wykonywać kod pomocniczy w prze- strzeni użytkownika. Funkcja ta umożliwia przekazanie uruchamianej aplikacji zmiennej liczby parametrów w arg[] i zmiennych środowiskowych w env[]. Na przykład pierwszy parametr arg[] informuje funkcję call_usermodehelper, jaki program należy uruchomić w przestrzeni użytkownika, a parametr arg[1] może zostać użyty do przekazania temu programowi skryptu konfiguracyjnego. Przykład pokazano w podrozdziale „/sbin/hotplug” zamieszczonym w dal- szej części tego rozdziału. Na rysunku 5.3 przedstawiony został sposób, w jaki dwie procedury jądra, request_module i kobject_hotplug, używają funkcji call_usermodehelper w celu wywołania programów po- mocniczych /sbin/modprobe i /sbin/hotplug działających w przestrzeni użytkownika. Rysunek poka- zuje również sposób inicjalizacji tablic arg[] i env[] w obu przypadkach. W następnych podroz- działach zajmiemy się nieco bardziej szczegółowo omówieniem obu programów pomocniczych. kmod kmod jest procedurą ładującą moduły jądra, pozwalającą komponentom jądra żądać załado- wania modułu. Jądro udostępnia w tym celu więcej niż jedną funkcję, ale tutaj zajmiemy się jedynie omówieniem funkcji request_module. Funkcja ta inicjuje arg[1] nazwą ładowanego modułu. /sbin/modprobe używa pliku konfiguracyjnego /etc/modprobe.conf, który pozwala mu na przykład sprawdzić, czy nazwa modułu otrzymana od jądra nie jest w rzeczywistości sy- nonimem czego innego (rysunek 5.3). Poniżej przedstawiamy dwa przykłady zdarzeń, które spowodują, że jądro zażąda od /sbin/ modprobe załadowania modułu: · Administrator używa programu ifconfig do skonfigurowania karty sieciowej, której ste- rownik nie został jeszcze załadowany, na przykład eth05. Wtedy jądro wysyła żądanie do /sbin/modprobe, aby załadował moduł, którego nazwą jest eth0 . Jeśli plik konfiguracyjny /etc/modprobe.conf zawiera pozycję alias eth0 3c59x , to /sbin/modprobe próbuje zała- dować moduł 3c59x.ko. 4 Przykład dla magistrali PCI można znaleźć w podrozdziale „Rejestracja sterownika karty sieciowej PCI” za- mieszczonym w rozdziale 6. 5 Zwróćmy uwagę, że eth0 jeszcze nie istnieje, ponieważ sterownik nie został załadowany. Kod pomocniczy w przestrzeni użytkownika | 111 Rysunek 5.3. Propagacja zdarzeń z jądra do przestrzeni użytkownika · Administrator konfiguruje sterowanie ruchem dla pewnego urządzenia, używając polecenia tc należącego do pakietu IPROUTE2. Może odwołać się wtedy do reguły kolejkowania lub klasyfikatora, które nie znajdują się w jądrze. W takim przypadku jądro żąda od /sbin/modprobe załadowania odpowiedniego modułu. Więcej informacji na temat modułów i kmod można znaleźć w książce Linux Device Drivers. Hotplug Opcję Hotplug wprowadzono do jądra systemu Linux w celu obsługi coraz popularniejszych urządzeń PnP (Plug and Play). Jądro może wykrywać podłączenie lub odłączenie takich urządzeń i powiadamiać o tym aplikacje działające w przestrzeni użytkownika, a także prze- kazuje im dość szczegółów, aby mogły załadować odpowiedni sterownik i zastosować zwią- zaną z nim konfigurację (jeśli taka istnieje). 112 | Rozdział 5. Inicjalizacja urządzeń sieciowych Hotplug może być również używana do obsługi tradycyjnych urządzeń podczas uruchamiania systemu. Nie ma znaczenia, czy urządzenie zostało podłączone w czasie pracy systemu, czy było już włączone podczas jego uruchamiania. W obu przypadkach powiadomiony zostaje kod pomocniczy działający w przestrzeni użytkownika. Aplikacja działająca w przestrzeni użyt- kownika decyduje o tym, czy zdarzenie to wymaga z jej strony podjęcia pewnych działań. System Linux, podobnie jak większość systemów Unix, wykonuje podczas startu zbiór skryp- tów służących do inicjalizacji urządzeń peryferyjnych, w tym urządzeń sieciowych. Składnia, nazwy i położenie tych skryptów zmienia się dla różnych dystrybucji systemu Linux. (Na przy- kład dystrybucje używające modelu init pochodzącego z Systemu V mają odpowiednie ka- talogi w /etc/rc.d/ wraz z plikami konfiguracyjnymi informującymi o tym, co należy uruchomić. Inne dystrybucje są albo oparte na modelu BSD, albo używają go w trybie zgodności z Sys- temem V.) Dlatego też powiadomienia o urządzeniach obecnych podczas uruchamiania systemu mogą zostać zignorowane, ponieważ skrypty i tak skonfigurują te urządzenia. Gdy kompilujemy moduły jądra, to pliki wynikowe zostają domyślnie umieszczone w katalogu /lib/modules/wersja_jądra, gdzie wersja_jądra może być na przykład równa 2.6.12. W tym samym katalogu możemy znaleźć dwa interesujące pliki: modules.pcimap i modules.usbmap. Pliki te zawie- rają odpowiednio: identyfikatory urządzeń PCI6 i USB obsługiwanych przez jądro. Te same pliki zawierają dla każdego identyfikatora urządzenia referencję związanego z nim modułu jądra. Gdy program pomocniczy działający w przestrzeni użytkownika otrzyma powiadomienie o włączeniu urządzenia PnP, używa tych plików do odnalezienia odpowiedniego sterownika urządzenia. Pliki modules.xxxmap są wypełniane informacją na podstawie wektorów identyfikatorów do- starczanych przez sterowniki urządzeń. W podrozdziale „Przykład rejestracji sterownika karty sieciowej PCI” zamieszczonym w rozdziale 6. pokażę, w jaki sposób sterownik Vortex inicjuje swoją instancję pci_device_id. Ponieważ sterownik ten został napisany dla urzą- dzenia PCI, to zawartość tej tablicy trafi do pliku modules.pcimap. Czytelnik zainteresowany najnowszą wersją kodu Hotplug znajdzie więcej informacji na stronie http://linux-hotplug.sourceforge.net. /sbin/hotplug Domyślnym programem pomocniczym, wykonywanym w przestrzeni użytkownika dla opcji Hotplug jest skrypt7 /sbin/hotplug należący do pakietu Hotplug. Pakiet ten może zostać skonfigurowany za pomocą plików umieszczonych w domyślnych katalogach /etc/hotplug/ i /etc/hotplug.d/. Funkcja kobject_hotplug jest wywoływana przez jądro między innymi w odpowiedzi na podłą- czenie lub odłączenie urządzenia. Funkcja kobject_hotplug inicjuje arg[0] jako /sbin/hotplug, a arg[1] — odpowiednim agentem. /sbin/hotplug/ jest bowiem prostym skryptem, który prze- kazuje obsługę zdarzenia innemu skryptowi (agentowi) w oparciu o parametr arg[1]. Agenty kodu pomocniczego wykonywanego w przestrzeni użytkownika mogą być mniej lub bardziej skomplikowane w zależności od tego, na ile „inteligentny” ma być proces autokon- figuracji. Skrypty dostarczane z pakietem Hotplug próbują rozpoznać dystrybucję systemu 6 Krótki opis identyfikatorów urządzeń PCI znajduje się w podrozdziale „Przykład rejestracji sterownika karty sieciowej PCI” zamieszczonym w rozdziale 6. 7 Administrator może tworzyć własne skrypty lub wykorzystać dostarczane z większością dystrybucji systemu Linux. Kod pomocniczy w przestrzeni użytkownika | 113 Linux i dopasować swoje działanie do odpowiedniej składni plików konfiguracyjnych i ich położenia. Przeanalizujmy przykład działania opcji Hotplug dla urządzenia sieciowego. Gdy karta sie- ciowa zostaje dodana do systemu lub z niego usunięta, funkcja kobject_hotplug inicjuje pa- rametr arg[1] jako net, co prowadzi do wywołania agenta net.agent przez /sbin/hotplug. W przeciwieństwie do innych agentów przedstawionych na rysunku 5.3, net.agent nie repre- zentuje ani medium transmisji danych, ani typu magistrali. Podczas gdy inne agenty są uży- wane do ładowania odpowiednich modułów (sterowników urządzeń) na podstawie identy- fikatorów urządzeń, net.agent jest używany w celu skonfigurowania urządzenia. Zadaniem net.agent jest zastosowanie konfiguracji związanej z nowym urządzeniem, wobec czego musi on otrzymać od jądra przynajmniej identyfikator tego urządzenia. W przykładzie pokazanym na rysunku 5.3 identyfikator urządzenia zostaje przekazany przez jądro za po- mocą zmiennej środowiskowej INTERFACE. Aby urządzenie mogło zostać skonfigurowane, musi najpierw zostać stworzone i zarejestro- wane w jądrze. Zadanie to jest zwykle wykonywane przez sterownik urządzenia, który wobec tego musi zostać najpierw załadowany. Na przykład dodanie karty sieciowej PCMCIA Ethernet spowoduje kilka wywołań programu /sbin/hotplug. Będą wśród nich: · · Wywołanie prowadzące do wykonania programu /sbin/modprobe8, który zajmie się zała- dowaniem odpowiedniego modułu sterownika. W przypadku kart PCMCIA sterownik zostaje załadowany przez agenta pci.agent (przy użyciu akcji ADD). Wywołanie konfigurujące nowe urządzenie. Zadanie to jest realizowane przez agenta net.agent (ponownie przy użyciu akcji ADD). Urządzenia wirtualne Urządzenie wirtualne jest abstrakcją zbudowaną w oparciu o jedno lub więcej rzeczywistych urządzeń. Związek pomiędzy urządzeniami wirtualnymi i rzeczywistymi może być typu wiele do wielu, co ilustrują trzy modele przedstawione na rysunku 5.4. Możliwe jest również tworzenie kolejnych urządzeń wirtualnych w oparciu o inne takie urządzenia. Jednak nie wszystkie takie kombinacje są obsługiwane przez jądro. Rysunek 5.4. Możliwe związki pomiędzy wirtualnymi i rzeczywistymi urządzeniami 8 W przeciwieństwie do programu /sbin/hotplug będącego skryptem powłoki program /sbin/modprobe jest bi- narnym plikiem wykonywalnym. Jeśli Czytelnik chce przeanalizować jego działanie, powinien pobrać kod źródłowy pakietu modutil. 114 | Rozdział 5. Inicjalizacja
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Linux. Mechanizmy sieciowe
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: