基于内核的OVS

首先验证内核版本uname -r与你下载的OVS版本是否匹配(必须),目前 ovs-2.16 最高只支持内核5.8!

linux内核与ovs版本匹配关系、ovs版本与DPDK版本匹配关系

OVS-2.16.0 为例,编译过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 获取源码
wget https://github.com/openvswitch/ovs/archive/refs/tags/v2.16.0.zip && unzip v2.16.0.zip

# 安装依赖包
sudo apt install build-essential fakeroot
dpkg-checkbuilddeps # 检查依赖并手动安装缺少的模块
#####################################################

cd ovs-2.16.0
./boot.sh
./configure --with-linux=/lib/modules/$(uname -r)/build
make -j # -j 默认让所有核同时进行编译,也可以指定编译核数

sudo make install # 安装ovs
sudo insmod datapath/linux/openvswitch.ko # 安装内核模块,报错处理见下文
sudo make modules_install
sudo modprobe openvswitch

# 报错处理,一般是缺失依赖模块,通过modprobe安装就好
modinfo ./datapath/linux/openvswitch.ko | grep depends # 查看缺少依赖模块
sudo modprobe nf_conntrack
sudo modprobe nf_nat

# 启动工具 ovs-ctl
echo 'export PATH=$PATH:/usr/local/share/openvswitch/scripts' | tee -a /root/.bashrc \
echo 'export DB_SOCK=/usr/local/var/run/openvswitch/db.sock' | tee -a /root/.bashrc

安装内核模块时报错的解决办法

基于DPDK的OVS

下面的DPDK编译方式都是基于meson,从DPDK 19版本开始才能使用meson进行编译!

同样注意OVS的版本与DPDK版本是否匹配,ovs-2.16 适配了DPDK-20.11.5,DPDK的版本20.11.n一定要选最新版,这种更新一般是修复了一些 bug。

编译安装DPDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 获取源码
wget https://fast.dpdk.org/rel/dpdk-20.11.5.tar.xz

# 编译工具 meson ninja,从v19开始使用meson进行DPDK的编译!
sudo pip3 install meson ninja
sudo apt install libnuma-dev libpcap-dev libfdt-dev

#####################################################

cd dpdk-stable-20.11.3
# 编译 使用`| tee file`是将日志显示在终端的同时,保存到文件中
meson build | tee ../meson.build
ninja -C build
# 安装库 将DPDK的相关库文件复制到根目录下的相关引用目录
sudo ninja -C build install
# 更新缓存 (usually run when a new library is installed)
sudo ldconfig
# 测试一下 libdpdk 是否安装成功
pkg-config --modversion libdpdk

# 卸载 dpdk
sudo ninja uninstall

编译安装 OVS-DPDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# get ovs v2.16.0
wget https://github.com/openvswitch/ovs/archive/refs/tags/v2.16.0.zip
# 安装依赖包
sudo apt install build-essential fakeroot
dpkg-checkbuilddeps # 检查依赖并手动安装缺少的模块
#####################################################

cd ovs-2.16.0
./boot.sh
./configure --with-dpdk=static CFLAGS="-Ofast -msse4.2 -mpopcnt"
make -j # 多线程编译

# 单元测试(可以跳过)
make check TESTSUITEFLAGS=-j8

# 安装 ovs
sudo make install

# 启动工具 ovs-ctl
echo 'export PATH=$PATH:/usr/local/share/openvswitch/scripts' | tee -a /root/.bashrc
echo 'export DB_SOCK=/usr/local/var/run/openvswitch/db.sock' | tee -a /root/.bashrc

# 查看是否启用了 dpdk
ovs-vswitchd --version
# ovs-vswitchd (Open vSwitch) 2.16.0
# DPDK 20.11.5

如果make -j编译时,出现错误:

1
2
3
4
5
6
  File "/usr/lib/python3/dist-packages/OpenSSL/__init__.py", line 8, in <module>
from OpenSSL import crypto, SSL
File "/usr/lib/python3/dist-packages/OpenSSL/crypto.py", line 3279, in <module>
_lib.OpenSSL_add_all_algorithms()
AttributeError: module 'lib' has no attribute 'OpenSSL_add_all_algorithms'
make: *** [Makefile:6819: lib/vswitch-idl.ovsidl] Error 1

根据这篇文章的解决办法:

Upgrading pip to the latest version will probably fix the issue for you.

1
python3 -m pip install --upgrade pip

If this doesn’t seem to be enough, you will then have to upgrade pyOpenSSL. You need to make sure that the install pyopenssl version is greater than v22.1.0 therefore,

1
2
3
4
python3 -m pip install --upgrade openssl

# alternatively
python3 -m pip install openssl>22.1.0

If for any reason you can’t upgrade openssl (due to conflicts with other dependencies you have) the last resort (which I wouldn’t recommend otherwise), is to downgrade cryptography module to an older version:

1
python3 -m pip install cryptography==38.0.4

生成Docker镜像

前提:主机上先安装好OVS!

注意:docker与宿主机是共享内核的!,即使是在 docker 中使用 OVS,无论是基于内核的还是基于 DPDK 的,都会用到内核模块openvswitch,只有在主机上安装 OVS 后才带有这个模块,并且每次关机、重启后,都需要重新加载modprobe该模块,否则在docker中启动 OVS 时会报下面的错误:

1
2
3
4
5
6
7
8
9
10
11
root@72a4b64ba608:~# ovs-ctl start
* /usr/local/etc/openvswitch/conf.db does not exist
* Creating empty database /usr/local/etc/openvswitch/conf.db
nice: cannot set niceness: Permission denied
* Starting ovsdb-server
* system ID not configured, please use --system-id
* Configuring Open vSwitch system IDs
/usr/local/share/openvswitch/scripts/ovs-kmod-ctl: 112: modprobe: not found ############# !!!! ################
* Inserting openvswitch module
/usr/local/share/openvswitch/scripts/ovs-kmod-ctl: 112: rmmod: not found
* removing bridge module

上述原因是,启动 OVS 时要判断内核中是否有 openvswitch 模块,如果没有,就需要加载(通过命令 modprobe),但 docker 中并没有 modprobe 命令,因此报错,解决办法就是在主机上先加载该模块到内核(前提是主机上安装过OVS):

1
sudo modprobe openvswitch

基于内核的 Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
FROM ubuntu:20.04 as build
ARG ovs_version=2.16.3

RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential fakeroot cmake wget unzip \
graphviz autoconf automake debhelper dh-autoreconf libssl-dev libtool python3-all python3-sphinx \
python3-twisted python3-zope.interface libunbound-dev libunwind-dev

WORKDIR /opt

# 下载编译 OVS
RUN wget https://codeload.github.com/openvswitch/ovs/zip/refs/tags/v${ovs_version} -O ovs-${ovs_version}.zip \
&& unzip ovs-${ovs_version}.zip

RUN cd ovs-${ovs_version} \
&& ./boot.sh \
&& ./configure --with-linux=/lib/modules/$(uname -r)/build \
&& make -j \
&& make install

#####################################################
FROM ubuntu:20.04

# 复制编译后的文件
COPY --from=build /usr/local /usr/local/
WORKDIR /root

RUN apt-get update \
&& apt-get -y --no-install-recommends install python3-all iproute2 net-tools \
vim iperf iftop tcpdump \
&& ldconfig \
&& echo 'export PATH=$PATH:/usr/local/share/openvswitch/scripts' | tee -a /root/.bashrc \
&& echo 'export DB_SOCK=/usr/local/var/run/openvswitch/db.sock' | tee -a /root/.bashrc

基于 DPDK 的 Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
FROM ubuntu:20.04 as build
ARG dpdk_version=20.11.5
ARG ovs_version=2.16.3

RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential python3-pip liblua5.3-dev \
cmake wget unzip libnuma-dev pciutils libpcap-dev libelf-dev linux-headers-generic \
&& pip3 install meson ninja pyelftools

WORKDIR /opt

# 下载编译 DPDK
RUN wget -q https://fast.dpdk.org/rel/dpdk-${dpdk_version}.tar.xz \
&& tar xf dpdk-${dpdk_version}.tar.xz

RUN cd dpdk-stable-${dpdk_version} \
&& meson build \
&& ninja -C build \
&& ninja -C build install \
&& cp -r build/lib /usr/local/

# 下载编译 OVS
RUN wget https://codeload.github.com/openvswitch/ovs/zip/refs/tags/v${ovs_version} -O ovs-${ovs_version}.zip \
&& unzip ovs-${ovs_version}.zip

RUN cd ovs-${ovs_version} \
&& ./boot.sh \
&& ./configure --with-dpdk=static CFLAGS="-Ofast -msse4.2 -mpopcnt" \
&& make -j \
&& make install

#####################################################
FROM ubuntu:20.04

# 复制相关文件
COPY --from=build /usr/local /usr/local/
WORKDIR /root

RUN apt-get update \
&& apt-get -y --no-install-recommends install liblua5.3 libnuma-dev pciutils \
libpcap-dev python3 iproute2 net-tools iputils-ping vim iperf iftop tcpdump \
&& ldconfig \
&& echo 'export PATH=$PATH:/usr/local/share/openvswitch/scripts' | tee -a /root/.bashrc \
&& echo 'export DB_SOCK=/usr/local/var/run/openvswitch/db.sock' | tee -a /root/.bashrc

自定义 OVS-DPDK 的 Dockerfile

如果对OVS,DPDK有任何修改,需要将源代码拷贝到容器中进行编译,准备一个文件夹,并准备以下文件:

1
2
3
4
Dockerfile
dpdk-stable-20.11.5 # DPDK的源码
ovs-2.16.0 # OVS的源码
bin # 其他一些可执行文件

Dockerfile 文件中的内容如下:

为了避免重复编译,不要使用COPY . .,并且COPY文件应该分别运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
FROM ubuntu:20.04 as build
ARG dpdk_version=20.11.5
ARG ovs_version=2.16.0

RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential python3-pip liblua5.3-dev \
cmake wget libnuma-dev pciutils libpcap-dev libelf-dev linux-headers-generic \
&& pip3 install meson ninja pyelftools

WORKDIR /opt

# 将本地文件复制到docker中
# 编译 DPDK,COPY 文件夹时必须指定目的文件夹名!
COPY dpdk-stable-${dpdk_version} dpdk-stable-${dpdk_version}
RUN cd dpdk-stable-${dpdk_version} \
&& meson build \
&& ninja -C build \
&& ninja -C build install \
&& cp -r build/lib /usr/local/

# 编译 OVS
COPY ovs-${ovs_version} ovs-${ovs_version}
RUN cd ovs-${ovs_version} \
&& sh boot.sh \
&& ./configure --with-dpdk=static CFLAGS="-Ofast -msse4.2 -mpopcnt" \
&& make -j \
&& make install

#####################################################
FROM ubuntu:20.04

# 复制编译后的文件
COPY --from=build /usr/local /usr/local/
WORKDIR /root

RUN apt-get update \
&& apt-get -y --no-install-recommends install liblua5.3 libnuma-dev pciutils \
libpcap-dev python3 iproute2 net-tools iputils-ping vim iperf iftop tcpdump \
&& ldconfig \
&& echo 'export PATH=$PATH:/usr/local/share/openvswitch/scripts' | tee -a /root/.bashrc \
&& echo 'export DB_SOCK=/usr/local/var/run/openvswitch/db.sock' | tee -a /root/.bashrc

# 复制其他可执行文件
COPY bin/* /usr/bin/

若使用 apt-get update 时比较慢,可以在上方更换阿里云源。

1
2
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \
&& apt-get clean

Pktgen 和 testpmd 的 Dockerfile

pktgen 用来生成、发送数据包,testpmd 用来接收数据包,两者都是针对DPDK的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
FROM ubuntu:20.04 as build
# 指定使用的DPDK, pktgen 版本
ARG dpdk_version=20.11.5
ARG pktgen_version=20.11.3

RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential python3-pip liblua5.3-dev \
cmake wget libnuma-dev pciutils libpcap-dev libelf-dev linux-headers-generic \
&& pip3 install meson ninja pyelftools

WORKDIR /opt

# 下载编译 DPDK
RUN wget -q https://fast.dpdk.org/rel/dpdk-${dpdk_version}.tar.xz \
&& tar xf dpdk-${dpdk_version}.tar.xz

RUN cd dpdk-stable-${dpdk_version} \
&& meson build \
&& ninja -C build \
&& ninja -C build install \
&& cp -r build/lib /usr/local/

# patch to make pktgen compile on arm. Got tip from
# https://medium.com/codex/nvidia-mellanox-bluefield-2-smartnic-dpdk-rig-for-dive-part-ii-change-mode-of-operation-a994f0f0e543
RUN sed -i 's/# error Platform.*//' /usr/local/include/rte_spinlock.h
RUN sed -i 's/# error Platform.*//' /usr/local/include/rte_atomic_32.h

# downlaod and unpack pktgen
RUN wget -q https://git.dpdk.org/apps/pktgen-dpdk/snapshot/pktgen-dpdk-pktgen-${pktgen_version}.tar.gz \
&& tar xf pktgen-dpdk-pktgen-${pktgen_version}.tar.gz

# building pktgen
RUN cd pktgen-dpdk-pktgen-${pktgen_version} \
&& tools/pktgen-build.sh clean \
&& tools/pktgen-build.sh buildlua \
&& cp -r usr/local /usr/ \
&& mkdir -p /usr/local/share/lua/5.3/ \
&& cp Pktgen.lua /usr/local/share/lua/5.3/

#####################################################
FROM ubuntu:20.04

COPY --from=build /usr/local /usr/local/
WORKDIR /root

RUN apt-get update \
&& apt-get -y --no-install-recommends install liblua5.3 libnuma-dev pciutils libpcap-dev python3 iproute2 \
&& ldconfig

生成镜像:docker build -t pktgen:20.11.3 .

OVS 启动及配置

基于内核的数据通路时,OVS启动需要配置的内容不多!但基于OVS-DPDK的数据通路,涉及到的参数设置比较麻烦!

基于内核数据通路

以默认参数启动可直接使用ovs-ctl命令。

1
ovs-ctl start

基于 DPDK 的数据通路

DPDK的数据通路需要一些额外的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 删除旧的配置信息
rm /usr/local/etc/openvswitch/*
rm /usr/local/var/run/openvswitch/*
rm /usr/local/var/log/openvswitch/*

## 0. 设置hugepages
dpdk-hugepages.py -p 1G --setup 4G

## 1. 启动ovsdb,先不启动ovs-vswitchd
ovs-ctl --no-ovs-vswitchd start --system-id=random

## 2. 配置使用DPDK,可以配置从任何给定 NUMA 节点使用的内存量
ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x02
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024"
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true

## 3. 启动 ovs-vswitchd (启动完成)
ovs-ctl --no-ovsdb-server --db-sock="$DB_SOCK" start

以上面的方式启动时,无法指定相关文件的路径,下面是最原始的启动流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 创建数据库文件
mkdir -p /usr/local/etc/openvswitch
ovsdb-tool create /usr/local/etc/openvswitch/conf.db \
/usr/local/share/openvswitch/vswitch.ovsschema

# 启动数据库
mkdir -p /usr/local/var/run/openvswitch
mkdir -p /usr/local/var/log/openvswitch
ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \
--remote=db:Open_vSwitch,Open_vSwitch,manager_options \
--private-key=db:Open_vSwitch,SSL,private_key \
--certificate=db:Open_vSwitch,SSL,certificate \
--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
--pidfile --detach --log-file

# 初始化数据库
ovs-vsctl --no-wait init

# 配置使用DPDK, pmd-cpu-mask 要用16进制
ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x6
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024"
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true

# 启动 Open vSwitch 守护进程
ovs-vswitchd --pidfile --detach --log-file=/root/logfile/ovs-vswitchd.log

相关资料