Ein “Multicast”-Paket ist ein Netzwerk-Paket, das an mehr als einen, aber nicht alle Rechner im Netzwerk geschickt werden soll. Diese Funktionalität wird dadurch erreicht, daß spezielle Hardware-Adressen an Rechnergruppen zugewiesen werden. Pakete, die an eine dieser besonderen Adressen geschickt werden, sollten von allen Rechnern in der Gruppe empfangen werden. Bei Ethernet ist in Multicast-Adressen das niedrigstwertige Bit des ersten Adressen-Oktetts in der Zieladresse gesetzt, während dieses Bit bei keiner Karte in der Hardware-Adresse gesetzt ist.
Der schwierige Teil des Umgangs mit Rechnergruppen und Hardware-Adressen wird von den Applikationen und dem Kernel übernommen; der Treiber selbst muß sich nicht um diese Probleme kümmern.
Die Übertragung von Multicast-Paketen ist einfach, weil sie genau wie jedes andere Paket aussehen. Die Schnittstelle überträgt die Pakete über das Kommunikationsmedium, ohne sich die Ziel-Adresse anzusehen. Es ist die Aufgabe des Kernels, eine korrekte Hardware-Ziel-Adresse zuzuweisen; die Gerätemethode hard_header muß sich, wenn sie überhaupt existiert, die Daten, nicht ansehen, die sie verarbeiten soll.
Der Kernel verfolgt, welche Multicast-Adressen zu einem gegebenen Zeitpunkt interessant sind. Diese Liste kann sich häufig ändern, weil sie eine Funktion der zu einem gegebenen Zeitpunkt laufenden Applikationen und des Benutzerinteresses ist. Die Aufgabe des Treibers ist es, die Liste interessanter Multicast-Adressen entgegenzunehmen und dem Kernel die an diese Adressen geschickten Pakete zu übergeben. Wie der Treiber die Multicast-Liste implementiert, ist etwas davon abhängig, wie die zugrundeliegende Hardware funktioniert. Normalerweise gehört die Hardware, was das Multicasting angeht, zu einer von drei Klassen:
Schnittstellen, die kein Multicasting kennen. Diese Schnittstellen empfangen entweder Pakete, die exakt an ihre Hardware-Adresse gerichtet sind (und natürlich Broadcast-Pakete), oder sie empfangen jedes einzelne Paket. Sie können Multicast-Pakete nur empfangen, indem sie jedes Paket entgegennehmen und damit auch das Betriebssystem mit einer riesigen Anzahl “uninteressanter” Pakete belasten. Diese Schnittstellen gelten üblicherweise nicht als Multicasting-fähig, und der Treiber wird daher auch IFF_MULTICAST in dev->flags nicht setzen.
Punkt-zu-Punkt-Schnittstellen sind ein Sonderfall, weil sie immer jedes Paket ohne Hardware-Filterung empfangen.
Schnittstellen, die Multicast-Pakete von anderen Paketen (Rechner-zu-Rechner- oder Broadcast-Pakete) unterscheiden können. Diese Schnittstellen können angewiesen werden, jedes Multicast-Paket zu empfangen und die Software entscheiden zu lassen, ob der Rechner ein gültiger Empfänger ist. Die dadurch zusätzlich entstehende Last ist noch akzeptabel, weil es normalerweise nur wenige Multicast-Pakete in einem Netzwerk gibt.
Schnittstellen, die Multicast-Adressen in der Hardware erkennen können. Diesen Schnittstellen kann eine Liste von Multicast-Adressen übergeben werden, für die Pakete empfangen werden sollen. Alle anderen Multicast-Pakete werden dann ignoriert. Das ist natürlich für den Kernel die optimale Lösung, weil er keine Prozessorzeit damit verschwenden muß, “uninteressante” Pakete, die von der Schnittstelle hereinkommen, zu verwerfen.
Der Kernel versucht, die Fähigkeiten von guten Schnittstellen auszunutzen und die dritte Klasse, die die flexibelste ist, so gut es geht zu unterstützen. Daher benachrichtigt der Kernel auch den Treiber, wenn sich die Liste der gültigen Multicast-Adressen geändert hat, und übergibt diese Liste an den Treiber, damit dieser dem Hardware-Filter die neue Information zur Verfügung stellen kann.
Im Folgenden finden Sie eine Zusammenfassung der Datenstrukturen und Funktionen aus dem Bereich des Multicasting:
Diese Gerätemethode wird immer dann aufgerufen, wenn sich die Liste der Maschinenadressen des Gerätes ändert, außerdem aber auch, wenn dev->flags geändert worden ist, weil manche der Flags (z. B. IFF_PROMISC) auch eine Neuprogrammierung der Hardware-Filter verlangen. Die Methode bekommt einen Zeiger auf eine struct net_device als Argument und gibt void zurück. Ein Treiber, der an der Implementation dieser Methode nicht interessiert ist, kann das Feld auf NULL setzen.
Dies ist eine verkettete Liste aller Multicast-Adressen, die zu diesem Gerät gehören. Die Definition dieser Struktur steht am Ende dieses Abschnittes.
Die Anzahl der Elemente in der verketteten Liste. Diese Information ist etwas redundant, aber es ist schneller, mc_count auf 0 zu prüfen, als die Liste abzusuchen.
Wenn der Treiber diese Option in dev->flags nicht setzt, dann wird die Schnittstelle nicht um die Verarbeitung von Multicast-Paketen gebeten. Gleichwohl wird aber immer noch die Methode set_multicast_list aufgerufen, wenn sich dev->flags ändert, weil die Multicast-Liste auch geändert werden kann, während die Schnittstelle nicht aktiv ist.
Dieses Flag wird von der Netzwerk-Software in dev->flags gesetzt, um dem Treiber mitzuteilen, daß er alle Multicast-Pakete aus dem Netzwerk entgegennehmen soll. Das ist der Fall, wenn Multicast-Routing eingeschaltet wird. Wenn dieses Flag gesetzt ist, dann sollte dev->mc_list nicht zur Filterung von Multicast-Paketen verwendet werden.
Dieses Flag wird in dev->flags gesetzt, wenn die Schnittstelle in den “Promiscuous-Modus” versetzt wird. In diesem Fall soll die Schnittstelle jedes Paket entgegennehmen, unabhängig von dev->mc_list.
Schließlich benötigen Treiber-Programmierer als letzte Information noch die Definition von struct dev_mc_list, die in <linux/netdevice.h> steht:
structdev_mc_list{ structdev_mc_list*next;/*NaechsteAdresseinderListe*/ _ _u8dmi_addr[MAX_ADDR_LEN];/*Hardware-Adresse*/ unsignedchardmi_addrlen;/*Adressenlaenge*/ intdmi_users;/*ZahlderBenutzer*/ intdmi_gusers;/*ZahlderGruppen*/ }; |
Weil Multicasting und Hardware-Adressen unabhängig von der eigentlichen Übertragung der Pakete sind, ist diese Struktur portabel über die verschiedenen Netzwerk-Implementierungen, denn jede Adresse wird durch einen String von Oktetten und eine Länge identifiziert, genau wie dev->dev_addr.
Am besten läßt sich set_multicast_list durch ein wenig Pseudocode verstehen.
Die folgende Funktion ist eine typische Implementation von set_multicast_list in einem vollständigen Treiber (full-featured driver). Der Treiber ist insofern full-featured (ff) oder vollständig, als die Schnittstelle, die er ansteuert, einen komplexen Hardware-Paketfilter hat, der eine Tabelle von Multicast-Adressen verwaltet, die von diesem Rechner empfangen werden sollen. Die Maximalgröße dieser Tabelle ist VS_TABLE_SIZE.
Alle Funktionen, die das Präfix ff_ haben, sind Platzhalter für Hardware-spezifische Operationen.
voidff_set_multicast_list(structnet_device*dev) { structdev_mc_list*mcptr; if(dev->flags&IFF_PROMISC){ ff_get_all_packets(); return; } /*WennwirmitmehralseinerAdresseumgehenkoennen,holenwirunsalleMulticast-PaketeundsortierendieinderSoftware.*/ if(dev->flags&IFF_ALLMULTI||dev->mc_count>FF_TABLE_SIZE){ ff_get_all_multicast_packets(); return; } /*KeinMulticast?DannholenwirunsnurunsereneigenenKram.*/ if(dev->mc_count==0){ ff_get_only_own_packets(); return; } /*AlleMulticast-AdressenimHardware-Filterspeichern*/ ff_clear_mc_list(); for(mc_ptr=dev->mc_list;mc_ptr;mc_ptr=mc_ptr->next) ff_store_mc_address(mc_ptr->dmi_addr); ff_get_packets_in_multicast_list(); } } |
Diese Implementation kann vereinfacht werden, wenn die Schnittstelle keine Multicast-Tabelle für eingehende Pakete im Hardware-Filter ablegen kann. In diesem Fall hat VS_TABLE_SIZE den Wert 0, und die letzten vier Codezeilen werden nicht benötigt.
Wie wir bereits angedeutet haben, müssen auch Schnittstellen, die mit Multicast-Paketen nichts anfangen können, set_multicast_list implementieren, um über Veränderungen in dev->flags informiert zu werden. Wir bezeichnen so etwas als eine “unvollständige” (uv) Implementation. Diese Implementation ist sehr einfach, wie der folgende Code zeigt:
voiduv_set_multicast_list(structnet_device*dev) { if(dev->flags&IFF_PROMISC) uv_get_all_packets(); else uv_get_only_own_packets(); } |
Es ist wichtig, IFF_PROMISC zu behandeln, weil der Benutzer sonst tcpdump oder andere Netzwerk-Analyse-Programme nicht benutzen kann. Wenn die Schnittstelle eine Punkt-zu-Punkt-Verbindung bedient, ist es dagegen nicht notwendig, set_multicast_list zu implementieren, weil sie ohnehin jedes Paket bekommt.