sábado, 7 de noviembre de 2015

Memorias de un administrador. Control del ancho de banda.



Introducción:



Recomiendo leer un post anterior en el que describo como está estructurada la red en el Centro.


Nuestra conexión a Internet dispone de una velocidad de bajada y subida determinada. Si existen muchas peticiones (atascos) puede darse el caso de que deje responder o que tarde mucho en hacerlo, dando lugar a una navegación por la Web lenta.


 Uno de los mayores problemas al que me enfrenté fue el de controlar el ancho de banda de la salida a Internet para que tanto profesores como alumnos pudieran navegar de forma decente.

Por defecto, las tarjetas de red utilizan una cola pfifo_fast que lo que hace es que el primer paquete que llega es el primer paquete que sale. Pero ¿ qué pasa con el tipo de paquete...? Esta cola no lo tiene en cuenta, y para mi es deseable dar prioridad al tráfico web que al tráfico ftp, por ejemplo.

Además no distribuye el ancho de banda entre las diferentes redes del Centro. Por lo tanto puede darse el caso que un alumno empieza a descargar una imagen y obtenga mucho ancho de banda, dejando al resto del centro con una velocidad muy pequeña.

Cabe indicar que el ordenador que da acceso a Internet al Centro (de nombre VPROXY) tiene un S.O. Linux Ubuntu 14.04 y dispone de dos tarjetas de red (una para la red interna y otra conectada a Internet). 

También dispone de un proxy SQUID configurado para dar servicio al tráfico http (puerto 80) y poder hacer uso de la caché para tener una navegación más rápida.


El equipo VProxy tiene añadidas a la Iptables las siguientes líneas:
#INTERNA
IFACEIN=eth0
#EXTERNA
IFACEOUT=eth1

modprobe ip_nat_ftp
#// Activar el enrutamiento en un sistema Linux
echo "1" > /proc/sys/net/ipv4/ip_forward

 
#SQUID
iptables -t nat -A PREROUTING -i ${IFACEIN} -p tcp --dport 80 -j REDIRECT --to-ports 3128
# SALIMOS CON LA IP EXTERNA

iptables -t nat -A POSTROUTING -o ${IFACEOUT} -j MASQUERADE

Como vemos, todo lo que se dirige al puerto 80 es redirigido al puerto 3128 del proxy. Este tipo de proxy es transparente de tal forma que los equipos clientes no tienen que configurar nada para poder salir a través del proxy. Simplemente se cambia el gateway para que apunte al proxy (en nuestro Centro eso lo hace el Switch HP de nivel 3 que tenemos).
 
La IP que sale a Internet del equipo VProxy es la de la tarjeta externa (MASQUERADE).

Cabe indicar que con el SQUID también se puede realizar el control del ancho de banda, pero dicho control no tiene en cuenta el tipo de tráfico y sólo se limita al tráfico web (dirigido al puerto 80).


Direcciones IP:

Las aulas están en una red 192.168.XX.YY siendo:

  • XX: El número de aula.
  • YY: El número de equipo.

Por ejemplo: 192.168.1.10, sería el equipo 10 del aula1.


Cabe señalar que todas las aulas están conectadas a un switch HP 3500yl de nivel 3, de tal forma que cada boca del switch lo he configurado para atender a un aula/departamento a nivel de red, no de Mac. Es decir, he habilitado el enrutamiento en el switch.

Así, la boca del switch que está conectada al Aula1 tiene una ip en el switch 192.168.1.250 y está configurada para pedir los datos al DHCP en el ámbito de esta red (192.168.1.0/255.255.255.0). Explicaremos esto en otra entrada posterior.

El Gateway que tiene cada aula es la boca IP del switch, así el aula 1 (192.168.1.X) tiene como gateway la ip 192.168.1.250.
A su vez, el Switch tiene como gateway predeterminado la dirección 172.30.1.1 que se corresponde con el equipo virtualizado VPROXY explicado a continuación....




Servidor Virtualizado: VPROXY

 


Enruta los paquetes desde la red interna (192.168.0.0/255.255.0.0) a la red conectada a Internet. Partimos de la base de que ya está configurado para enrutar el tráfico.

Dispone de dos tarjetas de red:
  • eth1: 69.57.157.200 (red externa)
  • eht0: 172.30.128.1 (red interna)
A la red Interna llegan los paquetes a través del switch HP 3500yl que hace la labor de 'enrutador' y por eso recibe paquetes de las aulas (red 192.168.NUM_AULA.NUM_EQUIPO). En un caso 'normal' tendréis los equipos en la misma red que la tarjeta interna del proxy.

Este artículo no va a tratar en cómo se configura un Proxy-SQUID en Linux. Para eso disponéis de múltiples entradas en Internet.

Partimos por lo tanto que ya tenéis instalado y configurado el proxy SQUID (puerto 3128).

El problema que tenía de utilizar este software es la gestión del ancho de banda. Y sí, el squid tiene esa función, pero sólo afecta al tráfico http, no teniendo en cuenta el resto del tráfico.

Control del ancho de banda


Para solucionar el problema leí por internet un manual sobre la gestión del tráfico utilizando colas de prioridad.

En resumidas cuentas, podemos configurar en la tarjeta de red diferentes colas de prioridad en las que definimos la velocidad de bajada/subida y la velocidad de bajada/subida máxima. Estas colas estás asociadas a clases las cuales pueden tener un ancho de banda diferente en base a diferentes criterios, como puertos, direcciones IP, tipo de tráfico....

Así, puedo definir por cada aula, que tenga una velocidad de bajada de 1Mbps y en caso de que haya ancho de banda, llegar hasta 5Mbps. Estas colas van a afectar a todo el tráfico que pase por la tarjeta, con lo que solucionamos el problema del SQUID. Las colas de prioridad veremos que las definiremos sobre la tarjeta interna, por el problema de que el tráfico que viene de fuera y llega a la red externa estará 'enmascarado' con la dirección IP del Proxy SQUID.

Cabe señalar que las colas de prioridades no conocen lo que te vas a descargar, por lo que la limitación del ancho de banda la realizan en base al descarte de paquetes.

A continuación os dejo el script que tengo, basado en varios encontrados por Internet, pero de los que no guardo el enlace original ya que lo hice hace bastante tiempo:

Este es el script que tenía en un principio. Comentar que el ancho de banda (parámetro rate de las colas) reservado a cada red es el resultado de dividir el ancho de banda total entre el número de redes. De esta forma, cada red (aula - departamento) tendrá un mínimo ancho de banda garantizado

Nota:  Mirar actualización del script a continuación.

RED.sh:

#!/bin/bash
# INTERFACE EXTERNA CONECTADA A INTERNET
IFACE=eth1
#INTERFACE INTERNAS: ALUMNOS
IFACEIN=eth0
# IP SQUID EXTERNA
IPSQUID=69.57.157.249
# En kbits . 1mbps = 1024 Kilo bit por segundo
VELOCIDAD_BAJADA=81920  

VELOCIDAD_REDSERVIDORES=1024
VELOCIDAD_SUBIDA_SQUID=7168

#Velocidad de Bajada
VELOCIDAD_MAXIMA_ALUMNOS=8 # en Mbps
VELOCIDAD_MAXIMA_SERVIDORES=4


#NUMERO DE REDES PARA DIVIDIR EL ANCHO DE BANDA DE BAJADA
# Formato red: ALUMNOS => 192.168.X ; 
REDES_ALUMNOS=( 1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 50 51 52 53 54 55 56 57 )
NUMREDES_ALUMNOS=${#REDES_ALUMNOS[@]} 
NUMREDES_TOTAL=$[$NUMREDES_ALUMNOS + 1] # RED SERVIDORES




# BORRAMOS LAS COLAS
tc qdisc del dev ${IFACE} root
tc qdisc del dev ${IFACE} ingress
# CREAMOS LAS COLAS
tc qdisc add dev ${IFACE} root handle 1: htb default 99
tc class add dev ${IFACE} parent 1: classid 1:1 htb rate ${VELOCIDAD_SUBIDA_SQUID}kbit ceil ${VELOCIDAD_SUBIDA_SQUID}kbit

#TRAFICO WEB el de mayor prioridad
tc class add dev ${IFACE} parent 1:1 classid 1:10 htb rate $[$VELOCIDAD_SUBIDA_SQUID*60/100]kbit ceil ${VELOCIDAD_SUBIDA_SQUID}kbit prio 1
#TRAFICO WEB SEGURO, DROPBOX Y RESTO
tc class add dev ${IFACE} parent 1:1 classid 1:20 htb rate $[$VELOCIDAD_SUBIDA_SQUID*30/100]kbit ceil $[$VELOCIDAD_SUBIDA_SQUID*60/100]kbit prio 2
#TRAFICO FTP
tc class add dev ${IFACE} parent 1:1 classid 1:30 htb rate $[$VELOCIDAD_SUBIDA_SQUID*10/100]kbit ceil $[$VELOCIDAD_SUBIDA_SQUID*40/100]kbit prio 3


# Hacemos sfq para que se reparta entre todos y nadie cope todo el ancho de banda
tc qdisc add dev ${IFACE} parent 1:10 handle 100: sfq perturb 10
tc qdisc add dev ${IFACE} parent 1:20 handle 200: sfq perturb 10
tc qdisc add dev ${IFACE} parent 1:30 handle 300: sfq perturb 10


#Mandamos por la de mas capacidad el icmp, web
iptables -F -t mangle

# EN EL SQUID SOLO EL TRAFICO WEB. COMO HACE NAT SIEMPRE SALE CON LA DIRECCION EXTERNA. 
# 443 ES EL QUE USA DROPBOX
iptables -t mangle -A POSTROUTING -p tcp -m tcp --dport 443 -j CLASSIFY --set-class 1:20
iptables -t mangle -A POSTROUTING -p tcp -m tcp --dport 443 -j RETURN# FTP
iptables -t mangle -A POSTROUTING -p tcp -m tcp --dport 20:21 -j CLASSIFY --set-class 1:30
iptables -t mangle -A POSTROUTING -p tcp -m tcp --dport 20:21 -j RETURN
iptables -t mangle -A POSTROUTING -o ${IFACE} -j CLASSIFY --set-class 1:10
iptables -t mangle -A POSTROUTING -o ${IFACE} -j RETURN

#############################################DESCARGA#######################################
#############################################ALUMNOS######################################
tc qdisc del dev ${IFACEIN} root
tc qdisc add dev ${IFACEIN} root handle 1:0 htb default 99
tc class add dev ${IFACEIN} parent 1:0 classid 1:1 htb rate ${VELOCIDAD_BAJADA}kbit ceil ${VELOCIDAD_BAJADA}kbit


for RED in ${REDES_ALUMNOS[@]}
do

    CLASS=${RED}
    # TEMOS UN PROBLEMA COA REDE 1
    if [ ${RED} -eq 1 ]
    then
       CLASS=100
    fi
 
  tc class add dev ${IFACEIN} parent 1:1 classid 1:${CLASS} htb rate $[$VELOCIDAD_BAJADA/$NUMREDES_TOTAL]kbit ceil ${VELOCIDAD_MAXIMA_ALUMNOS}Mbit prio 2 
  tc qdisc add dev ${IFACEIN} parent 1:${CLASS} handle $[$CLASS+200]: sfq perturb 10

  iptables -t mangle -A POSTROUTING -p tcp -d 192.168.${RED}.0/24 -j CLASSIFY --set-class 1:${CLASS}
  iptables -t mangle -A POSTROUTING -p tcp -d 192.168.${RED}.0/24 -j RETURN

  iptables -t mangle -A POSTROUTING -p udp -d 192.168.${RED}.0/24 -j CLASSIFY --set-class 1:${CLASS}
  iptables -t mangle -A POSTROUTING -p udp -d 192.168.${RED}.0/24 -j RETURN
done

#############################################SERVIDORES###################################### 
#REDE DE SERVIDORES
  tc class add dev ${IFACEIN} parent 1:1 classid 1:600 htb rate ${VELOCIDAD_REDSERVIDORES}kbit ceil ${VELOCIDAD_MAXIMA_SERVIDORES}Mbit prio 2
  tc qdisc add dev ${IFACEIN} parent 1:600 handle 700: sfq perturb 10

  iptables -t mangle -A POSTROUTING -p tcp -d 172.30.0.0/16 -j CLASSIFY --set-class 1:600
  iptables -t mangle -A POSTROUTING -p tcp -d 172.30.0.0/16 -j RETURN
  iptables -t mangle -A POSTROUTING -p udp -d 172.30.0.0/16 -j CLASSIFY --set-class 1:600
  iptables -t mangle -A POSTROUTING -p udp -d 172.30.0.0/16 -j RETURN


#POR DEFECTO PARA LA NO CLASIFICADA

tc class add dev ${IFACEIN} parent 1:1 classid 1:99 htb rate 500kbit ceil 1Mbit prio 3
tc qdisc add dev ${IFACEIN} parent 1:99 handle 99: sfq perturb 10


============ACTUALIZADO A NOVIEMBRE DEL 2015==============


Buscando por Internet como controlar el ancho  de banda de las conexiones de subida, encontré esto: https://github.com/firehol/firehol/wiki

Resulta que es una herramienta que actúa igual que el script que hice anteriormente, pero de una forma más intuitiva.

Lo que más me llevó tiempo fue entender que:

  • Necesita aplicar las colas a la interface interna, ya que por el mascarade del Iptables las direcciones llegan desde fuera teniendo como destino la IP pública del equipo VPROXY y no las direcciones ip´s internas.
  • Al aplicar las reglas sobre la red interna, el tráfico de bajada se aplica sobre la cola de SALIDA de la interface interna y las IP´s a controlar serán las internas y por lo tanto la de DESTINO.
                 interface $DEVICEIN world-in ouput rate $VELOCIDAD_BAJADA minrate 

          Y para controlar el tráfico de bajada de un aula tendré que poner:

             class group departamento1 rate 1000 ceil 5000 prio 1 balanced
                     match dst 192.168.2.0/24    # Aula 2
 
Fijarse que pongo destino ya que los paquetes vienen de fuera hacia dentro (por lo tanto es tráfico de bajada) y se dirigen a la IP interna.
 Esta línea lo que hace básicamente es crear una cola para todo el tráfico que vaya a 192.168.2.X dando un ancho de banda de 1000kbps y siempre que haya un ancho de banda disponible aumentar el tráfico a 5000Kbps.

  • El tráfico de subida se aplica sobre la cola de ENTRADA de la interface interna
    interface $DEVICEIN world-out input rate $VELOCIDAD_SUBIDA minrate 


Aquí os deje el script tal cual está, guardado en el directorio /etc/firehol

SCRIPT fireqos.conf

#!/bin/bash
# INTERFACE EXTERNA CONECTADA A INTERNET
DEVICEOUT=eth1
#INTERFACE INTERNA
DEVICEIN=eth0
# En kbits . 1mbps = 1024 Kilo bit por segundo
VELOCIDAD_BAJADA=100000   # No test de velocidade daba sobre 60
VELOCIDAD_SUBIDA=12000

# VELOCIDAD MAXIMA BAJADA SERVIDORES
VELOCIDAD_RED_SERVIDORES=2048

# VELOCIDADE DE BAJADA MAXIMA PARA ALUMNOS

VELOCIDAD_MAXIMA_ALUMNOS=12000 # en kbps

# VELOCIDADE DE BAJADA MAXIMA PARA SERVIDORES

VELOCIDAD_MAXIMA_SERVIDORES=4000

# VELOCIDADE DE SUBIDA MAXIMA PARA ALUMNOS

VELOCIDAD_MAXIMA_SUBIDA=1500


#NUMERO DE REDES PARA DIVIDIR EL ANCHO DE BANDA DE BAJADA
REDES_ALUMNOS=( 1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 50 51 52 53 54 55 56 57 )
NUMREDES_ALUMNOS=${#REDES_ALUMNOS[@]}
NUMREDES_TOTAL=$[$NUMREDES_ALUMNOS +1]  # RED DE SERVIDORES

PORCENTAJE_maspequeno=5/100
   # Por el minrate. No puede ser más grande que el menor ancho de banda

##################################BAJADA######################################## 

interface $DEVICEIN world-in ouput rate $VELOCIDAD_BAJADA minrate $[($VELOCIDAD_BAJADA/$NUMREDES_TOTAL)*$PORCENTAJE_maspequeno] balanced

      class group servidores rate 500Kbit  ceil ${VELOCIDAD_RED_SERVIDORES} prio 1  balanced
      match dst 172.30.1.0/24
      class interactive                 commit 50%
         match udp port 53             # <<< DNS
         match icmp                    # <<< ping
      class synacks                     commit 20%      # <<< the new synacks class
         match tcp syn                    # <<< TCP packets with SYN set
         match tcp ack                    # <<< small TCP packets with ACK set

    class group end

for RED in ${REDES_ALUMNOS[@]}
do

    class group aula${RED} rate $[$VELOCIDAD_BAJADA/$NUMREDES_TOTAL] ceil ${VELOCIDAD_MAXIMA_ALUMNOS} prio 1 balanced
      match dst 192.168.${RED}.0/24
      class interactive                 commit 10%
         match udp port 53             # <<< DNS
         match tcp port 22             # <<< SSH
         match icmp                    # <<< ping
      class surfing                     commit 40%
         match tcp sport 80
      class surfing_seguro        commit 30%
     match tcp sport 443       
      class synacks                     commit 5%      # <<< the new synacks class
         match tcp syn                    # <<< TCP packets with SYN set
         match tcp ack                    # <<< small TCP packets with ACK set

    class group end


done


##################################SUBIDA########################################
interface $DEVICEIN world-out input rate $VELOCIDAD_SUBIDA minrate $[($VELOCIDAD_SUBIDA/$NUMREDES_TOTAL)*$PORCENTAJE_
maspequeno]  balanced

   class group servidores rate 256  ceil ${VELOCIDAD_MAXIMA_SUBIDA}  prio 1 balanced
     match src 172.30.1.0/24
      class interactive                 commit 60%
         match udp port 53             # <<< DNS
         match icmp                    # <<< ping
      class synacks                     commit 10%      # <<< the new synacks class
         match tcp syn                    # <<< TCP packets with SYN set
         match tcp ack                    # <<< small TCP packets with ACK set


   class group end


for RED in ${REDES_ALUMNOS[@]}
do

    class group aula{RED} rate $[$VELOCIDAD_SUBIDA/$NUMREDES_TOTAL] ceil ${VELOCIDAD_MAXIMA_SUBIDA} prio 1 balanced
      match src 192.168.${RED}.0/24
      class surfing                     commit 45%
         match tcp dports 80
      class surfing_seguro        commit 30%
         match tcp dports 443
      class synacks                     commit 15%      # <<< the new synacks class
         match udp port 53             # <<< DNS
         match icmp                    # <<< ping
         match tcp port 22             # <<< SSH
         match tcp syn                    # <<< TCP packets with SYN set
         match tcp ack                    # <<< small TCP packets with ACK set

    class group end


done

Para iniciar las colas pondremos:
  • fireqos.in start
Para parar:
  • fireqos.in stop




Añadimos una entrada al archivo /etc/rc.local (al final de todo) para lanzar este script...


Espero que os haya servido de ayuda.
Hasta la siguiente entrada.

No hay comentarios:

Publicar un comentario