DN42&OneManISP - 使用VRF实现公网BGP和DN42共用一台机器

DN42&OneManISP - 使用VRF实现公网BGP和DN42共用一台机器

KaguraiYoRoy
2025-09-16 / 0 评论 / 9 阅读 / 正在检测是否收录...

背景

目前同一区域内公网BGP和DN42分别用了一台VPS,也就是说同一个区域需要两台机器。从群友那里得知了VRF,便想着通过VRF实现同一台机器同时处理公网BGP并加入DN42。

VRF的必要性

虽然说DN42使用的IP段是私有地址,并且它的ASN用的都是内部ASN,理论上不会和公网BGP相互干扰,但是如果共用同一张路由表,可能会造成路由污染、管理复杂等问题。

VRF(Virtual Routing and Forwarding,虚拟路由转发)可以实现在一台机器上创建多个路由表,也就是说我们可以通过它将DN42的路由单独放到一个路由表里,以实现将DN42路由表和公网路由表相隔离。这么做的优点有:

  • 绝对的安全与策略隔离:DN42路由表和公网路由表相隔离,从根本上杜绝了路由泄露的可能性。
  • 清晰的运维管理:可以使用birdc show route table t_dn42birdc show route table t_inet来分别查看和调试两张完全独立的路由表,一目了然。
  • 故障域隔离:若果DN42的某个对等体发生Flap,这些影响将被完全限制在dn42的路由表内,不会消耗公网实例的路由计算资源,也不会影响公网的转发性能。
  • 更符合现代网络设计理念:在现代网络工程中,为不同的路由域(生产、测试、客户、合作伙伴)使用VRF是标准做法。它将你的设备逻辑上划分成了多个虚拟路由器。

配置

系统部分

创建VRF设备

使用以下指令创建一个名为dn42-vrf的VRF设备并关联到系统的1042号路由表:

ip link add dn42-vrf type vrf table 1042
ip link set dev dn42-vrf up # 启用

路由表号可以按照你自己的喜好修改,但是请避开以下几个保留路由表编号:

名称 ID 说明
unspec 0 未指定,基本不用
main 254 主路由表,大多数普通路由都放在这里
default 253 一般不用,保留
local 255 本机路由表,存放127.0.0.1/8、本机 IP、广播地址等,不能改

将现有的相应网卡关联到VRF

按照我目前的DN42网络为例,有若干WireGuard网卡和一个dummy网卡是用于DN42的,因此将这几个网卡都关联到VRF中:

ip link set dev <网卡名> master dn42-vrf 

需要注意的是,网卡关联到VRF之后可能会丢失地址,因此需要重新为其添加一次地址,如:

ip addr add 172.20.234.225 dev dn42

完成之后,通过ip a应该能看到对应网卡的master是dn42-vrf:

156: dn42: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue master dn42-vrf state UNKNOWN group default qlen 1000
    link/ether b6:f5:28:ed:23:04 brd ff:ff:ff:ff:ff:ff
    inet 172.20.234.225/32 scope global dn42
       valid_lft forever preferred_lft forever
    inet6 fd18:3e15:61d0::1/128 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::b4f5:28ff:feed:2304/64 scope link 
       valid_lft forever preferred_lft forever

持久化

我使用了ifupdown来实现开机自动加载dummy网卡和VRF设备。

对于VRF设备,创建文件/etc/network/interfaces.d/01-dn42-vrf并填入:

auto dn42-vrf
iface dn42-vrf inet manual
    pre-up ip link add $IFACE type vrf table 1042
    up ip link set dev $IFACE up
    post-down ip link del $IFACE

然后使用ifup dn42-vrf启动。

对于dummy网卡,创建文件/etc/network/interfaces.d/90-dn42并填入:

auto dn42
iface dn42 inet static
    address 172.20.234.225
    netmask 32
    pre-up ip link add $IFACE type dummy
    up ip link set $IFACE up master dn42-vrf # 此处master指定和dn42-vrf相关联
    down ip link set $IFACE down
    post-down ip link del $IFACE

iface dn42 inet6 static
    address fd18:3e15:61d0::1
    netmask 128

因为ifupdown不支持同时配置v4和v6地址,因此需要分成两个iface。
我的dummy网卡名称为dn42,如果你的名称不一样请按需要修改。创建完后使用ifup dn42即可启动dummy网卡。

注意:VRF设备前面的标号需要比dummy网卡的大,以让VRF设备先于dummy网卡启动。

WireGuard隧道

添加PostUp使其关联到vrf并重新为其绑定地址。举个例子:

[Interface]
PrivateKey = [数据删除]
ListenPort = [数据删除]
Table = off
Address = fe80::2024/64
PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0
+ PostUp = ip link set dev %i master dn42-vrf
+ PostUp = ip addr add fe80::2024/64 dev %i

[Peer]
PublicKey = [数据删除]
Endpoint = [数据删除]
AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe00::/8

然后重新启动隧道即可。

Bird2部分

首先我们需要定义两张路由表,分别用于dn42的IPv4和IPv6:

ipv4 table dn42_table_v4;
ipv6 table dn42_table_v6

随后,在kernel protocol中指定VRF和系统路由表编号,并在IPv4、IPv6中指定前面创建的v4、v6路由表:

protocol kernel dn42_kernel_v6{
+   vrf "dn42-vrf";
+   kernel table 1042;
    scan time 20;

    ipv6 {
+       table dn42_table_v6;
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            krt_prefsrc = DN42_OWNIPv6;
            accept;
        };
    };
};

protocol kernel dn42_kernel_v4{
+   vrf "dn42-vrf";
+   kernel table 1042;
    scan time 20;

    ipv4 {
+       table dn42_table_v4;
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            krt_prefsrc = DN42_OWNIP;
            accept;
        };
    };
}

除了kernel以外的protocol都加上VRF和IPv4、IPv6独立的table,但不需要指定系统路由表编号:

protocol static dn42_static_v4{
+   vrf "dn42-vrf";
    route DN42_OWNNET reject;

    ipv4 {
+       table dn42_table_v4;
        import all;
        export none;
    };
}

protocol static dn42_static_v6{
+   vrf "dn42-vrf";
    route DN42_OWNNETv6 reject;

    ipv6 {
+       table dn42_table_v6;
        import all;
        export none;
    };
}

总而言之就是:

  • 一切和DN42有关的都给配置一个VRF和之前定义的路由表
  • 只有kernel协议需要指定系统路由表编号,其他不需要

对于BGP、OSPF等也如法炮制,不过我选择将公网的RouterID和DN42的分开,因此还需要单独配置一个RouterID:

# /etc/bird/dn42/ospf.conf
protocol ospf v3 dn42_ospf_iyoroynet_v4 {
+   vrf "dn42-vrf";
+   router id DN42_OWNIP;
    ipv4 {
+       table dn42_table_v4;
        import where is_self_dn42_net() && source != RTS_BGP;
        export where is_self_dn42_net() && source != RTS_BGP;
    };

    include "ospf/*";
};

protocol ospf v3 dn42_ospf_iyoroynet_v6 {
+   vrf "dn42-vrf";
+   router id DN42_OWNIP;
    ipv6 {
+       table dn42_table_v6;
        import where is_self_dn42_net_v6() && source != RTS_BGP;
        export where is_self_dn42_net_v6() && source != RTS_BGP;
    };

    include "ospf/*";
};
# /etc/bird/dn42/ebgp.conf
...
template bgp dnpeers {
+   vrf "dn42-vrf";
+   router id DN42_OWNIP;
    local as DN42_OWNAS;
    path metric 1;

    ipv4 {
+       table dn42_table_v4;
        ...
    };

    ipv6 {
+       table dn42_table_v6;
        ...
    };
}

include "peers/*";

完成后birdc c重载配置即可。
这时,我们可以通过ip route show vrf dn42-vrf来单独查看DN42的路由表:

root@iYoRoyNetworkHKGBGP:~# ip route show vrf dn42-vrf
10.26.0.0/16 via inet6 fe80::ade0 dev dn42_4242423914 proto bird src 172.20.234.225 metric 32 
10.29.0.0/16 via inet6 fe80::ade0 dev dn42_4242423914 proto bird src 172.20.234.225 metric 32 
10.37.0.0/16 via inet6 fe80::ade0 dev dn42_4242423914 proto bird src 172.20.234.225 metric 32 
...

也可以在Ping的时候通过参数-I dn42-vrf来实现通过VRF Ping:

root@iYoRoyNetworkHKGBGP:~# ping 172.20.0.53 -I dn42-vrf
ping: Warning: source address might be selected on device other than: dn42-vrf
PING 172.20.0.53 (172.20.0.53) from 172.20.234.225 dn42-vrf: 56(84) bytes of data.
64 bytes from 172.20.0.53: icmp_seq=1 ttl=64 time=3.18 ms
64 bytes from 172.20.0.53: icmp_seq=2 ttl=64 time=3.57 ms
64 bytes from 172.20.0.53: icmp_seq=3 ttl=64 time=3.74 ms
64 bytes from 172.20.0.53: icmp_seq=4 ttl=64 time=2.86 ms
^C
--- 172.20.0.53 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 2.863/3.337/3.740/0.341 ms

注意事项

  • 如果vrf设备重载了,所有原先和vrf相关联的设备都需要重载一次,否则无法正常工作

参考文章:

0

评论 (0)

取消