Frage Tc: Ingress Policing und ifb Spiegelung


Ich versuche Traffic Shaping auf einem Linux-Gateway einzurichten hier geschrieben. Das Skript muss angepasst werden, da ich mehrere LAN-Schnittstellen habe. Um die LAN-Seite zu gestalten, plane ich, ein ifb-Pseudogerät wie folgt zu erstellen:

     modprobe ifb
     ip link set dev ifb0 up
    /sbin/tc qdisc add dev $WAN_INTERFACE ingress
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

Das Skript aus dem oben erwähnten GIS-Repo hat folgende Zeilen:

 /sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip sport $INTERACTIVE_PORT 0xffff flowid :1
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip dport $INTERACTIVE_PORT 0xffff flowid :1
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 5 0 u32 match ip src 0.0.0.0/0 police rate $MAX_DOWNRATE_INGRESS burst 20k drop flowid :2

Dieser Code und der ifb Interface-Erstellungscode kommen nicht gut miteinander aus. Das angepasste Skript wird ausgeführt, aber das ifb0-Gerät zeigt keine Verkehrsstatistiken an. Wenn ich den Ingress-Repo-Code (oben zitiert) auskommentiere, zeigt das ifb0-Gerät die Anzahl der übertragenen Pakete an. Auch diese Zeilen können nicht zusammen ausgeführt werden:

/sbin/tc qdisc add dev $WAN_INTERFACE ingress
/sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress

Ich bekomme Datei existiert Fehler. Also, wie kann ich den Ingress auf WAN_INTERFACE gestalten und gleichzeitig den Traffic, der über das ifb0 Device an das LAN geht, mitgestalten?


19
2018-01-15 04:50


Ursprung




Antworten:


IFB ist eine Alternative zu tc-Filtern für die Verarbeitung von Ingress-Datenverkehr, indem es auf eine virtuelle Schnittstelle umgeleitet wird und dort als Egress-Verkehr behandelt wird. Sie benötigen eine ifb-Schnittstelle pro physikalische Schnittstelle, um den eingehenden Datenverkehr von eth0 nach ifb0, eth1 zu ifb1 und so weiter umzuleiten auf.

Wenn Sie das ifb-Modul einfügen, teilen Sie ihm die Anzahl der benötigten virtuellen Schnittstellen mit. Der Standardwert ist 2:

modprobe ifb numifbs=1

Aktivieren Sie nun alle ifb-Schnittstellen:

ip link set dev ifb0 up # repeat for ifb1, ifb2, ...

Und leiten Sie den eingehenden Datenverkehr von den physischen Schnittstellen zur entsprechenden ifb-Schnittstelle um. Für eth0 -> ifb0:

tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

Wiederholen Sie den Vorgang für eth1 -> ifb1, eth2 -> ifb2 usw., bis alle zu formenden Schnittstellen abgedeckt sind.

Jetzt können Sie alle gewünschten Regeln anwenden. Egress-Regeln für eth0 gehen wie gewohnt in eth0. Beschränken wir die Bandbreite, zum Beispiel:

tc qdisc add dev eth0 root handle 1: htb default 10
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1mbit

Unnötig zu sagen, wiederholen für eth1, eth2, ...

Ingress-Regeln für eth0 gehen jetzt als Egress-Regeln auf ifb0 (was immer in ifb0 hineinkommt muss rauskommen, und nur eth0-ingress-Verkehr geht in ifb0). Ein Beispiel für eine Bandbreitenbeschränkung:

tc qdisc add dev ifb0 root handle 1: htb default 10
tc class add dev ifb0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 1mbit

Der Vorteil dieses Ansatzes besteht darin, dass Egress-Regeln viel flexibler sind als Eingangsfilter. Mit Filtern können Sie beispielsweise Pakete löschen und keine Wartezeiten einführen. Indem Sie den Ingress-Verkehr als Egress behandeln, können Sie Warteschlangendisziplinen mit Verkehrsklassen und, falls erforderlich, Filtern einrichten. Sie erhalten Zugriff auf den gesamten TC-Baum, nicht nur einfache Filter.


38
2018-05-07 18:31



Schön gemacht. Immer gut, wenn ein Profi mit einer Rockstar-Erstantwort auftaucht. - Magellan
Das mag eine naive Frage sein, aber ich finde keine spezifischen Informationen. Basierend auf dieser Antwort (die übrigens toll ist), ist es möglich zu bekommen ifb0 Statistiken speziell für eine Cgroup Classid? Das heißt, ich kann die Ausgangsstatistik für eine Kontrollgruppe mit einem Klassidfilter erfolgreich erhalten. Kann aber auch der eingehende Verkehr pro Gruppe berücksichtigt werden? - jdi
Beachten Sie, dass Sie ifb nicht verwenden können, wenn Sie iptable verwenden, um Ihr Paket zu markieren und anschließend zu filtern, da der gesamte Ingress-Verkehr VOR der Markierung weitergeleitet wird. Sie werden also Ihre Klasse bei 0 bleiben lassen und alle zur Standardeinstellung weitergeleitet. IMQ scheint die richtige Lösung für iptables-Benutzer zu sein. - ornoone
@ SérgioCarvalho Ich kann nicht scheinen, dass dies zusammen mit dem net_cls Controller von cgroups funktioniert. Ich bin ein wenig verwirrt, weil ich normalen ausgehenden Netzwerkverkehr (Ausgang) mit net_cls im Tandem mit tc begrenzen kann? Meine beste Vermutung ist, dass für den Fall, dass ifb auf diese Weise verwendet wird, die Egress-Pakete, die aus ifb kommen, nicht richtig markiert werden, seit sie als Ingress begonnen haben? Kann das jemand bestätigen oder einen Weg vorschlagen, den ich kann? - Rooster


Basierend auf der Antwort von Sérgio Carvalho habe ich ein kleines Bash-Skript zur Begrenzung der Bandbreite erstellt:

Dateiname: netspeed

#!/bin/bash 

#USAGE: sudo ./netspeed -l limit_in_kbit -s
usage="sudo $(basename "$0") -l speed_limit -s
  -l speed_limit - speed limit with units (eg. 1mbit, 100kbit, more on \`man tc\`)
  -s - remove all limits
"

# default values
LIMIT=0
STOP=0

# hardcoded constats
IFACE=ifb0 # fake interface name which will be used for shaping the traffic
NETFACE=wlan0 # interface which in connected to the internet

# shift all required and leave only optional

while getopts ':hl:s' option; do
  case "$option" in
   l) LIMIT=$OPTARG
      ;;
   s) STOP=1
      ;;
   h) echo "$usage"
      exit
      ;;
  esac
done

#
# functions used in script
#
function limitExists { # detected by ingress on $NETFACE qdisc
   # -n equals true if non-zero string length
  if [[ -n `tc qdisc show | grep "ingress .* $NETFACE"` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi

}
function ifaceExists {
  # -n equals true if non-zero string length
  if [[ -n `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi
}
function ifaceIsUp {
  # -n equals true if non-zero string length
  if [[ -n `ifconfig | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi
}
function createLimit {
  #3. redirect ingress
  tc qdisc add dev $NETFACE handle ffff: ingress
  tc filter add dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE

  #4. apply egress rules to local inteface (like wlan0)
  tc qdisc add dev $NETFACE root handle 1: htb default 10
  tc class add dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class add dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT

  #5. and same for our relaying virtual interfaces (to simulate ingress)
  tc qdisc add dev $IFACE root handle 1: htb default 10
  tc class add dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class add dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function updateLimit {
  #3. redirect ingress
  tc filter replace dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE

  #4. apply egress rules to local inteface (like wlan0)
  tc class replace dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class replace dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT

  #5. and same for our relaying virtual interfaces (to simulate ingress)
  tc class replace dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class replace dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function removeLimit {
  if limitExists ; then
    tc qdisc del dev $NETFACE ingress
    tc qdisc del dev $NETFACE root
    tc qdisc del dev $IFACE root
  fi
  if ifaceIsUp ; then
    ip link set dev $IFACE down
  fi
}

#
# main script
#
if [[ `whoami` != "root" ]]; then
  echo "WARNING: script must be executed with root privileges!"
  echo $usage
  exit 1
fi
if [ $STOP -eq 1 ]; then
  echo "REMOVING limit"
  removeLimit
  echo "limit REMOVED"
elif [ "$LIMIT" != "0" ]; then
  # prepare interface
  if ! ifaceExists ; then
    echo "CREATING $IFACE by modprobe"
    modprobe ifb numifbs=1
    if ! ifaceExists ; then
      echo "creating $IFACE by modprobe FAILED"
      echo "exit with ERROR code 2"
      exit 2
    fi
  fi
  # set interface up
  if ifaceIsUp ; then
    echo "$IFACE is already up"
  else
    echo "set $IFACE up"
    ip link set dev $IFACE up # ( use ifconfig to see results)
    if ifaceIsUp ; then
      echo "$IFACE is up"
    else
      echo "enabling $IFACE by ip link FAILED"
      echo "exit with ERROR code 3"
      exit 3
    fi
  fi

  # create/update limits
  if limitExists ; then
    echo "update limit"
    updateLimit
  else
    echo "create limit"
    createLimit
  fi

  echo "limit CREATED"
  exit 0
else
  echo $usage
fi

3
2017-07-09 09:09





Sie haben ein einfaches Skript, das es in einem Linux-Router-Box für eingehenden und ausgehenden Verkehr tun:

https://github.com/rfrail3/misc/blob/master/tc/traffic-control.sh


1
2018-02-08 11:44