Geschwindigkeit/Übertragungsrate eines Netzwerkinterfaces unter Linux reduzieren

Im Rahmen aktueller Arbeiten an Ajax getriebenen Dateiuploads tauchte das Problem auf, mal kurzfristig die Geschwindigkeit einer Netzwerkverbindung drosseln zu müssen, um im lokalen Netz einer länger andauernden Dateitransfer zwischen einem Browser und einem Server zu simulieren.

Aus alten Zeiten hatte ich Werkzeuge wie “wondershaper” oder “trickle” im Kopf. Siehe etwa
http://www.ubuntugeek.com/use-bandwidth-shapers-wondershaper-or-trickle-to-limit-internet-connection-speed.html
http://askubuntu.com/questions/20872/how-do-i-limit-internet-bandwidth
http://unix.stackexchange.com/questions/83888/limit-outgoing-bandwidth-on-an-specific-interface
Diese Tools sind aber sehr alt. Entsprechende Pakete für “trickle” findet man für aktuelle Opensuse Versionen nicht mehr in den Standard-Repositories.

Eine einfach schnelle Lösung für Ethernet-Schnittstellen bietet das CLI Werkzeug “ethtool”, das zum Standardumfang der meisten Distributionen gehört. “ethtool” ist ein mächtiges Werkzeug zur Analyse und zur Konfiguration/Manipulation von Schnittstellen. Es lohnt sich, sich damit ein wenig zu beschäftigen. Zu meiner Schande muss ich gestehen, dass ich dies bislang eher versäumt habe.

Für unseren Anwendungszweck ist die Syntax aber sehr einfach. Heißt unser Ethernet Device etwa “enp8s0”, so erhalten wir einen Überblick über technische Daten der Schnittstelle mit :

mytux:~ # ethtool enp8s0
Settings for enp8s0:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Half 1000baseT/Full 
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Half 1000baseT/Full 
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  10baseT/Half 10baseT/Full 
                                             100baseT/Half 100baseT/Full 
                                             1000baseT/Full 
        Link partner advertised pause frame use: Symmetric Receive-only
        Link partner advertised auto-negotiation: Yes
        Speed: 1000Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00000033 (51)
                               drv probe ifdown ifup
        Link detected: yes

Welche Netzwerkschnittstellen auf dem eigenen System verfügbar sind, ermittelt man natürlich mit
“ip link show” oder “ifconfig”:

mytux:~ # ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
3: enp9s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether yy:yy:yy:yy:yy:yy brd ff:ff:ff:ff:ff:ff
4: vmnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 
1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether nn:nn:nn:nn:nn:nn brd ff:ff:ff:ff:ff:ff
5: vmnet8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether mm:mm:mm:mm:mm:mm brd ff:ff:ff:ff:ff:ff

Die generelle Syntax zur Änderung der Geschwindigkeit mit ethtool ist:

ethtool -s DEVICE speed [SPEED] duplex [DUPLEX]

DEVICE ist durch den Schnittstellennamen, den man über ifconfig ermitteln kann, zu ersetzen. Welche SPEED Werte angegeben werden können, zeigt der Output von “ethtool DEVICE”; s. das Beispiel oben.

Will ich also die Übertragungsrate meiner Netzwerkschnittstelle temporär auf mögliche 10Mb/s reduzieren, so hilft:

mytux:~ # ethtool -s enp8s0 speed 10 duplex full

Und tatsächlich:

mytux:~ # ethtool enp8s0
Settings for enp8s0:
....    
	Link partner advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Full
....

Zurücksetzen erfolgt mit

mytux:~ # ethtool -s enp8s0 speed 1000 duplex full

Autonegotiation für weiterreichende Experimente, bei denen man Verbindungskabel abzieht/ansteckt, stoppt man übrigens mit

ethtool -s DEVICE autoneg off

Der Nachteil von “ethtool” gegenüber dem alten “trickle” ist übrigens, dass “trickle” durch Manipulationen im Userspace die Transfergeschwindigkeit für eine bestimmte Anwendung drosseln kann. Das geht mit ethtool nicht.

Eclipse PDT – Code Assist in PHP 5.4 Traits

Traits sind eine feine Sache, wenn man horizontales Design in PHP Projekten angemessen unterstützen will.
Siehe z.B.: http://www.kingcrunch.de/blog/2011/08/01/php5-4-traits-aka-horizontal-reuse/
Ich setze Traits z.Z. selbst verstärkt in Kundenprojekten ein. Ein kleines praktisches Problemchen, über das ich in Eclipse PDT dabei gestolpert bin, ist die Frage des Code Assists bzw. der Code Completion bei der Code-Erstellung innerhalb von Methoden (Funktionsblöcken) eines Traits.

In den Code-Blöcken der Methoden eines Traits kommt ja oft der $this-Operator mit Referenzen auf Methoden, Variablen und ggf. weitere (z.B. injizierte) Objekte der Zielobjekte bzw. Zielklassen des Traits zum Einsatz. Die Zielklassen eines Traits – also die Klassen, in die der Trait eingebunden und die Trait-Funktionen genutzt werden sollen – beinhalten ja typischerweise bereits Referenzen auf eigene Methoden und ggf. auch weitere Objekte (mit zugehörigen Klassen-Variablen und Methoden). Diese referenzierten Methoden und auch Objekte müssen im Trait u.U. angesprochen werden.

Bei der entwicklungstechnischen Bearbeitung der Zielklassen selbst unterstützt einen PDT umfangreich mit Code Assisting auch für weitere referenzierte Objekte und Klassen, wenn

  • diejenigen Member-Variablen, denen die intern referenzierten Objekte zugeordnet werden, z.B. per “phpDocumentor Tag”-Anweisung mit einem Hint hinsichtlich der Klassenzugehörigkeit versehen wurden
  • und/oder innerhalb der Methoden-Codes ein entsprechendes Type Hinting vorgenommen wurde.

Siehe hierzu:
PHP Type Hinting with Eclipse
PHP Code Content Assists und Inline Type Hinting in Eclipse

Nun möchte man gerne bei der Trait-Entwicklung

  • für die Methoden und Variablen der Zielklassen des Traits selbst
  • wie auch für Objekte und deren Klassen, die innerhalb der Zielklasse referenziert werden,

Code Assisting erhalten, wenn man diese in einer Trait-Methode ansprechen und nutzen will.

Natürlich kann die PDT-Engine bei der Bearbeitung eines Traits aber nicht wissen, für welche Ziel-Klassen das Trait zum Einsatz kommen wird. Mit welchem Klassentypus (einer Vererbungshierarchie) der $this-Operator innerhalb des Traits assoziiert sein wird, ist daher ohne weitere Hilfe unklar. Damit hängen auch alle über $this referenzierten internen Objekte in der Luft. Code Assist innerhalb eines Traits beschränkt sich daher ohne weiteres Zutun des Entwicklers nur auf genau die Variablen und Funktionen/Methoden, die im Trait selbst definiert wurden.

In dem Falle, dass die Ziel-Klassen des Traits alle von einer (gemeinsamen) Klasse abgeleitet wurden, kann man aber mehr erreichen.

Diese Situation entspricht z.B. der, dass man für bestimmte Objekt-Typen über eine Vererbungshierarchie einen Satz von Funktionalitäten bereitgestellt hat. Nun sollen entsprechende Objekte in einer unterschiedlichen Gruppen von Applikationen zum Einsatz kommen, in denen die Basis-Funktionalitäten in gruppen- und applikationsspezifischer Weise überschrieben und ergänzt werden sollen. Diese Änderungen/Ergänzungen seien applikationsspezifisch und nicht strukturell bedingt und mögen daher keinen Grund für eine Erweiterung der Klassenhierarchie selbst darstellen.
Dann kann man in PHP sein Ziel auf breiter Front pro Gruppe durch Integration von gruppenspezifischen Traits erreichen.

Beispiel: Eine Veererbungshierarchie stelle ein allgemeines Spektrum an Funktionalitäten für Template-Control-Objekte zur Verfügung. In unserem zu realisierenden Anwendungsspektrum sollen diese Funktionalitäten für definierte
Applikationsgruppen spezifisch – innerhalb einer Applikatonsgruppe jedoch immer in gleicher Weise – kombiniert werden. Traits lösen dieses Problem auf einfache und elegante Weise.

Innerhalb des Traits möchte man nun Code-Assisting für die Variablen der gemeinsamen Basisklassen erhalten. Nennen wir die potentiellen Zielklassen mal “Class_CTRL_1”, “Class_CTRL_2”, … und gehen wir davon aus, dass alle diese Klassen von einer gemeinsamen Parent-Klasse “Class_Basis_CTRL” abgeleitet sein sollen.

Der kleine aber wirkungsvolle Trick, um volles Code Assist zu bekommen, besteht nun darin, am Kopf einer Trait-Methode $this auf eine interne Variable abzubilden und dabei ein Typ-Hinting einzusetzen:

/* @var $myself Class_Basis_CTRL */
$myself = $this;

Danach arbeitet man in der Entwicklung der Trait-Methoden-Codes anstelle von $this mit $myself weiter und erhält dadurch kompletten Zugriff auf alle Variablen und Methoden von “Class_Basis_Ctrl” im Rahmen des PDT Code Assists. Und weiter auch auf referenzierte Objektklassen, wenn die für die zugehörigen Variablen in der Zielklasse bereits Type Hinting eingesetzt wurde. Das macht wirklich Spaß und Laune …

Viel Spaß künftig bei der effizienten Entwicklung von Traits unter PHP5.4 mit Eclipse !