L2 tunnel over IP на FreeBSD
May. 8th, 2015 03:33 pmВозникла необходимость сделать подручными средствами L2 tunnel over IP, пропускающий любой Ethernet трафик, в том числе служебные кадры. Сначала пробовал сделать, как описано в if_bridge(4): через gif-туннель, а gif0 и vr0 собрал в bridge. Не проходят STP BPDUs.
Сделал UDP туннель с помощью net/vtun, а в бридж собрал vr0 и tap0. Опять не проходят STP BPDUs на другую сторону. Значит дело в if_bridge, именно он не пропускает BPDU, придется от него отказаться.
Решил делать через netgraph, соединил vr0:lower и ksocket. Оказывается, ng_ether снимает с поступившего кадра 802.1q тэг, таким образом все кадры, на этой стороне принадлежавшие разным vlan, на другой стороне оказываются в одном нетэгированном vlan. Кроме этого, при соединении непосредственно ng_ether и ksocket через этот интерфейс уже не поуправляешь хостом, а хотелось бы. Значит придется задействовать ng_bridge для обеспечения управления и ng_vlan для сортировки кадров по vlan-ам. Слава Богу, ng_bridge не знает про STP и поэтому не фильтрует BPDU.
В показанной на рисунке конфигурации vlan38 не только передается на другую сторону, но и используется для управления хостом, а vlan3 и нетэгированный трафик передаются на другую сторону напрямую:

Недостаток данной конструкции в том, что любой vlan, отличный от 3 и 38, будет отправлен в untagged_socket и отправлен на ту сторону с потерей информации о тэге. Поэтому надо следить, чтобы в данный туннель не попадали vlan, которые не должны туда попадать.
И наконец сам скрипт для netgraph.
Если кто подскажет способ сделать так, чтобы неизвестные скрипту vlan-ы просто отфильтровывались вместо попадания в untagged_socket, буду благодарен.
Сделал UDP туннель с помощью net/vtun, а в бридж собрал vr0 и tap0. Опять не проходят STP BPDUs на другую сторону. Значит дело в if_bridge, именно он не пропускает BPDU, придется от него отказаться.
Решил делать через netgraph, соединил vr0:lower и ksocket. Оказывается, ng_ether снимает с поступившего кадра 802.1q тэг, таким образом все кадры, на этой стороне принадлежавшие разным vlan, на другой стороне оказываются в одном нетэгированном vlan. Кроме этого, при соединении непосредственно ng_ether и ksocket через этот интерфейс уже не поуправляешь хостом, а хотелось бы. Значит придется задействовать ng_bridge для обеспечения управления и ng_vlan для сортировки кадров по vlan-ам. Слава Богу, ng_bridge не знает про STP и поэтому не фильтрует BPDU.
В показанной на рисунке конфигурации vlan38 не только передается на другую сторону, но и используется для управления хостом, а vlan3 и нетэгированный трафик передаются на другую сторону напрямую:

Недостаток данной конструкции в том, что любой vlan, отличный от 3 и 38, будет отправлен в untagged_socket и отправлен на ту сторону с потерей информации о тэге. Поэтому надо следить, чтобы в данный туннель не попадали vlan, которые не должны туда попадать.
И наконец сам скрипт для netgraph.
#!/bin/sh
kldstat -q -m ng_ether || kldload ng_ether || exit 3
self=10.x.x.x
peer=10.y.y.y
port01=7701
port38=7738
port03=7703
if=vr0
case "$1" in
start)
echo "Starting netgraph switch."
ngctl mkpeer ${if}: vlan lower downstream
ngctl name ${if}:lower vlan
ngctl mkpeer vlan: ksocket nomatch inet/dgram/udp
ngctl name vlan:nomatch untagged_socket
ngctl msg untagged_socket: bind inet/${self}:${port01}
ngctl msg untagged_socket: connect inet/${peer}:${port01}
ngctl mkpeer vlan: ksocket vlan3 inet/dgram/udp
ngctl name vlan:vlan3 vlan3_socket
ngctl msg vlan: addfilter '{ vlan=3 hook="vlan3" }'
ngctl msg vlan3_socket: bind inet/${self}:${port03}
ngctl msg vlan3_socket: connect inet/${peer}:${port03}
ngctl mkpeer vlan: bridge vlan38 link0
ngctl name vlan:vlan38 sw
ngctl connect ${if}: sw: upper link1
ngctl mkpeer sw: ksocket link2 inet/dgram/udp
ngctl name sw:link2 vlan38_socket
ngctl msg vlan: addfilter '{ vlan=38 hook="vlan38" }'
ngctl msg vlan38_socket: bind inet/${self}:${port38}
ngctl msg vlan38_socket: connect inet/${peer}:${port38}
ngctl msg ${if}: setpromisc 1
ngctl msg ${if}: setautosrc 0
ngctl msg sw: setconfig '{ debugLevel=1 loopTimeout=60 maxStaleness=60 minStableAge=1 }'
echo "Ok."
exit 0
;;
stop)
echo "Stopping netgraph switch."
ngctl shutdown vlan38_socket:
ngctl shutdown vlan3_socket:
ngctl shutdown untagged_socket:
ngctl shutdown sw:
ngctl shutdown vlan:
ngctl shutdown ${if}:
echo "Ok."
exit 0
;;
restart)
sh $0 stop
sh $0 start
;;
*)
echo "Usage: `basename $0` { start | stop | restart }"
exit 64
;;
esac
Если кто подскажет способ сделать так, чтобы неизвестные скрипту vlan-ы просто отфильтровывались вместо попадания в untagged_socket, буду благодарен.