一文进阶frr

1,187 阅读10分钟

FRR

简介

在大规模网络环境下,我们部署的服务常常会利用BGP网络的优点来使我们的服务更加可靠、维护更加便捷。那既然服务器要使用到bgp协议,我们常使用frr(Quagga的分支)来和交换机组建bgp网络。

常见的场景

  1. 通过bgp来发布一组IP,我们可以基于bgp协议将IP宣告到网络中,实现替代Keepalived的VIP方案。常用于Nginx、Dns等需要高可用、负载均衡的服务上。
  2. 通过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