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, буду благодарен.