Prezentacja User-Mode Linux

Katarzyna Rempoła, Jakub Tomiczek, Adam Warski


Spis treści:


Wstęp

Historia

User-Mode Linux to system operacyjny Linux zagnieżdżony w zewnętrznym systemie operacyjnym (Linux). Koncepcja jego stworzenia zrodziła się na początku 1999 roku, a jej autorem jest Jeff Dike. UML zaczął powstawać jako łatka do jądra 2.0. Oryginalnie był projektowany jako narzędzie develpoerów, które miało przyspieszyć rozwijanie oprogramowania i zredukować wpływ wymagań sprzętowych. Pierwsza wersja ukazała się wiosną 2000 roku. Od tego czasu UML jest w ciągłym rozwoju i do każdej nowej wersji jądra Linuxa powstaje odpowiednia łatka.

Konkurencja

Idea zagnieżdżania systemów operacyjnych bardzo się rozpowszechniła i obecnie User-Mode Linux nie jest jedynym projektem tego typu. Konkurencyjne projekty to między innymi: Linux on Linux, Windows on Linux, Linux on Windows.

UML nie jest najszybszym do uruchomienia i najłatwiejszym w obsłudze spośród nich. Ma jednak wiele istotnych przewag, które wynikają z towarzyszącej mu i ściśle przestrzeganej ideologii.

Zasady działania

W przeciwieństwie do normalnego jądra systemu operacyjnego Linux, UML nie komunikuje się ze sprzętem. Jest od niego oddzielony warstwą macierzystego systemu - hosta. Zamiast z interfejsu hardware'u, korzysta z interfejsu funkcji systemowych udostępnianych przez hosta. Z punktu widzenia hosta jest więc zwykłym procesem działającym w przestrzeni użytkownika: nie ma dostępu do pamięci systemu macierzystego. Za to z punktu widzenia uruchomionych w nim aplikacji jest jądrem: z własną pamięcią wirtualną, schedulerem (planistą) oraz dostępem do zasobów. Procesy nie mają dostępu do jego przestrzeni adresowej.

User-Mode Linux umożliwia uruchomienie wielu wirtualnych komputerów pracujących pod kontrolą systemu Linux, które są odizolowane zarówno od siebie, jak i od systemu macierzystego (wraz z kontrolowanym przez niego sprzętem).

Ideologia i zalety

W odróżnieniu od konkurencyjnych projektów, twórcy UML-a dbają o to, aby w jak największym stopniu pozostał on zwykłym programem. Wynikają z tego następujące zalety:


Zastosowania

Niektóre zastosowania UML-a zaskoczyły samego autora, Jeffa Dike'a. Oto niektóre z nich:


Kompilacja i instalacja

Instalacja z RPM-a

Najłatwiej uzyskać User-Mode Linux ściągając RPM-a, gdzie będzie skompilowane jądro, dokumentacja i narzędzia (uml_moo, mkcow, mconsole...). Dodatkowo trzeba ściągnąć specjalnie przygotowany pod UML-a system plików.
Po zainstalowaniu za pomocą wywołania

[host]$ rpm -ivh nazwa_pakietu

można już uruchomić UML-a wywołując

[host]$ /usr/bin/linux (lub linux)

Kompilacja jądra UML-a

Przebiega jak zwykła kompilacja jądra.

  1. Ściągnąć najnowszą łatkę. Z nazewnictwem jest inaczej niż w przypadku jądra Linuxa - numer łatki odpowiada numerowi jądra, na które powinna być nałożona.
  2. Ściągnąć pasujące jądro (Chodzi tu o normalne Linuxowe jądro - łatka przystosuje je do UML-a)
  3. Stworzyć katalog (np. ~/uml) i rozpakować w nim jądro:

    [host]$ mkdir ~/uml
    [host]$ cd ~/uml
    [host]$ tar -xjvf linux-2.4.27.tar.bz2

  4. Nałożyć łatkę:

    [host]$ cd ~/uml/linux
    [host]$ bzcat uml-patch-2.4.27.bz2 | patch -p1

  5. Uruchomić standardowy program do konfiguracji jądra, np. wywołać make menuconfig lub make xconfig. Ważna zmiana: trzeba w linii wywołania dopisać ARCH=um, np.:

    [host]$ make menuconfig ARCH=um

    Uwaga: to działa tylko na systemach z podziałem przestrzeni adresowej 3G/1G; dla tych skonfigurowanych na 2G/2G trzeba pobrać specjalną łatkę.
  6. Uruchomić

    [host]$ make linux ARCH=um

    W wyniku powstanie plik linux w katalogu, w którym były źródła. UML jest już gotowy do uruchomienia.

Uwaga: rozmiar jądra, które powstało może być niepokojąco duży. To cecha charakterystyczna UML-a i modułów dla UML-a, że powstające binaria zajmują więcej miejsca niż analogiczne binaria hosta. W rzeczywistości są to w dużej części informacje debugowe, a faktyczna wielkość kodu wykonywalnego jest normalna. Rezczywisty rozmiar można zobaczyć robiąc na hoście strip linux

Uwaga: nie budować UML-a w /usr/source/linux ze względu na dowiązania symboliczne istniejące w katalogu /usr/include

Uwaga: bootowanie na większości systemów plików wymaga devfs (wirtualnego systemu plików) wkompilowanego do jądra i montowanego w czasie bootowania. Wyjątkiem jest system plików tomsrtbt. Można też zmodyfikować system plików, aby nie wymagał devfs. Aby to osiągnąć, należy:

Uwaga: ubd0 jest domyślnym urządzeniem filesystemu UML-a. ubd reprezentuje skonfigurowane urządzenia blokowe. Jest to oznaczenie przyjęte w UML-u dla hd, fd, cdrom, scd, itd. Urządzenia ubd są bardzo elastyczne. Mogą być mapowane na partycje, katalogi, volume managers, jak również fizyczne urządzenia. Urządzenia mogą być ładowane i usuwane z uruchomionego UML-a za pomocą konsoli zarządzania (management console, mconsole).

Kompilacja i instalacja modułów do jądra

Ta procedura wygląda analogicznie jak ze zwykłym jądrem, z dokładnością do tego, że trzeba, jak zwykle, dopisać do polecenia "ARCH=um":

[host]$ make modules ARCH=um

Moduły, jakich ma używać uml-kernel muszą być zbudowane w tym samym katalogu, gdzie kompilowaliśmy kernel ("user-mode pool"); moduły z macierzystego jądra nie działają dla UML-a.

Uwaga: znowu binaria są większe niż można by przypuszczać, ale wiadomo, o co chodzi.

Instalacja modułów

Istnieje kilka sposobów, aby zainstalować moduły:

Ładowanie modułów do jądra i kompilacja własnych modułów

Funkcje obsługujące ładowanie modułów są standardowe: depmod może zgłaszać problemy, ale dośwadczenie wskazuje, że nie należy się tym przejmować, ponieważ insmod, modprobe działają poprawnie.

Standardowym problemem przy kompilowaniu własnych modułów dla UML-a na hoście jest dobór właściwych flag kompilatora (CFLAGS). Gdy są one niepoprawne, moduł może nie działać, nawet jeśli się skompiluje. Bezpieczne jest ustawienie dokładnie tych CFLAGS, których są użyte w Makefile do budowania jądra. Aby je poznać, można do tego użyć tego właśnie pliku Makefile i jego reguły script:
Po wejściu do katalogu źródeł UML-a, następujące polecenie powinno wypisać CFLAGS:

make script 'SCRIPT=@echo $(CFLAGS)' ARCH=um

We własnym skrypcie można zdefiniować zmimenną CFLAGS następującym poleceniem:

CFLAGS=`cd katalog_ze_źródłami; make script 'SCRIPT=@echo $(CFLAGS)' ARCH=um

We własnym Makefile można zdefiniować zmienną CFLAGS następująco:

CFLAGS=$(shell cd katalog_ze_źródłami; make script 'SCRIPT=@echo $$(CFLAGS)' ARCH=um)

Kompilacja i instalowanie narzędzi UML-a

Realizacja niektórych funkcji jądra jest wspomagana przez programy przestrzeni użytkownika. Odpowiednie programy znajdują się w pakiecie uml_utilities, rozprowadzanym niezależnie od łatki na jądro. Istnieje jednak ścisła zależność między wersją łatki a wersją pakietu.

Kompilacja pakietu uml_utilities (w katalogu ze źródłami na hoście)

[host]$ make && make install

Przykładowe narzędzia


Uruchomienie i logowanie

User-Mode Linux uruchamia się poleceniem linux. Jeśli nie podamy parametru ubd0, UML będzie próbował zamontować plik o nazwie root_fs z bieżącego katalogu jako swój root filesystem. Jeśli chcemy wskazać inny filesystem, uruchamiamy:

[uml]$ linux ubd0=nasz_filesystem

UML uruchamia się i prosi o zalogowanie. UML-owe systemy plików początkowo zawierają 2 konta: root z hasłem root i user z hasłem user. Podajemy wybrany login i hasło i już jesteśmy zalogowani na wirtualną maszynę.

Inne metody logowania


Łącza szeregowe i konsole

Możliwe jest podłączenie UML-a do wielu typów kanałów wejścia/ wyjścia komputera bazowego. Umożliwia to między innymi:

  • podłączenie konsoli UML-a do nieużywanej konsoli komputera bazowego
  • podłączenie konsoli UML-a do portu, przez co możliwy jest dostęp do maszyny wirtualnej przez sieć
  • połączenie dwóch maszyn wirtualnych

Ogólny format - w linii poleceń dajemy jedną lub więcej opcji postaci:

urządzenie=kanał

Jeżeli chcemy osobno okreslić kanał wejściowy i wyjściowy, należy użyć opcji:

urządzenie=kanał_wejściowy,kanał_wyjściowy

Urządzenia

Dostępne urządzenia są dwa: konsola - con oraz łącze szeregowe - ssl. Użycie jako nazwy urządzenia po prostu "con" albo "ssl" oznacza przypisanie kanału wszystkim urządzeniom. Jeżeli chcemy podłączyć kanał do konkrentego urządzenia, po nazwie urządzenia dodajemy numer, np. "con5", "ssl9". Ustawienia dla konkretnych urządzeń przesłaniają ustawienia ogólne.

Kanały

Np., aby pozbyć się dwóch dodatkowych konsol otwierających się podczas startu systemu, należy dodać do linii poleceń opcje:

con=pty con0=fd:0,fd:1


Systemy plików

Tworzenie nowych systemów plików

Na początku musimy utworzyć plik, w którym będziemy przechowywać nowy system plików. Robimy to korzystając z polecenia dd, którym tworzymy plik rzadki (tzn. plik który fizyczne zajmuje mniej miejsca niż wynosi jego rozmiar):

[host]$ dd if=/dev/zero of=nowy_fs seek=100M count=1 bs=1

W ten sposób plik "nowy_fs" będzie miał wielkość 100MB, ale na dysku zajmie dużo mniej (można to sprawdzić poleceniem ls -ls - plik zajmuje 12 bloków).

Następnie uruchamiamy UML-a, dodając w linii poleceń opcję:

ubdx=nowy_fs

gdzie x jest numerem wolnego urządzenia blokowego.
Można utworzyć tylko system plików, którego obsługa jest wbudowana w jądro lub załadowana jako moduł jądra. Aby utworzyć system plików wydajemy polecenie:

[uml]$ mke2fs /dev/ubd/x

gdzie x jest poprzednio wybranym numerem. Polecenie to stworzy system plików ext2, ale można też tworzyć inne, poleceniami: mkreiserfs, mkdosfs itd.. Jakie systemy plików możemy stworzyć zależy od tego, jakie systemy plików obsługuje jądro (ich lista znajduje się w /proc/filesystems) oraz od zainstalowanych narzędzi w systemie. W przypadku ich braku, możemy ściągnąć je z sieci lub bazowego komputera.
Na koniec trzeba zamontować system plików:

[uml]$ mount /dev/ubd/x /mnt/nowy_fs_katalog

Rozszerzanie istniejących systemów plików

Często systemy plików ściagnięte z sieci jako nie mają prawie wolnego miejsca, przez co praca z nimi jest bardzo utrudniona. Jednak w łatwy sposób można istniejący system plików powiększyć. W tym celu trzeba wyjść z UML-a i wydać polecenia (dla systemu plików ext2):

[host]$ e2fsck -f nazwa_pliku
[host]$ dd if=/dev/zero of=nazwa_pliku bs=1 count=1 seek=nowy_rozmiar conv=notrunc
[host]$ resize2fs -p nazwa_pliku
[host]$ e2fsck -f nazwa_pliku

Po kolei: sprawdzamy system plików, zmieniamy rozmiar pliku (jako nowy_rozmiar możemy podać np. 100M lub 2GB), zmieniamy rozmiar systemu plików i na koniec dla pewności ponownie sprawdzamy czy cała operacja przebiegła pomyślnie.

Dostęp do systemu plików komputera bazowego (hosta)

Często zachodzi potrzeba skopiowania jakichś plików z komputera na którym jest uruchomiony UML do systemu plików UML-a. Można to zrobić na parę sposobów: zamontować system plików hosta przez nfs, wyłączyć UML-a, zamontować jego system plików na komputerze bazowym, poleceniem:

[host]$ mount system_plików katalog -o loop

albo skorzystać z wbudowanego w UML-a systemu plików hostfs. Aby z niego skorzystać, system plików musi być dostępny w systemie (wkompilowany w jądro albo załadowany jako moduł). Najprostszym sposobem na jego wykorzystanie jest wydanie polecenia:

[uml]$ mount none /mnt/host -t hostfs

W ten sposób przez katalog /mnt/host będziemy mieli dostęp do całego systemu plików hosta. Dodanie opcji -o katalog spowoduje zamontowanie tylko podanego katalogu (np. -o /home).
Możliwe jest też uruchomienie UML-a z katalogu na komputerze bazowym, zamiast z zawartego w pliku systemu plików. W tym celu najpierw musimy mieć odpowiedni katalog (jeżeli mamy system plików w pliku, możemy to zrobić poleceniem mount system_plików katalog -o loop). Następnie w pliku etc/fstab zamontowanego systemu plików zmieniamy rodzaj systemu plików dla katalogu głównego / na:

none / hostfs defaults 1 1

Po czym zmienimy właściciela wszystkich plików, których właścicielem był root na nas:

[host]$ find . -uid 0 -exec chown użytkownik {} \

Na koniec uruchamiamy UML-a z następującymi opcjami:

root=/dev/root rootflags=/ścieżka/do/katalogu/z/systemem/plików rootfstype=hostfs

Można też ograniczyć działanie hostfs-a przez podanie opcji w linii poleceń:

hostfs=katalog,[append]

gdzie katalog jest nazwą katalogu, który będzie można standardowo zamontować (przy podaniu np. /home niemożliwe jest uzystkanie dostępu do katalogu /etc; katalog ten można pominąć, jeżeli nie chcemy ograniczać dostępu). Opcja append oznacza, że nie będziemy mogli kasować plików z komputera bazowego (otwarcie pliku do zapisu spowoduje otwarcie go w trybie dopisywania).

Współdzielenie systemów plików

Mogłoby się wydawać, że gdy chcemy naraz uruchomić więcej niż jednego UML-a, to dla każdego musimy mieć osobny plik z głównym systemem plików (root_fs). (Próba uruchomienia dwóch UML-i z tym samym plikiem jak root_fs skończy się uszkodzeniem systemu plików!) Jednak takie rozwiązanie jest bardzo pamięciożerne, gdyż systemy plików zajmują na ogół dużo miejsca. Dlatego UML oferuje mechanizm dostępu do systemów plików COW (copy-on-write, kopiowanie przy zapisie). Każda kopia UML-a posiada jedynie własny plik COW, w którym zapisywane są zmiany w stosunku do oryginalnego systemu plików. Uruchomienie UML-a z systemem plików COW jest bardzo proste, w linii poleceń przy uruchamianiu UML-a dodajemy opcję:

ubd0=nazwa_pliku_cow,nazwa_root_fs

Spowoduje to utworzenie pliku nazwa_pliku_cow, jeżeli jeszcze nie istniał, albo skorzystanie z już istniejącego. Gdy plik COW już istnieje, możemy uruchamiać UML-a z opcją:

ubd0=nazwa_pliku_cow

Rozmiar pliku COW będzie dużo większy niż faktyczna ilość zajętego na dysku miejsca. Dlatego aby go sprawdzić należy wydać polecenie ls -ls. Gdy raz skorzystamy z pliku nazwa_root_fs jako pliku bazowego dla pliku COW, nie należy go modyfikować, czyli uruchamiać UML-a bezpośrednio z niego. Spowoduje to, że wszystkie pliki COW powiązane z tym systemem plików najprawdopodobniej przestaną działać.
Możliwe jest też scalenie pliku COW z systemem plików. W tym celu wydajemy polecenie:

[host]$ uml_moo nazwa_pliku_COW nowy_root_fs

Spowoduje to utworzenie nowego pliku z systemem plików, który będzie połączonym oryginalnym systemem plików z zmianami zawartymi w pliku COW. Można też dokonać scalenia bez tworzenia nowego pliku:

[host]$ uml_moo -d nazwa_pliku_COW

Jednak spowoduje to że inne pliki COW powiązane z oryginalnym systemem plików przestaną działać.
Aby utworzyć nowy plik COW bez uruchamiana UML-a, należy wydać polecenie:

[host]$ uml_mkcow [-f] plik_COW plik_root_fs

Opcja -f powoduje nadpisanie starego pliku COW. Narzędzie uml_moo i uml_mkcow są częścią pakietu UML Utilites.

Tworzenie nowego bazowego systemu plików

Do tworzenia nowych bazowych systemów plików (root_fs) zostało stworzonych kilka narzędzi:

Więcej informacji o tych i innych narzędziach można znaleźć na stronie UML-a.


Konsola zarządzania

Konsola zarządzania stanowi niskopoziomowy interfejs do jądra, udostępnia funkcjonalność komend sysrq (więcej o komendach sysrq w dalszej częsci tego rozdziału), rozszerzając ją o kilka innych poleceń.

Instalacja i uruchamianie konsoli

Konsolę zarządzania możemy pobrać z repozytorium CVS projektu UML: (dostepna w postaci pliku źródłowego), nastepnie kompilujemy ją dostarczonym makefile`m. Przy uruchamianiu UML-a wystarczy teraz tylko dopisać CONFIG_MCONSOLE, spowoduje to utworzenie w katalogu .uml w podkatalogu z nazwą maszyny wirtualnej instancji UML-a gniazda umożliwiającego komunikację konsoli zarządzania z UML-em. Nazwa katalogu maszyny wirtualnej jest dość losowa więc dla wygody uruchamiania konsoli możemy w linii poleceń przy startowaniu UML-a wpisać umid=nazwa

[root@localhost linux-2.4.26]$ ./linux ubd0=../root_fs_toms1.7.205 CONFIG_MCONSOLE umid=nazwa

Podczas uruchamiania UML-a powinniśmy zobaczyć coś podobnego do:

mconsole (version 2) initialized on /root/.uml/nazwa/mconsole

Teraz możemy uruchomić uml_mconsole w następujący sposób:

uml_mconsole nazwa

Pojawi się linia poleceń w której możemy wpisać następujące komendy


Dostępne komendy

1. version

Bezargumentowa, drukuje wersję UML-a:

OK Linux tomsrtbt 2.4.26 #1 nie lis 28 03:09:16 CEST 2004 i686

Można użyć tej komendy np. w celu sprawdzenia czy UML pracuje.

2. halt i reboot

Bezargumentowe, powoduje natychmiastowe zamknięcie systemu(UML-a).

3. config

Dodaje do maszyny wirtualnej nowe urządzenie lub wyświetla informacje o istniejącym urządzeniu np:

config ubd0

spowoduje wyświetlenie informacji o urządzeniu blokowym ubd0

OK ../root_fs_toms1.7.205

Natomiast

config ubd3=/root/user-mode/root_fs_slack8.1

dodanie filesystemu jako ubd3.

4. remove

Usunięcie wybranego urządzenia z systemu np:

remove ubd3

Urządzenie wybrane do usunięcia nie może być używane przez system

5. help

Wyświetla spis możliwych poleceń i opis ich czynności.

6. sysrq

Jest interfejsem do przekazywania jądru komend sysrq(normalnie są wywoływane wciśnieciem ALT+Sys Rq+). Więcej o komendach sysrq jest w pliku: Documentation/sysrq.txt w katalogu z kernelem. Wywołanie wygląda następująco:

sysrq znak_z_komenda

Przykładowo polecenie konsoli zarządzania

sysrq i

spowoduje wysłanie wszystkim procesom(poza initem) działającym na maszynie wirtualnej sygnału SIGKILL.

7. cad

Wykonuje na procesie init czynność powiązaną z kombinacja klawiszy ALT+CTRL+DELETE (normalnie powoduje restart systemu)

8. stop

Po wykonaniu stop UML wejdzie w pętle, w której może wykonywać wyłącznie polecenia wydawane z konsoli zarządzania aż do wydania polecenia go. Takie zatrzymanie systemu przydaje się przy tworzeniu backup`ów systemów plików UML`a. Możemy mianowicie zatrzymać system a następnie poleceniem konsoli sysrq -s zapisać wszystkie dane z buforów dyskowych na dysk. Teraz można zrobić kopię systemu plików i "uwolnić" system poleceniem go. Jeśli UML działa na architekturze wieloprocesorowej polecenie stop spowoduje zapętlenie tylko na jednym procesorze, ten bład, według twórców UML-a, ma zostać wkrótce naprawiony.

9. go

Używane w kontekście wspomnianym wyżej, powoduje wyjście UML-a z pętli.

10. log

W argumencie podajemy napis, na którym kernel wykona funkcję printk-czyli napis zostanie zapisany w message log-u.

12. proc

Jako argument podajemy nazwę pliku z katalogu proc w UML-u np.

proc version

Spowoduje to wypisanie na konsoli zarządzania zawartości pliku version.

Dostęp do sieci

Jeden UML uruchomiony na maszynie hosta udostepnia nam mozliwośc badania zachowań systemu operacyjnego w różnych sytuacjach, ale tak naprawdę w dzisiejszym świecie rzadkościa już są takie izolowane środowiska. Twórcy UML-a zdali sobie z tego sprawę i umożliwili łączenie maszyn wirtualnych w sieci. Dzięki temu na przykład możemy na jednym komputerze testować programy które ma docelowo mają działać współbieżnie na wielu maszynach i komunikować się między sobą. Aby skonfigurować sieć musimy mieć opcję Network device support ustawioną na enabled(jeśli korzystamy z RPM-a ta opcja jest domyślnie ustawiona). UML umożliwia transmisję pakietów danych na siedem sposobów:

ethertap i TUN/TAP

TUN/TAP, ethertap, slip oraz slirp umożliwiają wymianę pakietów pomiędzy wirtualna maszyna UML a hostem, przy czym host może być docelowym odbiorcą albo tylko routerem przesyłającym paczki innym maszynom wirtualnym bądź fizycznym. Sposób komunikacji z hostem zależy od jego wersji jądra, jeśli mamy jądro 2.2 musimy używać ethertap, wersja 2.4 może używać zarówno ethertap jak i TUN/TAP ale ten drugi ma lepszą wydajność i zapewnia większe bezpieczeństwo.

Konfiguracja TUN/TAP Przed rozpoczęciem konfiguracji musimy zainstalować uml_net (część pakietu uml_tools, do ściagnięcia ze strony projektu). W wierszu poleceń przy uruchamianiu UML-a wpisujemy:

[root@localhost linux-2.4.26]$ ./linux ubd0=../root_fs_toms1.7.205 eth0=tuntap,,,10.1.1.110

A nastepnie po zalogowaniu się(z uprawnieniami roota w UML-u):

ifconfig eth0 10.1.1.1 up

Teraz dla UML-a host jest widoczny jako 10.1.1.110 a UML dla hosta jako 10.1.1.1. Jeśli nasza wirtualna maszyna UML ma widzieć elementy sieci hosta to musimy uruchomić routowanie na maszynie wirtualnej:

Konfiguracja ethertap przebiega bardzo podobnie, z tym że nie trzeba używać do niej uml_net-a, można go zastąpić /dev/tap0. Dla jądra 2.4 nie zaleca się jej stosowania (na stronie projektu UML pisze obsolete).

[root@localhost linux-2.4.26]$ ./linux ubd0=../root_fs_toms1.7.205 eth0=ethertap,tap0,fe:fd:0:0:0:1,10.1.1.129

multicast, switch demon

Multicast(zaimplementowany przez Haralda Welte, dostępny od wersji 2.4.5-5) i demon switch umożliwiają połączenie wirtualnych maszyn UML w sieć. Taka wirtualna sieć może istnieć w całkowitej izolacji od sieci fizycznej, może także uzyskać do niej połączenie, jeśli wyznaczymy pewnym wirtualnym maszynom rolę bramek do sieci fizycznej. W zasadzie jedyna różnicą między multicast a switch jest lepsza wydajność switcha, który działa jako demon

Konfiguracja multicast W linii poleceń podczas uruchamiania UML-a dopisujemy:

[root@localhost linux-2.4.26]$ ./linux ubd0=../root_fs_toms1.7.205 eth0=mcast

Przy założeniu, że host ma interfejs eth0 Teraz wpisujemy juz w linii poleceń UML-a:

ifconfig eth0 10.1.1.1 up

Teraz możemy na hoście uruchomić kolejne UML-e i ta wirtualna maszyna będzie dla nich widoczna pod numerem 10.1.1.1

Slip

slip jest mechanizmem zastępczym do komunikacji z hostem, tzn. używamy go gdy nie chce zadziałać TUN/TAP ani ethertap.

Slirp

slirpa używamy gdy nie mamy uprawnień roota na maszynie hosta(niemożność konfiguracji sieci) lub gdy nie chcemy nadawać maszynie wirtualnej UML numeru IP.

Pcap

pcap jest interfejsem tylko do odczytu, umożliwiającym zbieranie i filtrowanie pakietów z interfejsów sieciowych hosta.

Do czego może się przydać

Na UML-u możemy uruchomić sobie także środowisko graficzne, nie korzystając przy tym z UML-owego X serwera. Wystarczy posiadać zainstalowane x-clients w systemie plików, z którego bootujemy UML-a. Po starcie konfigurujemy połącznie z hostem(np. TUN/TAP) a następnie wpisujemy:

export DISPLAY=host-ip:0

Teraz możemy uruchomić X-y.

Ciekawe zastosowanie sieciowych mozliwości maszyn wirtualnych UML-a znajduje się w Virtual Network Laboratory - Christchurch Polytechnic Institute of Technology (CPIT) w Nowej Zelandii. W obawie o wpływ eksperymentów przeprowadzanych przez studentów na siec akademicką, a mając na uwadze duże koszty utworzenia odrębnej sieci do eksperymentów postanowiono wykorzystać UML-a tworząc sieć maszyn wirtualnych przedstawioną na poniższym rysunku. Całe laboratorium składa się z 20 wirtualnych maszyn umieszczonych na jednym hoście. Wirtualne maszyny są za pomocą jednego wirtualnego routera połączone z hostem i dalej do sieci akademickiej. Konstrukcja jest bardzo dokładnie opisana na stronie: "http://user-mode-linux.sourceforge.net/cpit.html"


SKAS

Tryb TT

W normalnym trybie, UML działa w następujący sposób:

Takie rozwiązanie ma wady: ponieważ jądro jest częścią przestrzeni adresowej każdego procesu, proces może do niego pisać. W ten sposób proces mógłby dostać się do komputera bazowego. Można też wykryć czy proces działa na UML-u, sprawdzając, czy można czytać kod jądra - jest to niepożądana m.in. w "honeypotach". Również wydajność jest niższa, ponieważ do komunikacji z jądrem UML-a tt używa sygnałów.

Tryb SKAS

Rozwiązaniem tych i innych problemów jest łatka SKAS - Single Kernel Address Space. Łatka ta nakładana jest na jądro linuxa komputera bazowego (!) i umożliwia procesom przełączanie się między różnymi przestrzeniami adresowymi.

W ten sposób jądro UML-a posiada własną przestrzeń adresową i jest jest całkowicie odizolowane od procesów. Zamiast jednego procesu na komputerze bazowym dla każdego procesu UML-a, tworzone są tylko 4 procesy (jądra, procesów, sterownik ubd, emulacja pisania SIGIO), co znacznie przyśpiesza działanie. Nie jest też używana powolna komunikacja sygnałami.

Aby zainstalować SKAS, należy: ściągnąć odpowiednią łatkę i skompilować z nią jądro; w opcjach UML-a włączyć CONFIG_MODE_SKAS. Wzrost wydajności jest znaczny (nawet pięciokrotny).


Debugowanie jądra

Jądro UML jest z punktu widzenia Linuxa zwykłym zestawem procesów, może więc być debugowane w sposób podobny do zwykłego procesu na przykład przy użyciu gdb(jego będziemy dalej używać). Musimy pamiętać, że aby móc debugować jądro należy podczas kompilacji ustawić(np. dla menuconfig w sekcji Kernel hacking) Sposób debugowania jądra zależy do tego czy nasz UML działa w trybie tt(tracing thread) czy skas(separate kernel address space).

Debugowanie jądra w tt mode

Debugowanie jądra w tracing thread mode jest nieco bardziej skomplikowane, naprościej je ropocząć uruchamiając UML-a od razu pod kontrolą gdb(z opcją debug) np:

[root@localhost linux-2.4.26]$ ./linux ubd0=../root_fs_slack8.1 debug

W efekcie pojawi sie xterm z uruchomionym gdb a bootowanie UML-a zostanie zatrzymane(zatrzyma sie proces tt) na poczatku funkcji start_kernel(). Od tej chwili możemy juz wydawać polecenia debugera.

Jeśli chcemy podłączyć gdb do już działającego jądra, możemy skorzystać z konsoli zarządzania wpisując w jej linii poleceń:

config gdb=xterm

Efektem będzie uruchomienie gdb w nowym xtermie.

Jeszcze inny sposób(ogólniejszy bo możemy tak podłączyć do UML-a inne programy zawierające podproces gdb jak np. ddd i jedyny działający na moim komputerze(nie wyskakuje żaden a u xterm zwracał błąd)) Uruchamiamy UML z opcją

debug gdb-pid=

Potem podłączamy UML do gdb poleceniem

att 1

a następnie symbol-file ze ścieżką do UML-a(ładuje symbole jądra do gdb)

symbol-file /root/uml/linux-2.4.26/linux

Przykład

Przed rozpoczęciem rzeczywistej zabawy najlepiej poczytać dokładnie man gdb, dla celów tego przykładu powiemy jedynie że c wznawia wykonanie programu(np. po zatrzymaniu na breakpoincie), n wykonuje program do następnego wiersza wykonywanej funkcji a b < nazwa_funkcji > (można też podać b z innymi argumentami ale o tym w man) ustawia breakpoint na wybranej funkcji. ustawmy np. najpierw breakpoint na start_kernel a później na funkcji inicjującej wątki systemowe. Efekt poniżej:

(gdb) b start_kernel
Breakpoint 1 at 0xa00023f7: file init/main.c, line 362.
(gdb) c
Continuing.

Breakpoint 1, start_kernel () at init/main.c:362
362 printk(linux_banner);
(gdb) b kernel_thread
Breakpoint 2 at 0xa000f46b: file fork.c, line 606.
(gdb) c
Continuing.
Breakpoint 2, kernel_thread (fn=0xa000b5d0 , arg=0x0, flags=69120)
at fork.c:606
606 struct task_struct *task = current;

Debugowanie jądra w skas mode.

W trybie Single Kernel Address Space debugowanie jadra UML przebiega całkowicie jak debugowanie normalnego procesu, ropoczynamy je z linii poleceń gdb poprzez run:

run /root/user-mode/2.4.26/linux ubd0=/root/user-mode/root_fs_slack8.1

Powinniśmy jeszcze tylko nakazać gdb ignorowanie sygnałów SIGSEGV i SUGUSR1 ponieważ są one uzywane wewnętrznie przez UML i powodowałyby ciągłe przerywanie debugowania.

(gdb) handle SIGSEGV pass nostop noprint
(gdb) handle SIGUSR1 pass nostop noprint

Debugowanie modułów

Gdb wspiera debugowanie kodu który jest ładowany dynamicznie, umożliwia zatem w szczególności debugowanie modułów jądra UML. Proces ten jest jednak dosyć skomplikowany, po pierwsze musimy wskazać gdb który plik obiektowy ( *.o) został właśnie załadowany i gdzie się on znajduje w pamięci(założenie że moduł został skompilowany z opcją -g)

add-symbol-file modul.o adres_w_pamieci

Parametr adres_w pamieci jest domyślnie równy 0. Dzięki niemu gdb może zinterpretować adresy symboli zawartych w pliku modul.o. Parametr adres_w_pamieci można zdobyć z ze struktury module_list(lista załadowanych modułów) czynnośc ta jest skomplikowana i jej opis znajduje się: Wygodniejszym rozwiązaniem jest użycie gotowego skryptu umlgdb(autorstwa Chandana Kudige, do sciągnięcia z części utilities portalu sourceforge ) automatyzującego cały proces ładowania modułów. Skrypt trzeba najpierw przeglądnąć i ewentualnie pozmieniać zmienne w skrypcie tak żeby pasowały do naszych ustawień choć teoretycznie musimy jedynie poustawiać scieżki w poniższej liście tak żeby wskazywały na nasze moduły:

set MODULE_PATHS { fat /usr/src/uml/linux-2.4.18/fs/fat/fat.o
isofs /usr/src/uml/linux-2.4.18/fs/isofs/isofs.o
minix /usr/src/uml/linux-2.4.18/fs/minix/minix.o }

Przerabiamy tę listę tak, aby wskazywała moduły które chcemy debugować i uruchamiamy skrypt, postępując dalej zgodnie z jego poleceniami.

Linki


Autorzy


20:18 09/12/2004