Tc: sorveglianza degli ingressi e mirroring ifb


20

Sto cercando di configurare il traffic shaping su un gateway Linux come scritto qui . Lo script deve essere personalizzato perché ho più interfacce LAN. Quindi, per modellare il lato LAN, sto pianificando di creare uno pseudo dispositivo ifb in questo modo:

     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

La sceneggiatura del repository gist di cui sopra ha queste righe:

 /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

Questo codice e il codice di creazione dell'interfaccia ifb non vanno d'accordo. Lo script personalizzato viene eseguito, ma il dispositivo ifb0 non mostra alcuna statistica del traffico. Se commento il codice repository gist in ingresso (citato sopra), il dispositivo ifb0 mostra il numero di pacchetti che vengono trasferiti. Inoltre, queste righe non possono essere eseguite insieme:

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

Ottengo errore di file esiste. Quindi, come posso modellare l'ingresso su WAN_INTERFACE e allo stesso tempo anche modellare il traffico che va alla LAN tramite il dispositivo ifb0?

Risposte:


41

IFB è un'alternativa ai filtri tc per la gestione del traffico in ingresso, reindirizzandolo a un'interfaccia virtuale e trattando è un traffico in uscita lì. È necessaria un'interfaccia ifb per interfaccia fisica, per reindirizzare il traffico in ingresso da eth0 a ifb0, da eth1 a ifb1 e così via su.

Quando si inserisce il modulo ifb, indicare il numero di interfacce virtuali necessarie. L'impostazione predefinita è 2:

modprobe ifb numifbs=1

Ora abilita tutte le interfacce ifb:

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

E reindirizza il traffico in ingresso dalle interfacce fisiche all'interfaccia ifb corrispondente. Per 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

Ancora una volta, ripetere per eth1 -> ifb1, eth2 -> ifb2 e così via, fino a coprire tutte le interfacce che si desidera modellare.

Ora puoi applicare tutte le regole che desideri. Le regole di uscita per eth0 vanno come al solito in eth0. Limitiamo la larghezza di banda, ad esempio:

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

Inutile dire che ripeti per eth1, eth2, ...

Regole di ingresso per eth0, ora vai come regole di uscita su ifb0 (qualunque cosa entri in ifb0 deve venire fuori, e solo il traffico in ingresso eth0 entra in ifb0). Ancora una volta, un esempio di limite di larghezza di banda:

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

Il vantaggio di questo approccio è che le regole di uscita sono molto più flessibili dei filtri di ingresso. I filtri consentono solo di eliminare i pacchetti, non introdurre i tempi di attesa, ad esempio. Gestendo il traffico in entrata come uscita è possibile impostare le discipline della coda, con classi di traffico e, se necessario, filtri. Puoi accedere all'intero albero di tc, non solo a semplici filtri.


Ben fatto. Sempre bello vedere un professionista spuntare con una prima risposta da rockstar.
Magellan,

Questa potrebbe essere una domanda ingenua, ma non riesco a trovare informazioni specifiche. Sulla base di questa risposta (che è eccezionale tra l'altro), è possibile ottenere ifb0statistiche specifiche per un cid classid? Cioè, posso ottenere con successo le statistiche di uscita per un cgroup con un filtro classid. Ma il traffico in entrata può anche essere contabilizzato su una base per cgroup?
jdi

tenere presente che se si utilizza iptable per contrassegnare il pacchetto e quindi li filtra, non è possibile utilizzare ifb poiché tutto il traffico in ingresso verrà inoltrato PRIMA di qualsiasi contrassegno. quindi vedrai la tua classe rimanere a 0 e tutti inoltrati al valore predefinito. IMQ sembra la soluzione giusta per gli utenti di iptables.
Ornoone,

@ SérgioCarvalho Non riesco a farlo funzionare in tandem con il controller net_cls di cgroups. Sono un po 'confuso, perché posso limitare il normale traffico di rete in uscita (uscita) usando net_cls in tandem con tc? La mia ipotesi migliore è che per somereason si usi ifb in questo modo che i pacchetti di uscita che escono da ifb non vengono taggati correttamente da quando hanno iniziato come ingress? Qualcuno può confermare questo o suggerire un modo che posso?
Gallo,

3

Basato sulla risposta di Sérgio Carvalho, ho realizzato un piccolo script bash per limitare la larghezza di banda:

Nome file: 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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.