miércoles, 6 de abril de 2011

Solucionando error en Xen "received packet with own address as source address"

Hola ciberamigos... hoy me encontre con un problema un poco extraño en dos de mis VM en Xen. Un error que decia asi:

vif 0.0: received packet with own address as source address

Esto se debe a un problema con CentOS y la instalacion de Xen, el encontrarse dos o mas maquinas con Dom0 en la misma red. Supongamos que el equipo A recibe broadcast del equipo B, y este ve que esta recibiendo un paquete con su misma mac address (o algo asi, la verdad no entendi bien, no estudie ccna (?!!?!?))

Buscando y buscando encontre la solucion gracias a un tal Cyrus Katrak, asi que los creditos son para el.

se debe reemplazar el archivo /etc/xen/scripts/network-bridge por el siguiente

#!/bin/bash
#============================================================================
# Default Xen network start/stop script.
# Xend calls a network script when it starts.
# The script name to use is defined in /etc/xen/xend-config.sxp
# in the network-script field.
#
# This script creates a bridge (default xenbr${vifnum}), adds a device
# (default eth${vifnum}) to it, copies the IP addresses from the device
# to the bridge and adjusts the routes accordingly.
#
# If all goes well, this should ensure that networking stays up.
# However, some configurations are upset by this, especially
# NFS roots. If the bridged setup does not meet your needs,
# configure a different script, for example using routing instead.
#
# Usage:
#
# network-bridge (start|stop|status) {VAR=VAL}*
#
# Vars:
#
# vifnum Virtual device number to use (default 0). Numbers >=8
# require the netback driver to have nloopbacks set to a
# higher value than its default of 8.
# bridge The bridge to use (default xenbr${vifnum}).
# netdev The interface to add to the bridge (default eth${vifnum}).
# antispoof Whether to use iptables to prevent spoofing (default no).
#
# Internal Vars:
# pdev="p${netdev}"
# vdev="veth${vifnum}"
# vif0="vif0.${vifnum}"
#
# start:
# Creates the bridge
# Copies the IP and MAC addresses from netdev to vdev
# Renames netdev to be pdev
# Renames vdev to be netdev
# Enslaves pdev, vdev to bridge
#
# stop:
# Removes netdev from the bridge
# Transfers addresses, routes from netdev to pdev
# Renames netdev to vdev
# Renames pdev to netdev
# Deletes bridge
#
# status:
# Print addresses, interfaces, routes
#
#============================================================================

#macid is used to uniquely identify this dom0 on this network
#change this to avoid MAC address conflicts if you get:
#"peth0: received packet with own address as source address"
macid="F0"

dir=$(dirname "$0")
. "$dir/xen-script-common.sh"
. "$dir/xen-network-common.sh"

findCommand "$@"
evalVariables "$@"

vifnum=${vifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')}
vifnum=${vifnum:-0}
bridge=${bridge:-xenbr${vifnum}}
netdev=${netdev:-eth${vifnum}}
antispoof=${antispoof:-no}

pdev="p${netdev}"
vdev="veth${vifnum}"
vif0="vif0.${vifnum}"

get_ip_info() {
addr_pfx=`ip addr show dev $1 | egrep '^ *inet' | sed -e 's/ *inet //' -e 's/ .*//'`
gateway=`ip route show dev $1 | fgrep default | sed 's/default via //'`
}

do_ifup() {
if ! ifup $1 ; then
if [ ${addr_pfx} ] ; then
# use the info from get_ip_info()
ip addr flush $1
ip addr add ${addr_pfx} dev $1
ip link set dev $1 up
[ ${gateway} ] && ip route add default via ${gateway}
fi
fi
}

# Usage: transfer_addrs src dst
# Copy all IP addresses (including aliases) from device $src to device $dst.
transfer_addrs () {
local src=$1
local dst=$2
# Don't bother if $dst already has IP addresses.
if ip addr show dev ${dst} | egrep -q '^ *inet ' ; then
return
fi
# Address lines start with 'inet' and have the device in them.
# Replace 'inet' with 'ip addr add' and change the device name $src
# to 'dev $src'.
ip addr show dev ${src} | egrep '^ *inet ' | sed -e "
s/inet/ip addr add/
s@\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/[0-9]\+\)@\1@
s/${src}/dev ${dst}/
" | sh -e
# Remove automatic routes on destination device
ip route list | sed -ne "
/dev ${dst}\( \|$\)/ {
s/^/ip route del /
p
}" | sh -e
}

# Usage: transfer_routes src dst
# Get all IP routes to device $src, delete them, and
# add the same routes to device $dst.
# The original routes have to be deleted, otherwise adding them
# for $dst fails (duplicate routes).
transfer_routes () {
local src=$1
local dst=$2
# List all routes and grep the ones with $src in.
# Stick 'ip route del' on the front to delete.
# Change $src to $dst and use 'ip route add' to add.
ip route list | sed -ne "
/dev ${src}\( \|$\)/ {
h
s/^/ip route del /
P
g
s/${src}/${dst}/
s/^/ip route add /
P
d
}" | sh -e
}


##

Reiniciar el equipo y listo, solucionado!

viernes, 1 de abril de 2011

Cluster de Alta disponibilidad con LVS (Linux Virtual Server)

Alta disponibilidad de servicios con LVS (Linux Virtual Server)

Hola amiguitos virtuales(?).Hoy les voy a mostrar como hice para configurar un cluster de alta disponibilidad de Apache. Tambien se puede hacer de otros servicios (FTP, Telnet, etc).

La estructura de funcionamiento es la siguiente; hay uno o mas balanceadores o directores que comparten una ip virtual que es la que presta servicio, es decir que los clientes se conectan a una ip, supongamos 192.168.10.27. Esta seria la ip virtual, los equipos directores tienen 2 direcciones ip, la real (que no se comparte, supongamos 192.168.10.23) y la virtual que se comparte con los demas directores del servicio.
Se completa la configuracion con dos servidores Apache (en este caso son dos, pueden ser mas).
Hay distintos tipos de ruteo en lvs, en este caso use Direct Routing porque tengo todo en la misma red, de otro modo habria que usar NAT.

En mi caso son dos directores y dos apache. Los cuatro equipos tienen CentOS, asi que esta guia es valida para CentOS / Red Hat / Fedora, aunque conceptualmente es lo mismo en cualquier linux, salvo la herramienta para configurar el cluster lvs que es propietaria de Red Hat, tal vez en otras distros haya algo similar

En los directores lvs:

Instalar piranha (consola de configuracion de HA) e ipvsadm (paquete de servicios lvs)
yum install -y ipvsadm piranha


Habilitar los servicios al inicio.

chkconfig pulse on
chkconfig piranha-gui on
chkconfig httpd on

Establecer una clave para el servicio piranha

piranha-passwd

Habilitar forwarding de paquetes en el kernel y modificar parametros ARP

en /etc/sysctl.conf agregar o editar las siguientes lineas

net.ipv4.ip_forward = 1
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.eth0.arp_announce = 2


Se reinicia el equipo para que queden aplicados los cambios y luego para acceder a piranha http://ip.del.director:3636


Luego en "Global Settings" se configura la ip del director primario, en mi caso 192.168.10.23 y el tipo de red (Direct Routing). En el campo "Private server IP" no poner nada, ya que en este caso no hay dos adaptadores de red en el director.



En Redundancy ingresar la ip del director lvs secundario, en mi caso 192.168.10.24, lo demas dejarlo como esta.



Ahora, en virtual server se configura la ip que prestara servicio, es decir la ip visible de servicio. En mi caso seria para acceder al servicio, por ejemplo http://192.168.10.27.
Dejar todo como esta y en el tipo de scheduling seleccionar "Weightead-least Connections". Esta opcion es para que distribuya la carga en funcion al peso que tenga cada equipo y es proporcional. Suponiendo que Servidor A tiene peso 1 y Servidor B tiene peso 2, por cada DOS conexiones que tenga B, el servidor A va a tener una.

Una vez finalizado esto en la opcion de REAL SERVERS, se ingresan las ips y el peso de los equipos que van a prestar servicio, en el ejemplo es 192.168.10.205 con peso 1 (y 192.168.10.102 con peso 1 que ya lo configure desde antes).


Ya esta casi finalizada la configuracion, solo hay que definir el monitoreo de los servicios (en MONITORING SCRIPTS). Yo no utilice la opcion por defecto de piranha sino que use un script que me robe por ahi (!)
en /etc/sysconfig/ha crear un archivo llamado check_apache

#!/bin/bash
if links -dump -eval 'set connection.receive_timeout = 1' -eval 'set connection.retries = 1' -eval 'set connection.unrestartable_receive_timeout = 1' http://$1/ > /dev/null 2>&1; then

echo "OK"

else

echo "FAILURE"

fi

exit 0

Se guarda el archivo y se pasa a configurar en piranha el script de monitoreo. (No olvidar de darle permisos 755 al archivo).



Aceptar para aplicar los cambios, y NO OLVIDAR DE ACTIVAR LOS SERVIDORES!!!. Si no se activan no inicia el servicio despues....

Para configurar el director secundario (192.168.10.24 en mi caso) copiar el archivo /etc/sysconfig/ha/lvs.cf del primario hacia el secundario y el script check_apache dentro del mismo directorio.
Una vez terminado esto, hacer un service pulse restart en los dos directores.
En /var/log/messages se muestra el estado del servicio, por ejemplo

Apr 1 13:00:18 xxxx pulse[7834]: STARTING PULSE AS MASTER
Apr 1 13:00:21 xxxx pulse[7834]: backup inactive: activating lvs
Apr 1 13:00:21 xxxx lvs[7839]: starting virtual service web1 active: 80
Apr 1 13:00:21 xxxx nanny[7848]: starting LVS client monitor for 192.168.10.27:80 -> 192.168.10.205:80
Apr 1 13:00:21 xxxx lvs[7839]: create_monitor for web1/application1 running as pid 7848
Apr 1 13:00:21 xxxx nanny[7852]: starting LVS client monitor for 192.168.10.27:80 -> 192.168.10.120:80
Apr 1 13:00:21 xxxx lvs[7839]: create_monitor for web1/application2 running as pid 7852
Apr 1 13:00:21 xxxx nanny[7848]: [ active ] making 192.168.10.205:80 available
Apr 1 13:00:21 xxxx nanny[7852]: [ active ] making 192.168.10.120:80 available
Apr 1 13:00:26 xxxx pulse[7843]: gratuitous lvs arps finished

Listo con los directores. Si se prueba el servicio NO VA A FUNCIONAR, esto es por un problema de ARP en lvs, para mas info detallada http://www.linuxvirtualserver.org/docs/arp.html

Se proponen varias soluciones, yo utilice arptables. Para esto EN LOS SERVIDORES REALES, se debe instalar el paquete arptables

yum install -y arptables_jf
una vez instalado el paquete, se inicia el servicio y se corren los comandos arp correspondientes

service arptables_jf start
arptables -A IN -d 192.168.10.27 -j DROP # se dropean los pedidos arp a la ip virtual del lvs. En otros casos cambiar 192.168.10.27 por la correspondiente

arptables -A OUT -d 192.168.10.27 -j mangle --mangle-ip-s 192.168.10.205 # se sacan los paquetes de la ip flotante por la ip REAL del servidor, en otros casos cambiar 192.168.10.205 por la ip del servidor.
Guardar las tablas:

service arptables_jf save
Activar servicio arptables al inicio

chkconfig arptables_jf on

Ahora se debe crear un adaptador virtual con la ip virtual de lvs

ifconfig eth0:1 192.168.10.27 netmask 255.255.255.0 broadcast 192.168.10.255 up
NOTA: Agregar esta linea a /etc/rc.local ya que al reiniciarse el equipo se pierden esos cambios

agregar a /etc/sysctl.conf

net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
Reiniciar el equipo y listo!

Al acceder a http://192.168.10.27 tendremos un cluster apache con failover y balanceo de carga (en mi caso con relacion 1 a 1).