FRR
简介
在大规模网络环境下,我们部署的服务常常会利用BGP网络的优点来使我们的服务更加可靠、维护更加便捷。那既然服务器要使用到bgp协议,我们常使用frr(Quagga的分支)来和交换机组建bgp网络。
常见的场景
- 通过bgp来发布一组IP,我们可以基于bgp协议将IP宣告到网络中,实现替代Keepalived的VIP方案。常用于Nginx、Dns等需要高可用、负载均衡的服务上。
- 通过bgp可以让k8s pod ip宣告到网络中,可以不依赖vxlan实现直接通信,减少了封装/解封装的开销,是当前非常流行的一个方案。
日常工作中我们是否会有疑问,pod ip是怎么通过bgp发布出去的?为什么不像普通的bgp节点配置dummy0呢?想要理解它,那就需要去了解frr的配置原理,避免埋坑。
zebra
zebra是一个IP路由管理器。它提供内核路由表更新、接口查找和不同路由协议之间路由的重新分配。(提供了虚拟路由器的主要功能)
匹配地址的行为
在启动时,Zebra将首先从操作系统中发现底层网络对象。这包括接口(interfaces)、接口地址(adresses)、静态路由(routes)等。
然后,它将读取配置文件,包括它自己的接口地址、静态路由等。所有这些信息都包含来自Zebra的操作上下文。
但是,Zebra的配置上下文将与zebra.conf配置文件中的配置上下文保持一致。例如,执行下面的show running-config命令将反映zebra.conf中的内容。
以类似的方式,在Zebra之外配置的网络对象(如iproute2)不会影响Zebra的配置上下文。这种行为允许您继续保存自己的配置文件,并决定在配置文件上真正要推送的内容,以及依赖于底层系统的内容。相反,在Zebra中,您将无法删除先前在Zebra之外配置的网络对象。
$ sudo ip rule list table 0
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
$ sudo ip route show table local |grep dummy0
local xx.xx.136.3 dev dummy0 proto kernel scope host src xx.xx.136.3
broadcast xx.xx.136.3 dev dummy0 proto kernel scope link src xx.xx.136.3
# sh ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
F - PBR, f - OpenFabric,
> - selected route, * - FIB route, q - queued route, r - rejected route
K>* 0.0.0.0/0 [0/0] via 10.170.181.1, tunl0 onlink, 21:24:30
K>* 10.0.0.0/8 [0/0] via xx.xx.83.65, bond0, 21:24:30
K>* xx.xx.20.206/32 [0/0] is directly connected, 7aa353ea6e, 21:09:33
K>* xx.xx.32.7/32 [0/0] is directly connected, c29c96a78b, 21:09:33
K>* xx.xx.96.81/32 [0/0] is directly connected, 9b0138244d, 21:09:33
C>* xx.xx.136.3/32 is directly connected, dummy0, 20:01:56
C>* xx.xx.83.64/26 is directly connected, bond0, 21:20:27
C>* 169.254.169.253/32 is directly connected, lo, 21:24:31
K>* 172.16.0.0/12 [0/0] via xx.xx.83.65, bond0, 21:24:30
# show ip bgp nei xx.xx.83.65 advertised-routes
BGP table version is 7, local router ID is xx.xx.83.94, vrf id 0
Default local pref 100, local AS 4200000010
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> xx.xx.20.206/32 0.0.0.0 0 32768 ? # pod的bgp ip
*> xx.xx.32.7/32 0.0.0.0 0 32768 ?
*> xx.xx.96.81/32 0.0.0.0 0 32768 ?
*> xx.xx.136.3/32 0.0.0.0 0 32768 i # dummy0 ip,同时通过network发布
bfd
BFD是双向转发检测(Bidirectional Forwarding Detection)的缩写
neighbor <A.B.C.D|X:X::X:X|WORD> bfd [profile BFDPROF]:bgp bfd配置
bgp
bgp边界网关协议
基本概念
Autonomous Systems(AS)自治系统
as是由一个或多个网络运营商运行的一个或多个IP前缀组成的连接组,具有单一且定义明确的路由策略。
每个自治系统都有一个与之相关联的标识号,称为ASN。两个八位字节,取值范围是1 ~ 65535。自治系统号64512 ~ 65535定义为私有自治系统号。私有自治系统号码不能在全球互联网上发布。
ASN是BGP的基本元素之一。BGP是一种距离矢量路由协议,AS-Path框架为BGP提供距离矢量度量和环路检测功能。
Route Selection 路由选择
FRR的BGP实现使用的路由选择过程使用以下决策标准,从列表的顶部开始,向底部移动,直到其中一个因素可以使用。
- Weight check:优先选择高本地权重的路由,而不是低本地权重的路由。
- Local preference check:本地优先级较高的路由优先于较低的路由。
- Local route check:优先选择本地路由(statics静态路由、aggregates聚合路由、redistributed重分发路由)。
- AS path length check:优先选择跳数最短的as_path。
- Origin check:源检查
- MED check:如果从同一自治系统接收到具有MED值的路由,则优先选择MED值最小的路由。
- External check:优先从外部eBGP对等体接收路由,而不是从其他类型的对等体接收路由。
- IGP cost check:优先选择IGP开销较小的路由。
- Multi-path check:多路径检查
- Already-selected external check:如果两条路由都是从eBGP对等体接收到的,则优先选择已经选择的路由。
- Router-ID check:优先选择router-ID最小的路由。
- Cluster-List length check:使用簇列表长度最短的路由。
- Peer address:优先选择从具有更高传输层地址的对等体接收的路由,作为最后的决胜手段。
bgp路由发布
network A.B.C.D/M:宣告路由给所有邻居
redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static> [metric (0-4294967295)] [route-map WORD]: 从别的协议中重分发路由
redistribute <table|table-direct> (1-65535)] [metric (0-4294967295)]:将路由表ID中的路由重分发到BGP中
frr基础配置
frr安装后默认什么都不做,我们以启动bgp为例修改/etc/frr/daemons
$ cat /etc/frr/daemons |grep -v "^#"
bgpd=yes # 启动bgpd服务
bfdd=yes
……
vtysh_enable=yes # 启动vtysh命令
zebra_options=" -A 127.0.0.1 -s 90000000"
bgpd_options=" -A 127.0.0.1"
在/etc/services我们可以看到服务的端口
zebrasrv 2600/tcp # zebra service
zebra 2601/tcp # zebra vty
ripd 2602/tcp # RIPd vty
ripngd 2603/tcp # RIPngd vty
ospfd 2604/tcp # OSPFd vty
bgpd 2605/tcp # BGPd vty
……
常用命令
基础命令
hostname HOSTNAME:为“路由器”设置一个主机名
password PASSWORD: 设置vty接口的密码
enable password PASSWORD:设置enable的密码
log file [FILENAME [LEVEL]]:设置日志文件和等级,例如:log file /var/log/frr/bgpd.log informational
log syslog [LEVEL]:把日志写入syslog
基础的配置
!
! Zebra configuration file
!
frr version 6.0
frr defaults traditional
!
hostname Router
password zebra
enable password zebra
!
log stdout
!
!
Terminal命令
write file:保存当前配置到配置文件,例如:write
show logging|memory :查看日志配置|内存信息
路由过滤
Filtering用于路由信息的输入和输出。一旦定义了过滤,它就可以在任何方向上应用。
IP Access List
访问限制
access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK:允许特定的网段
access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK:禁止特定的网段
Seq号可以自动设置,也可以手动设置。
在手动设置序列号的情况下,用户可以选择小于4294967295的任何数字。
在自动设置序列号的情况下,每个列表的序列号将以5为单位增加。如果在一个指定序号的列表之后创建一个未指定序号的列表,该列表将自动选择下一个5(5)的倍数作为列表号。例如,如果一个编号为2的列表已经存在,并且创建了一个没有指定编号的新列表,则下一个列表将编号为5。如果列表2和7已经存在,并且创建了一个没有指定编号的新列表,则新列表将编号为10。
show <ip|ipv6> access-list [WORD] [json]:查看access lists
例如定义了一个myfilter
access-list myfilter deny 10.0.0.0/9 # 拒绝10.0.0.0/9
access-list myfilter permit 10.0.0.0/8 # 允许10.0.0.0/8
access-list myfilter seq 13 permit 10.0.0.0/7 # 允许10.0.0.0/7
IP Prefix List
基于前缀的过滤机制,除了access-list功能外,ip prefix-list还具有前缀长度范围规范和序列号规范。
如果没有定义ip prefix-list,默认是permit。如果定义了ip prefix-list,但是没有匹配到,默认是deny。
ip prefix-list NAME [seq NUMBER] (permit|deny) PREFIX [le LEN] [ge LEN]
le:如果掩码小于等于LEN,则应用前缀列表。
ge:如果掩码大于等于LEN,则应用前缀列表。
show ip prefix-list [NAME] [json]:查看prefix-list
debug prefix-list NAME match <A.B.C.D/M|X:X::X:X/M> [address-mode]:测试prefix-list结果
Route maps
docs.frrouting.org/en/stable-1…
Route maps提供了一种过滤 and/or 应用动作到路由的方法,从而允许将策略应用到路由上。要使路由反射器对反射的路由应用route-map,请确保在bgp模式中包含bgp route-reflector allow-outbound-policy。
Route maps是一个 路由条目 的有序列表。每个条目最多可指定四组不同的条款:
Matching Conditions匹配条件:如果route-map条目没有明确指定任何匹配条件,则它总是匹配。
Set Actions设置动作
Matching Policy匹配策略:
-
permit:如果条目匹配,则执行
Set Actions。然后完成对路由图的处理,允许该路由通过,除非Exit Policy动作另有指示。 -
deny:如果匹配,则结束对路由的处理,拒绝该路由(返回deny)。
Call Actioncall动作:调用另一个route-map
Exit Policy退出策略:替换默认的退出策略
-
next:继续处理路线图条目。
-
goto N:跳转到第一个路由表项,该路由表项在路由表中的顺序>= N。不允许跳转到前一个路由表项。
一个Route maps的最后一个条目是空的deny条目,它匹配所有的路由。
route-map相关命令
route-map ROUTE-MAP-NAME (permit|deny) ORDER:定义route-map,ORDER就是定义的access-list或者ip prefix-list的序号(优先级)。
match ip address ACCESS_LIST:匹配access-list
match ip address prefix-list PREFIX_LIST:匹配ip prefix-list
set tag <untagged|(1-4294967295)>:为匹配的路由设置tag
call NAME:调用另外一个route-map
on-match next:匹配到继续执行下面的规则
on-match goto N:匹配到跳转到seq N规则
route-map test permit 10
match ip address 10
set local-preference 200 # 配置BGP本地优先级为local_pref
Nexthop Groups
docs.frrouting.org/en/stable-1…
Nexthop groups是将ECMP信息封装在一起的一种方法。它是用于转发数据包的ECMP下一跳的列表。
配置示例讲解
nginx-frr配置示例
frr version 9.0
frr defaults traditional
hostname xxx
log syslog informational
no ip forwarding
no ipv6 forwarding # 路由器将不再转发收到的IPv4/IPv6数据包,而是仅处理目标地址与路由器本身相关的数据包。
service integrated-vtysh-config
# 配置BGP邻居关系及路由器间的交互行为。
router bgp 64603 # 设置本地路由器的AS号为64603
bgp router-id $peer_ip # 设置BGP路由器ID为$peer_ip。
no bgp default ipv4-unicast # 禁用默认的IPv4单播路由设置。这意味着BGP将不会自动传播所有IPv4单播路由。
neighbor $neighbor_ip remote-as 64602 # 指定邻居的IP地址为$neighbor_ip,并设置其远端AS号为64602。
neighbor $neighbor_ip advertisement-interval 1 # 设置向邻居路由器发送路由更新的时间间隔为1秒。
neighbor $neighbor_ip next-hop-self # 在发送路由更新时,将自身作为下一跳地址发送给邻居路由器。
neighbor $neighbor_ip timers connect 10 # 置与邻居路由器建立连接的超时时间为10秒。
!# 对IPv4单播地址族的BGP邻居配置
address-family ipv4 unicast # 进入IPv4单播地址族的配置模式
redistribute connected route-map V4VIP # 使用V4VIP的routemap去匹配本地连接的路由信息,将匹配的路由发送给BGP邻居。
neighbor $neighbor_ip activate # 激活指定邻居的BGP邻居关系。
neighbor $neighbor_ip route-map PASSALL in # 指定了在从邻居接收路由时,使用PASSALL的routemap。
neighbor $neighbor_ip route-map PASSALL out # 指定了在向邻居发送路由时,使用PASSALL的routemap。
exit-address-family # 退出配置
!
ip prefix-list V4VIP-LIST seq 10 permit $vip_subnet/30 ge 32 # 创建一个名为V4VIP-LIST的prefix-list,序号为10,允许一个网段,而且匹配长度要大于等于32位
ip prefix-list V4VIP-LIST seq 1000 deny any # 序号为1000,拒绝所有
!
route-map V4VIP permit 1 # 创建一个名为V4VIP的路由映射,并定义了一个允许的条目序号为1。
match ip address prefix-list V4VIP-LIST # 在该路由映射中,指定匹配来自名为V4VIP-LIST的prefix-list的路由。
!
route-map PASSALL permit 10 # 创建一个名为PASSALL路由映射,并定义了一个允许的条目序号为10。
!
line vty
!
route-map 定义了路由策略,我们可以把这些策略应用到路由上
route-map ROUTE-MAP-NAME (permit|deny) ORDER:定义route-map,ORDER就是定义的access-list或者ip prefix-list的序号(优先级)。
match ip address ACCESS_LIST:匹配access-list
match ip address prefix-list PREFIX_LIST:匹配ip prefix-list
ip prefix-list 过滤机制,除了access-list功能外,ip prefix-list还具有前缀长度范围规范和序列号规范。
ip prefix-list NAME [seq NUMBER] (permit|deny) PREFIX [le LEN] [ge LEN]
bgp路由发布(重点)
network A.B.C.D/M:宣告路由给所有邻居(静态)redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static> [metric (0-4294967295)] [route-map WORD]: 从别的协议中重分发路由redistribute <table|table-direct> (1-65535)] [metric (0-4294967295)]:将路由表ID中的路由重分发到BGP中
我看看一下connected和kernel有什么区别
# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
F - PBR, f - OpenFabric,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
K>* 0.0.0.0/0 [0/0] via xx.xx.68.1, bond0.100 onlink, 44w1d21h
K>* 10.0.0.0/8 [0/0] via xx.xx.68.1, bond0.100, 44w1d21h
C>* xx.xx.67.2/32 is directly connected, dummy0, 44w0d22h
C>* xx.xx.68.0/22 is directly connected, bond0.100, 44w1d21h
K>* xx.xx.133.104/32 [0/0] is directly connected, fcc1602dd4, 31w1d20h
K>* xx.xx.141.97/32 [0/0] is directly connected, 65cdae0bbc, 31w1d20h
K>* xx.xx.149.68/32 [0/0] is directly connected, 0818fec08e, 29w0d20h
K>* xx.xx.151.81/32 [0/0] is directly connected, cbd6ac74b1, 22w1d16h
K>* xx.xx.152.217/32 [0/0] is directly connected, 20c57ce3d2, 27w4d19h
K>* xx.xx.157.28/32 [0/0] is directly connected, 647a90ae25, 43w4d19h
K>* xx.xx.159.11/32 [0/0] is directly connected, 6dd9261626, 29w0d20h
K>* xx.xx.179.131/32 [0/0] is directly connected, 288519c586, 31w1d20h
K>* xx.xx.183.160/32 [0/0] is directly connected, 263fb3902f, 31w1d20h
K>* xx.xx.228.215/32 [0/0] is directly connected, 6e79df1bd7, 06w4d20h
K>* xx.xx.251.72/32 [0/0] is directly connected, c98d748626, 2d19h56m
C>* 169.254.169.253/32 is directly connected, lo, 44w1d21h
K>* 172.16.0.0/12 [0/0] via xx.xx.68.1, bond0.100, 44w1d21h
K>* 开头的就是kernel获取的路由,C>*开头的就是connected获取到的路由。我们可以看到bond0.100、dummy0是connected,容器IP是kernel,所以如果我们需要将容器IP动态发布的话,我们就需要添加redistribute kernel,例如
redistribute connected route-map V4VIP
redistribute kernel
我们在之前的使用中一直有一个误区,使用network来静态发布一条路由,然后使用ifdown dummy0来想撤销路由,结果发现有些时候并不能撤销路由。正确的做法就是不用配置network,使用redistribute connected来动态控制路由即可。
现在我们再来看一下redistribute connected route-map V4,首先将所有connected路由进行V4VIP匹配。V4VIP定义了一条匹配ip前缀的规则:ip prefix-list V4VIP-LIST seq 10 permit $vip_subnet/30 ge 32,只允许$vip_subnet/30网段(例如:10.1.1.0/30,10.1.1.1~10.1.1.3),而且掩码是32位,就表示我们只能够将特定的ip发布出去。而且我们配置的ip可以在任何地方,不一定要是dummy0。
我们也可以测试匹配情况
$ ipcalc 10.1.1.0/30
Network: 10.1.1.0/30 00001010.00000001.00000001.000000 00
HostMin: 10.1.1.1 00001010.00000001.00000001.000000 01
HostMax: 10.1.1.2 00001010.00000001.00000001.000000 10
Broadcast: 10.1.1.3 00001010.00000001.00000001.000000 11
Hosts/Net: 2 Class A, Private Internet
# ip prefix-list test seq 10 permit 10.1.1.0/30 ge 32
# debug prefix-list test match 10.1.1.3/32
IPv4 prefix list test yields PERMIT for 10.1.1.3/32, matching entry #10: 10.1.1.0/30 ge 32
# debug prefix-list test match 10.1.1.4/32
IPv4 prefix list test yields DENY for 10.1.1.4/32, no match found
# debug prefix-list test match 10.1.1.3/31
IPv4 prefix list test yields DENY for 10.1.1.3/31, no match found
# ip prefix-list test1 seq 20 permit 10.1.1.0/30 ge 31
# debug prefix-list test1 match 10.1.1.3/31
IPv4 prefix list test1 yields PERMIT for 10.1.1.3/31, matching entry #20: 10.1.1.0/30 ge 31
最终我们可以查看哪些路由发布出去了
# show ip bgp nei xx.xx.83.65 advertised-routes
BGP table version is 7, local router ID is xx.xx.83.94, vrf id 0
Default local pref 100, local AS 4200000010
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> xx.xx.20.206/32 0.0.0.0 0 32768 ?
*> xx.xx.32.7/32 0.0.0.0 0 32768 ?
*> xx.xx.96.81/32 0.0.0.0 0 32768 ?
*> xx.xx.136.3/32 0.0.0.0 0 32768 i