Calico BGP功能介绍:BIRD简介
Calico作为一种常用的Kubernetes网络插件,使用BGP协议对各节点的容器网络进行路由交换。本文是《Calico BGP功能介绍》系列的第一篇,介绍Calico所使用的BGP软件路由器——BIRD。
关于BGP协议,网上资料众多,在这里不再做介绍。另外,推荐《BGP in the datacenter》作为BGP应用的进阶阅读,另有中文翻译版本
BIRD
BIRD实际上是BIRD Internet Routing Daemon的缩写(禁止套娃),是一款可运行在Linux和其他类Unix系统上的路由软件,它实现了多种路由协议,比如BGP、OSPF、RIP等。
概念
BIRD会在内存中维护许多路由表,路由表根据不同的协议,通过与各种“其他事物”交换路由信息,来更新路由规则。这里说的“其他事物”可能是其他的路由表,也可能是外部的路由器,还可以是内核的某些API。
路由表
路由表(Routing tables)是BIRD的核心,一个路由表是内存中一组路由规则的集合,BIRD根据网络类型的不同会有多种路由表。默认情况下,BIRD有master4
和master6
两个默认的路由表,分别保存IPv4和IPv6路由规则。除此外,你也可以创建其他的路由表,比如在配置文件bird.conf
中添加如下配置,创建一个IPv4的路由表my_table
。
ipv4 table my_table;
要注意的是,BIRD的路由表仅仅是一个表,并没有转发的功能,真正的转发控制,是内核的FIB(Forwarding Information Base)。而BIRD的kernel
协议,可以将BIRD路由表与FIB进行同步,后面会介绍。
路由规则中包含了各种路由属性(Route attributes),网络类型不同的路由表,其路由属性也不太一样,比如常见的IPv4和IPv6的路由表,会包括两个路由属性:
- 路由目的地
- 路由下一跳
而VPN路由表还会包含路由属性:路由标识符(Route distinguisher)。
BIRD的每种表都会将一个或一组路由属性作为主键,类似于SQL数据库。当多个来源都提供了相同主键的路由条目时,BIRD会根据一定的规则选择最优路由。例如IPv4和IPv6类型的路由表,将“路由目的地”作为主键。
协议与通道
协议(Protocols)将路由表和“其他事物”连接起来。“其他事物”可以是一个Socket对象,连接了外部的路由器,例如BGP路由协议;也可以是修改FIB的内核API,例如kernel
协议;也可以是空,比如静态路由static
协议。一个协议可以实例化为多个对象,例如创建多个BGP协议的实例,以表示多个BGP邻居。
协议也会提供一些路由属性,根据协议的不同路由属性也不同,比如使用BGP协议时,会有bgp_path
属性。
协议可能包含一些通道(Channels),通道是在协议和路由表之间,配置了路由规则在导入(import))、导出(export)两个方向上的行为,导入导出是针对路由表来说的,路由规则经过通道后,或是被接收(Accept),或是被拒绝(Reject),或是被修改。不同的协议可拥有的通道也不一样,例如BGP协议可以同时拥有IPv4
和IPv6
通道,RIP只能拥有IPv4或IPv6一种协议,而BFD则没有通道。
下面是根据官网样例修改而来的配置,实例化了一个名为peer_one
的BGP协议,并且设置了ipv4
和ipv6
两个通道,两个通道都未指明连接的路由表,则使用默认的master4
与master6
路由表。其中在ipv4
通道中,导入方向配置为全部接收,导出方向上只导出静态路由,同时还会对路由规则的BGP信息进行修改:修改bgp community,修改bgp path;在ipv6
通道上,则直接使用默认配置。
protocol bgp peer_one {
local 198.51.100.14 as 65000; # Use a private AS number
neighbor 198.51.100.130 as 64496; # Our neighbor ...
ipv4 {
export filter { # We use non-trivial export rules
if source = RTS_STATIC then { # Export only static routes
# Assign our community
bgp_community.add((65000,64501));
# Artificially increase path length
# by advertising local AS number twice
if bgp_path ~ [= 65000 =] then
bgp_path.prepend(65000);
accept;
}
reject;
};
import all;
};
ipv6;
}
主要功能
模板
在BIRD中,可以定义模板(template),通过模板来创建一个协议的多个实例。模板在使用BGP协议时非常好用,因为BGP通常都会设置多个BGP Peer。例如下面配置,通过模板提取出共用的配置,然后利用模板创建多个BGP邻居。
template bgp foo {
local 198.51.100.14 as 65000;
ipv4 {
table mytable4;
import filter { ... };
export none;
};
ipv6 {
table mytable6;
import filter { ... };
export none;
};
}
protocol bgp bgp1 from foo {
neighbor 198.51.100.130 as 64496;
}
protocol bgp bgp2 from foo {
neighbor 198.51.100.131 as 64496;
}
过滤器
过滤器(Filters)在上面的用例中已经出现了多次,通过在通道中添加过滤器,可以灵活地控制路由规则的交换。在过滤器中,你可以像访问变量一样直接使用各种路由属性,来编写各种判断条件,以决定对路由规则是ACCEPT还是REJECT,或是直接对路由属性进行修改。
为了便于复用,还可以以函数的形式定义一个过滤器,使用时在相应的通道中直接调用。需要注意的是,编写过滤器需要使用BIRD提供的专门的编程语言,它提供了一些例如if
、switch
的简单控制结构,但不允许有循环出现。同时,除了int
、string
这些基础的数据结构外,它还提供了例如bgppatch
、bgpmask
等这种表示路由规则中某些信息的数据结构。例如下面定义了一个名为not_too_far
的过滤器,丢弃掉rip_metric
大于10的路由规则,可以通过import filter not_too_far
直接调用此函数。
filter not_too_far
int var;
{
if defined( rip_metric ) then
var = rip_metric;
else {
var = 1;
rip_metric = 1;
}
if rip_metric > 10 then
reject "RIP metric is too big";
else
accept "ok";
}
常见协议
这里只介绍Calico中使用到的几种协议,以及用到的协议属性。
device
准确来说,device
并不算是一个协议,它不产生任何路由,也不支持通道,而是被用来从内核中获取网卡设备的信息。每个bird.conf
的配置文件中,都应定义一个device
。
protocol device {
scan time 10; # Scan the interfaces often
interface "eth0" {
preferred 192.168.1.1;
preferred 2001:db8:1:10::1;
};
}
上面配置定义了BIRD每10s扫描一遍eth0
网卡,同时定义了首选的IP地址。
kernel
kernel
也不算真正的协议,它负责同步路由表与内核。如果内核支持多个内核路由表,那么可以创建多个kernel
实例,否则只需要创建一个kernel
实例。kernel
协议有两个限制:
- 不能将多个
kernel
实例都连接到同一个路由表上 - 不能修改导出(export)路由规则的目标地址
一些主要的参数包括:
learn switch
,开启后路由表可以从内核中学习到非内核生成(其他方式添加)的路由。“内核生成的路由”指的是由于本机网络的配置而产生的路由,比如eth0
在被分配192.168.1.2/24
后,会自动产生一条目的地为192.168.1.0/24
,下一跳为eth0
的路由。需要注意的是,即使是开启learn
,kernel
也不会将这些路由从内核导入(import)路由表,这种路由的传递需要使用到direct
协议。(switch
表示on
和off
两种值,下面相同)persist switch
,BIRD退出时,在内核保留同步的路由(即不会进行clean up操作)。scan time number
,同步间隔,单位秒
# 同步master4、master6路由表与主FIB,并在退出后保持同步的路由
protocol kernel {
learn;
persist;
}
direct
如上面所述,direct
用于将内核生成的路由规则从内核导入到BIRD路由表中,可用的参数包括:
interface pattern [, ...]
,用于指定传递由哪些网卡生成的路由规则,默认是全部网卡check link switch
,开启后会考虑link的状态,当link状态为up时,传递路由,否则,撤销传递的路由
# 同步除了eth0以外的其他网卡
protocol direct {
interface -"eth0", "*";
}
BGP
每一个BGP协议的实例,代表了一个BGP Peer连接。需要注意的是,部分参数的默认值对IBGP与EBGP并不相同,例如aigp
默认在IBGP中是开启的,默认在EBGP是关闭的。协议的主要参数包括:
local [ip] [port number] [as number]
,可以用来指定BGP的源IP地址以及本地的AS。multihop [number]
,表示多跳的BGP,后面的number
可以用来设置TTL
的值,IBGP默认开启;相反的,还有个参数为direct
,表示与BGP邻居直连,EBGP默认开启。source address ip
,用来指定本端使用的BGP源地址。add paths switch|rx|tx
,开启时,会将 BGP 配置为向同一目标通告多个路径,否则 BGP 仅通告活动路径。password string
,使用设置的密码进行BGP的身份验证。rr client
,开启RR模式(Route Reflector)。rr cluster id IPv4 address
,设置RR的cluster id
,以防止路由环路。默认情况下,会直接使用BGP的router id
(一般是ipv4地址)作为cluster id
,当有多个RR时,需要使用此参数设置相同的cluster id
。bfd switch|graceful
,使用BFD作为BGP协议心跳机制。passive switch
,被动模式,不主动初始化连接,而是等待其他BGP邻居发起连接。
以上是协议一层的配置参数,在BGP协议中,通道也会有额外的参数,例如:
gateway direct|recursive
,用来控制如何计算路由的gw属性。当设置为direct
时,如果路由中的bgp_next_hop
是和本机中的某个地址同一子网(同一个二层),则gw直接为bgp_next_hop
,否则为对端BGP Peer的IP地址;当设置为recursive
时,会从IGP路由表中查询bgp_next_hop
来作为gw。next hop keep switch|ibgp|ebgp
,开启后,BGP不再将next hop
属性修改为自身,而是直接通告原始的next hop
,这个参数在多跳的EBGP场景或BGP路由反射中会使用到。