
Calico 作为一种常用的 Kubernetes 网络插件,使用 BGP 协议对各节点的容器网络进行路由交换。本文是《Calico BGP 功能介绍》系列的第一篇,介绍 Calico 所使用的 BGP 软件路由器——BIRD。
关于 BGP 协议,网上资料众多,在这里不再做介绍。另外,推荐《BGP in the datacenter》作为 BGP 应用的进阶阅读,另有中文翻译版本[1]
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 路由反射中会使用到。
参考文档
BIRD 官方手册[2]
脚注
[1]
中文翻译版本: https://cshihong.github.io/2020/04/18/BGP-in-the-datacenter-数据中心的BGP-数据中心网络架构-Clos网络架构/
[2]BIRD 官方手册: https://bird.network.cz/?get_doc&v=20&f=bird.html#toc5
原文链接:https://maao.cloud/2021/01/26/Calico-BGP%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D%EF%BC%9ABIRD%E7%AE%80%E4%BB%8B/


你可能还喜欢
点击下方图片即可阅读

云原生是一种信仰 ????
关注公众号
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!


点击 "阅读原文" 获取更好的阅读体验!
发现朋友圈变“安静”了吗?

本文详细介绍了Calico网络插件中使用的BGP软件路由器BIRD,包括其路由表、协议、通道、过滤器等功能。BIRD维护了多个路由表,与各类“其他事物”交换路由信息,通过协议如BGP、OSPF、RIP等同步路由规则。BIRD的路由表不负责转发,而是与内核的FIB同步。BIRD的协议如BGP可以设置多个通道,通过过滤器控制路由规则的导入和导出。此外,文章还讲解了BIRD的模板、直接协议、内核协议和BGP协议的使用。

3218

被折叠的 条评论
为什么被折叠?



