多个不同的 VLAN 中继到 KVM 来宾 (Linux)

cho*_*loo 5 linux vlan bridge trunk kvm-virtualization

我遇到了架构挑战的各种障碍。我有一台运行 KVM 的服务器——它将包含许多来宾,一些运行虚拟化防火墙,其他一些,只是普通的 Web 服务器。

  • Web 服务器需要一个未标记的 VLAN 接口
  • 防火墙需要标记的 VLAN 中继

现在,这通常很简单,只需eth0在其中添加一个网桥,在网桥上添加几个 VLAN(vmbr0.1等等) - 然后为每个来宾(或其倍数)分配一个带有未标记 VLAN 的接口。

                             firewall1 (vlan 1,2,3,4)
switch ===== eth0  vmbr0     firewall2 (vlan 1,2,5,6)
                   (eth0)    server1 (vlan 7)
                             server2 (vlan 8)
     vlan trunk
 (1,2,3,4,5,6,7,8)     
Run Code Online (Sandbox Code Playgroud)

现在,如果您只有几个需要传递给来宾的接口,这可以正常工作。但是当您需要将 500 个 VLAN 放入防火墙时会发生什么。它的不切实际。

所以我无法弄清楚如何创建一个数字中继(具有公共 VLAN 和不同的 VLAN),并将它们分配给来宾。

到目前为止,我找到的最接近的解决方案是在主桥上创建 VLAN,然后对于服务器,只需从中分配一个 VLAN。

然后对于防火墙,为每个防火墙创建一个桥,其中只有来宾的tap接口,然后vlan为相应的桥创建未标记的接口,并将其添加到主vmbr0桥。

唯一的问题是离开未标记接口的流量当然是未标记的。

是否可以标记离开接口的流量?

——

否则,如何实现 KVM 来宾的不同中继,这些中继可能具有公共 VLAN 和不同的 VLAN(但绝不是所有 VLAN) - 并且能够分配单个未标记的 vlan 接口

cho*_*loo 6

一个漫长的解决方案......

所以我一直在玩弄不同的概念,我想我已经找到了一个可行的解决方案。基本上,有一个主桥主干 ( bt)eth0属于。然后对于每个防火墙 VM 都有自己的网桥。

bridge name     bridge id               STP enabled     interfaces
bt              8000.002618895a72       no              eth0
bt-fw1          8000.000000000000       no              tap100i0
bt-fw2          8000.000000000000       no              tap101i0
Run Code Online (Sandbox Code Playgroud)

此时,来自防火墙 VM 的标记流量将进入它们自己的网桥以供流量进入。

然后,我为需要标记流量的每个接口创建了 VLAN,并在主网桥上为未标记流量创建了相应的 VLAN。

例如。VLAN 1, 4000-4005

bt-fw1.1       | 1  | bt-fw1
bt-fw1.4000    | 4000  | bt-fw1
bt-fw1.4001    | 4001  | bt-fw1
bt-fw1.4002    | 4002  | bt-fw1
bt-fw1.4003    | 4003  | bt-fw1
bt-fw1.4004    | 4004  | bt-fw1
bt-fw1.4005    | 4005  | bt-fw1
bt-fw2.1       | 1  | bt-fw2
bt-fw2.4000    | 4000  | bt-fw2
bt-fw2.4001    | 4001  | bt-fw2
bt-fw2.4002    | 4002  | bt-fw2
bt-fw2.4003    | 4003  | bt-fw2
bt-fw2.4004    | 4004  | bt-fw2
bt-fw2.4005    | 4005  | bt-fw2
bt.1           | 1  | bt
bt.4000        | 4000  | bt
bt.4001        | 4001  | bt
bt.4002        | 4002  | bt
bt.4003        | 4003  | bt
bt.4004        | 4004  | bt
bt.4005        | 4005  | bt
Run Code Online (Sandbox Code Playgroud)

然后,为每个 VLAN 创建一个网桥,该网桥将来自每个接口的所有相应 VLAN 组合在一起,以允许主网桥和 VM 网桥之间进行无标记通信。

bt.v1                   8000.2a8c73ad057d       no      bt-fw1.1
                                                        bt-fw2.1
                                                        bt.1
bt.v4000                8000.2a8c73ad057d       no      bt-fw1.4000
                                                        bt-fw2.4000
                                                        bt.4000
bt.v4001                8000.2a8c73ad057d       no      bt-fw1.4001
                                                        bt-fw2.4001
                                                        bt.4001
bt.v4002                8000.2a8c73ad057d       no      bt-fw1.4002
                                                        bt-fw2.4002
                                                        bt.4002
bt.v4003                8000.2a8c73ad057d       no      bt-fw1.4003
                                                        bt-fw2.4003
                                                        bt.4003
bt.v4004                8000.2a8c73ad057d       no      bt-fw1.4004
                                                        bt-fw2.4004
                                                        bt.4004
bt.v4005                8000.2a8c73ad057d       no      bt-fw1.4005
                                                        bt-fw2.4005
                                                        bt.4005
Run Code Online (Sandbox Code Playgroud)

这现在允许中继接口连接到防火墙虚拟机,只有我想要的 VLAN 在它们上面。

任何只需要单个未标记 VLAN 的未来来宾只能添加到相应的bt.X网桥。

添加主机 IP 接口就像将 IP 添加到相应的 VLAN 网桥一样简单

例如。

ip addr add 192.168.100.1/24 dev bt.v4005
Run Code Online (Sandbox Code Playgroud)

一个帮助脚本

由于我的/etc/network/interfaces文件很快就会变得很大,我写了一个小脚本,允许最少的配置 - 但具有相同的预期最终结果。

/etc/network/interfaces它包含的文件中

# bridge bt-c0-fw1 vlan 1 4000-4005 interfaces tap100i0
# bridge bt-c0-fw2 vlan 1 4000-4005 interfaces tap101i0
# bridge bt vlan 1 4000-4005 interfaces eth0
# bridge-vlan bt vlan 1 4000-4005 interfaces bt-fw1 bt-fw2 bt

auto eth0
iface eth0 inet manual
  post-up /scripts/build-bridges.sh || /bin/true
Run Code Online (Sandbox Code Playgroud)

然后在后期脚本中, /scripts/build-bridges.sh

#!/bin/bash

CONFIG="/etc/network/interfaces"
DEFINERS="vlan|interfaces"
DEBUG=0

# Tear down all interfaces
modprobe -r 8021q
modprobe 8021q

brctl show | awk 'NR>1{print $1}' | while read BRIDGE; do
  ifconfig "$BRIDGE" down
  brctl delbr "$BRIDGE"
done

function run()
{
  if [ $DEBUG -eq 1 ]; then
    echo "$@"
  else
    eval "$@"
  fi
}

function get_vars()
{
  DATA=( $(echo "$2" | grep -Eoh "$1.+?" | sed -E "s/^$1 //g;s/($DEFINERS).+//g") )
  for VAL in ${DATA[@]}; do
    echo $VAL | grep -qE "[0-9]+-[0-9]+"
    if [ $? -eq 0 ]; then
      LOWER=$(echo $VAL | cut -f1 -d"-")
      UPPER=$(echo $VAL | cut -f2 -d"-")
      for i in $(seq $LOWER $UPPER); do
        echo $i
      done
    else
      echo $VAL
    fi
  done
}

# Build bridges
while read LINE; do
  BRIDGE=$(get_vars bridge "$LINE")
  if [[ ! "$BRIDGE" == "" ]]; then
    run brctl addbr $BRIDGE
    run ifconfig $BRIDGE up
    for INTERFACE in $(get_vars interfaces "$LINE"); do
      ifconfig $INTERFACE >/dev/null 2>&1
      if [ $? -eq 0 ]; then
        run brctl addif $BRIDGE $INTERFACE
      fi
    done
    run ifconfig $BRIDGE up
    for VLAN in $(get_vars vlan "$LINE"); do
      run vconfig add $BRIDGE $VLAN 2>&1 | grep -vE "(VLAN 1 does not work|consider another number)"
      run ifconfig $BRIDGE.$VLAN up
    done
  fi
done < <(grep -E "^# bridge " $CONFIG)

# Build vlan bridges
while read LINE; do
  BRIDGE=$(get_vars "bridge-vlan" "$LINE")
  for VLAN in $(get_vars " vlan" "$LINE"); do
    run brctl addbr $BRIDGE.v$VLAN
    run ifconfig $BRIDGE.v$VLAN up
    for INTERFACE in $(get_vars interfaces "$LINE"); do
      ifconfig $INTERFACE.$VLAN >/dev/null 2>&1
      if [ $? -eq 0 ]; then
        run brctl addif $BRIDGE.v$VLAN $INTERFACE.$VLAN
      fi
    done
  done
done < <(grep -E "^# bridge-vlan " $CONFIG)

exit 0
Run Code Online (Sandbox Code Playgroud)

我希望这对其他人有帮助,我花了 DAYS 天的时间阅读和测试,这似乎是最优雅、最易于管理的解决方案。

这里也有一些很好的阅读http://blog.davidvassallo.me/2012/05/05/kvm-brctl-in-linux-bringing-vlans-to-the-guests/