Calico BGP功能介绍:BIRD简介

2021-06-09 16:55:24 浏览数 (1)

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 有master4master6两个默认的路由表,分别保存 IPv4 和 IPv6 路由规则。除此外,你也可以创建其他的路由表,比如在配置文件bird.conf中添加如下配置,创建一个 IPv4 的路由表my_table

代码语言:javascript复制
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 协议可以同时拥有IPv4IPv6通道,RIP 只能拥有 IPv4 或 IPv6 一种协议,而 BFD 则没有通道。

下面是根据官网样例修改而来的配置,实例化了一个名为peer_one的 BGP 协议,并且设置了ipv4ipv6两个通道,两个通道都未指明连接的路由表,则使用默认的master4master6路由表。其中在ipv4 通道中,导入方向配置为全部接收,导出方向上只导出静态路由,同时还会对路由规则的 BGP 信息进行修改:修改 bgp community,修改 bgp path;在ipv6通道上,则直接使用默认配置。

代码语言:javascript复制
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 邻居。

代码语言:javascript复制
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 提供的专门的编程语言,它提供了一些例如ifswitch的简单控制结构,但不允许有循环出现。同时,除了intstring这些基础的数据结构外,它还提供了例如bgppatchbgpmask等这种表示路由规则中某些信息的数据结构。例如下面定义了一个名为not_too_far的过滤器,丢弃掉rip_metric大于 10 的路由规则,可以通过import filter not_too_far直接调用此函数。

代码语言:javascript复制
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

代码语言:javascript复制
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的路由。需要注意的是,即使是开启learnkernel也不会将这些路由从内核导入(import)路由表,这种路由的传递需要使用到direct协议。(switch表示onoff两种值,下面相同)
  • persist switch,BIRD 退出时,在内核保留同步的路由(即不会进行 clean up 操作)。
  • scan time number,同步间隔,单位秒
代码语言:javascript复制
# 同步master4、master6路由表与主FIB,并在退出后保持同步的路由
protocol kernel {
    learn;
    persist;
}

direct

如上面所述,direct用于将内核生成的路由规则从内核导入到 BIRD 路由表中,可用的参数包括:

  • interface pattern [, ...],用于指定传递由哪些网卡生成的路由规则,默认是全部网卡
  • check link switch,开启后会考虑 link 的状态,当 link 状态为 up 时,传递路由,否则,撤销传递的路由
代码语言:javascript复制
# 同步除了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功能介绍:BIRD简介/

0 人点赞