Tc : 수신 정책 및 ifb 미러링


20

여기에 작성된 것처럼 Linux 게이트웨이에서 트래픽 쉐이핑을 설정하려고합니다 . 여러 개의 LAN 인터페이스가 있으므로 스크립트를 사용자 정의해야합니다. 따라서 LAN 쪽을 형성하기 위해 ifb 의사 장치를 다음과 같이 만들 계획입니다.

     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

위에서 언급 한 요지 리포지토리의 스크립트는 다음과 같습니다.

 /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

이 코드와 ifb 인터페이스 작성 코드는 서로 잘 어울리지 않습니다. 사용자 정의 스크립트가 실행되지만 ifb0 장치에는 트래픽 통계가 표시되지 않습니다. 위에서 인용 한 수신 gist repo 코드를 주석 처리하면 ifb0 장치에 전송 된 패킷 수가 표시됩니다. 또한이 줄들은 함께 실행할 수 없습니다 :

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

파일에 오류가 있습니다. 그렇다면 어떻게 WAN_INTERFACE에서 수신을 형성하고 동시에 ifb0 장치를 통해 LAN으로가는 트래픽을 형성 할 수 있습니까?

답변:


41

IFB는 수신 트래픽을 가상 인터페이스로 리디렉션하여 수신 트래픽을 처리하기위한 tc 필터의 대안이며, 송신 트래픽으로 간주합니다. 물리적 인터페이스 당 하나의 ifb 인터페이스가 필요합니다. 에.

ifb 모듈을 삽입 할 때 필요한 가상 인터페이스 수를 알려주십시오. 기본값은 2입니다.

modprobe ifb numifbs=1

이제 모든 ifb 인터페이스를 활성화하십시오 :

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

물리적 인터페이스에서 해당 ifb 인터페이스로 수신 트래픽을 리디렉션합니다. 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

다시, eth1-> ifb1, eth2-> ifb2 등을 반복하여 형성하려는 모든 인터페이스가 덮일 때까지 반복하십시오.

이제 원하는 모든 규칙을 적용 할 수 있습니다. eth0의 송신 규칙은 eth0에서 평소대로 진행됩니다. 예를 들어 대역폭을 제한합시다.

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

말할 필요도없이 eth1, eth2, ...

eth0에 대한 수신 규칙, 이제 ifb0에 대한 송신 규칙으로 이동합니다 (ifb0에 들어가는 모든 것이 나오고 eth0 수신 트래픽 만 ifb0에 들어갑니다). 다시, 대역폭 제한 예 :

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

이 방법의 장점은 송신 규칙이 수신 필터보다 훨씬 유연하다는 것입니다. 필터는 예를 들어 대기 시간을 도입하지 않고 패킷을 삭제할 수만 있습니다. 수신 트래픽을 송신으로 처리하면 트래픽 클래스 및 필요한 경우 필터를 사용하여 큐 규칙을 설정할 수 있습니다. 간단한 필터뿐만 아니라 전체 TC 트리에 액세스 할 수 있습니다.


잘 했어요 록 스타의 첫 번째 답변이 나오는 전문가를 만나는 것이 좋습니다.
마젤란

이것은 순진한 질문 일지 모르지만 특정 정보를 찾지 못했습니다. 이 답변 (btw가 큰)을 기반으로 ifb0cgroup classid에 대한 통계 를 얻을 수 있습니까? 즉, classid 필터를 사용하여 cgroup에 대한 송신 통계를 성공적으로 얻을 수 있습니다. 그러나 들어오는 트래픽도 cgroup 단위로 설명 할 수 있습니까?
jdi

iptable을 사용하여 패킷을 표시 한 다음 필터링하면 모든 수신 트래픽이 표시 전에 전달되므로 ifb를 사용할 수 없습니다. 따라서 클래스를 0으로 유지하고 모두 기본값으로 전달합니다. IMQ는 iptables 사용자를위한 rigth 솔루션 인 것 같습니다.
ornoone

@ SérgioCarvalho 나는 cgroups의 net_cls 컨트롤러와 함께 작동하도록 할 수없는 것 같습니다. tc와 함께 net_cls를 사용하여 정상적인 발신 네트워크 트래픽 (탈출)을 제한 할 수 있기 때문에 약간 혼란 스럽습니까? 가장 좋은 추측은 ifb를 사용하여 ifb에서 나오는 송신 패킷이 수신으로 시작한 이후 올바르게 태그가 지정되지 않는 ifb를 사용하는 것입니다. 누구든지 이것을 확인하거나 내가 할 수있는 방법을 제안 할 수 있습니까?
Rooster

3

Sérgio Carvalho의 답변에 따라 대역폭을 제한하기 위해 작은 bash 스크립트를 만들었습니다.

파일 이름 : 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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.