TC: Giriş polisliği ve ifb yansıtma


20

Burada yazıldığı gibi bir Linux ağ geçidinde trafik şekillendirme kurmaya çalışıyorum . Birden fazla LAN arabirimim olduğu için komut dosyasının özelleştirilmesi gerekiyor. LAN tarafı şekillendirmek için ben böyle bir ifb sözde aygıt oluşturmayı planlıyorum:

     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

Yukarıda belirtilen özgeçmiş repo betiği şu satırlara sahiptir:

 /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

Bu kod ve ifb arayüzü oluşturma kodu birlikte iyi anlaşamıyor. Özelleştirilmiş komut dosyası yürütülür, ancak ifb0 cihazında trafik istatistikleri gösterilmez. Giriş gist repo kodunu (yukarıda alıntılanır) yorumlarsam, ifb0 cihazı aktarılan paket sayısını gösterir. Ayrıca bu satırlar birlikte yürütülemez:

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

Dosya var hatası alıyorum. Peki, WAN_INTERFACE'e girişi nasıl şekillendirebilirim ve aynı zamanda ifb0 cihazı aracılığıyla LAN'a giden trafiği de şekillendirebilirim?

Yanıtlar:


41

IFB, giriş trafiğini işlemek için tc filtrelerine bir alternatiftir ve bunu sanal bir arayüze yönlendirir ve tedavi, oradaki çıkış trafiği gibidir. üzerinde.

İfb modülünü yerleştirirken, ihtiyacınız olan sanal arabirim sayısını söyleyin. Varsayılan 2'dir:

modprobe ifb numifbs=1

Şimdi tüm ifb arayüzlerini etkinleştirin:

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

Ve giriş trafiğini fiziksel arayüzlerden karşılık gelen ifb arayüzüne yönlendirin. Eth0 -> ifb0 için:

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

Yine, şekillendirmek istediğiniz tüm arabirimler kaplanana kadar eth1 -> ifb1, eth2 -> ifb2 vb. İçin tekrarlayın.

Şimdi, istediğiniz tüm kuralları uygulayabilirsiniz. Eth0 için ilerleme kuralları eth0'da her zamanki gibi geçerlidir. Bant genişliğini sınırlayalım, örneğin:

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

Söylemeye gerek yok, eth1, eth2, için tekrarlayın ...

Eth0 için giriş kuralları, şimdi ifb0 üzerinde çıkış kuralları olarak gidin (ifb0'a giren her şey ortaya çıkmalı ve sadece eth0 giriş trafiği ifb0'a girer). Yine, bir bant genişliği sınırı örneği:

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

Bu yaklaşımın avantajı çıkış kurallarının giriş filtrelerinden çok daha esnek olmasıdır. Filtreler örneğin paketleri bırakmanıza izin verir, örneğin bekleme süreleri getirmez. Giriş trafiğini çıkış olarak ele alarak, trafik sınıfları ve gerekirse filtreler içeren kuyruk disiplinleri ayarlayabilirsiniz. Sadece basit filtrelere değil, tüm tc ağacına erişebilirsiniz.


Güzel yapılmış. Her zaman profesyonel bir rock yıldızı ilk cevap ile haşhaş görmek iyi.
Magellan

Bu naif bir soru olabilir, ancak belirli bilgileri bulamıyorum. Bu cevaba dayanarak (ki bu harika bir btw), ifb0özellikle bir cgroup sınıf kimliği için istatistik almak mümkün mü? Yani, bir classid filtreli bir grup için çıkış istatistiklerini başarıyla alabilirim. Ancak gelen trafik de grup başına hesaplanabilir mi?
jdi

paketinizi işaretlemek için iptable kullanıyorsanız ve ardından filtrelerseniz, tüm giriş trafiğinin herhangi bir işaretlemeden ÖNCE yönlendirileceğinden ifb'yi kullanamayacağınızı unutmayın. böylece sınıfınızın 0'da kalacağını ve varsayılan olarak yönlendirileceğini göreceksiniz. IMQ iptables kullanıcıları için sağlam bir çözüm gibi görünüyor.
ornoone

@ SérgioCarvalho Ben bunu cgroups net_cls denetleyicisi ile birlikte çalışmak için elde edemiyor gibi görünüyor. Ben tc ile birlikte net_cls kullanarak normal giden ağ trafiğini (çıkış) sınırlayabilir, çünkü biraz kafam karıştı? Benim en iyi tahminim ifb bu şekilde kullanarak ifb ifres çıkan çıkış paketlerinin giriş olarak başladığından beri düzgün etiketlenmemiş olmasıdır? Herkes bunu onaylayabilir veya yapabileceğim bir yol önerebilir mi?
Horoz

3

Sérgio Carvalho cevabına dayanarak bant genişliğini sınırlamak için küçük bash betiği yaptım:

Dosya adı: 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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.