HP ops 目前已过时,现在主导 openswitch 项目的是 DELL 和 SnapRoute,主推 DELL NAS + SnapRoute Flexswitch (称为 opx)。
本文 openswitch 指 HP ops。记录以前移植 openswtich 到 arm CPU 的过程。
1. BSP 适配
1.1. 新增一个新产品
在目录 yocto/openswitch/
下新建 meta-platform-openswitch-[product]
,其中 product 对应新增的产品名字,可以从已有的产品目录拷贝。以 xxx 为例子:
使用 cp 命令,拷贝其他产品目录为
meta-platform-openswitch-xxx
:1
cp meta-platform-openswitch-as6712 meta-platform-openswitch-xxx –r
删除
recipes-kernel
以外的配方目录(以recipes-*
开头的)- 将目录下所有文件的中 as6712 修改为 xxx,主要有以下几个文件:
conf/machine/as6712.conf
重命名为conf/machine/xxx.conf
conf/layer/conf
README
rules.make
recipes-kernel
子目录下的*.bbappend
中的PR_append
- 根据 cpu 架构适配
conf/machine/xxx.conf
文件,xxx 的 cpu 是 arm cortexa9 系列,其中DEFAULTTUNE
定义表示不支持硬件 FPU。
1 | DEFAULTTUNE ?= "core2-64" |
- 根据产品支持的内核版本,修订
PREFERRED_VERSION_linux-ops
参数 - 暂时屏蔽
MACHINE_FEATURES
和MACHINE_ESSENTIAL_EXTRA_RDEPENDS
,根据需要添加
1.2. 添加一个新内核版本支持
- 在目录
yocto/openswitch/meta-distro-openswitch/recipes-kernel/linux/
新增linux-ops_[version].bb
文件,可以从其他版本复制 - 修订 *.bb 文件
- 对应内核版本号,
KERNEL_RELEASE = "3.10.18"
- 对应内核源码下载地址,当前为本地地址
SRC_URI = http://192.168.x.x/linux-3.10.18.tar.gz;name=kernel
- 对应源码的 md5sum 值(可以使用 linux md5sum 工具计算),
SRC_URI[kernel.md5sum] = "e19cbb242d776223c337e10a31ca9865"
- 对应源码的 sha256sum 值(可以使用 linux sha256sum 工具计算),
SRC_URI[kernel.sha256sum] = "a11abd0ac80c6195aaab16c8be3e97c07c705d0ee135f3c5c092a99c4973b1be"
- 对应内核版本号,
备注:两个 checksum 和下载地址要保证正确,不然编译的时候会出错
- 由于 openswitch 的 linux-ops 不支持设备树,需要新增文件
linux-dtb.inc
,并且修订文件linux.inc
:
1 | LOCALVERSION ?= "" |
- 适配 xxx,新增文件:
1 | yocto meta-platform-openswitch-xxx dtc/dtc_git.bbappend |
- 在
meta-platform-openswitch-xxx/recipes-kernel/linux/linux-ops/
增加内核配置文件以及产品需要的 patch文件
1.3. 适配完成之后,使用 make kernel
编译内核模块
no log。
1.4. 调试问题汇总
- Open-switch 内核默认编译出来的 image 是 zimage,我的设备 uboot 比较老,不支持这种格式;可以通过在
xxx.config
中新增KERNEL_IMAGETYPE = "uImage"
来指定成 uimage 格式。 - 在设备树编译的时候,需要指定目录的在内核的绝对地址,不能单单执行个xx.dts:
KERNEL_DEVICETREE = "${S}/arch/arm/boot/dts/zzz_yyy.dts"
- 内核编译出来的 image 如果使用 uImage 或者 zImage 的时候,内核需要打开以下配置,并且 cpu 产品目录需要有这个文件
arch/arm/mach-yyy/include/mach/uncompress.h
,否则会出现调整内核之后死机:
1 | CONFIG_BLK_DEV_INITRD=y |
- 如果使用的 uImage 或者 zImage 格式加载,内核的入口函数是
arch/arm/boot/bootp/init.S
中,这个文件主要是跳转到misc.c
自解压内核 image,然后跳转到真正的内核执行。 - 如果出现自解压完成,调整到真正内核执行的时候无 log 输出,可以将内核的
early debug
打开,具体配置宏如下:
1 | CONFIG_DEBUG_LL=y |
- 如果出现以下的错误 log,是由于 uboot 未传入正确的设备树或者参数导致:
1 | 10-21-09:30:03.036:Uncompressing Linux... done, booting the kernel. |
- 使用
bootm
命令可以带两地址,第一个表示 image 的地址,第二个表示设备树地址,bootm 62000000 - 62400000
。
1.5. kernel defconfig
1.6. 支持 systemd 的 kernel defconfig
这里的 defconfig 不全是支持 systemd 所需配置。
支持 systemd 所需配置见 systemd README,注意不同的 systemd 版本可能对内核的配置要求不一样。
1 | diff --git a/yocto/openswitch/meta-platform-openswitch-xxx/recipes-kernel/linux/linux-ops/defconfig b/yocto/openswitch/meta-platform-openswitch-xxx/recipes-kernel/linux/linux-ops/defconfig |
2. gcc tune
2.1.rootfs 不可用
xxx cpu 为 arm cortex-a9 芯片。DEFAULTTUNE
置为 cortexa9
或 cortexa9-neon
时,编译出来的 rootfs 不可用:
启机运行时,会出现 undefined instruction
,内核 kill init 退出:
1 | init (1): undefined instruction: pc=b6ebcbdc |
这个问题排查了约两个星期,排查的方向:
- 内核是否支持 systemd?
根据 systemd 官方说明文档配置内核,启机还是挂在同样的地方; - rootfs 的格式是不是有问题(ubifs 还是 ext3)?
把 rootfs 改为 ubifs,启机还是挂在同样的地方; - 反汇编
通过objdump
vmlinux 或看system map table,都没有对应 PC 值。这个 undefined instruction 的意思应该就是说明没有这个指令,所以不用看了,找也找不着。
偶然的机会,与同事的讨论中,他曾经在某个产品上使用 debian 8 (默认采用 systemd) 的 rootfs 跑过。因此通过 ops-build 编译的 kernel + debian 8 rootfs (U盘启动)确认内核没有问题。
既然内核没有问题,那就得看 debian jessie arm 版本编译的结果与 ops-build 编译结果的差异,通过 readelf -A systemd
查看 systemd 编译结果的架构相关信息,发现了差异:
不可用的 rootfs:
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/rgosm-build/prj_xxx/images/rootfs/lib/systemd$ arm-cortex_a9-linux-gnueabi-readelf -A systemd |
可用的 rootfs:
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/rgosm-build/prj_xxx/images/rootfs$ arm-cortex_a9-linux-gnueabi-readelf -A lib/systemd/systemd |
主要差异在 NEON、VFP 和 HardFP 上。因尝试改 tune-cortexa9.inc
等相关文件调整默认 FPU 等编译选项,但是一直修改失败,因此换了个思路,看 debian porting to arm 用了什么编译选项。详见 debian 移植到 arm 32 的编译选项 ,根据文中的建议 tune gcc。
2.2. tune gcc
- 配置
yocto/openswitch/meta-platform-openswitch-xxx/conf/machine/xxx.conf
,改DEFAULTTUNE
为armv4t
1 | DEFAULTTUNE ?= "armv4t" |
- 配置
yocto/poky/meta/conf/machine/include/arm/arch-arm.inc
,改TARGET_FPU
为soft
,添加选项-mabi=aapcs-linux
- 配置
yocto/poky/meta/conf/machine/include/arm/feature-arm-neon.inc
和yocto/poky/meta/conf/machine/include/arm/feature-arm-vfp.inc
,把 FPU 相关配置改为 soft。
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/ops-build.rj$ git diff yocto/poky/meta/conf/machine* |
2.3. 关于 xxx CPU 是否支持 NEON 和 VFP
xxx CPU 的芯片手册上有明确写支持 NEON 和 VFP,但是不清楚如何使能 NEON,是否要在上电和通过特定配置使能?
通过 cat /proc/cpuinfo
可以看出芯片不支持 NEON 和 VFP,但是 /proc/cpuinfo 能完全体现 CPU features 吗?
PS:内核有明确打开了配置 CONFIG_NEON=y
与 CONFIG_VFP=y
。
1 | root@ops-xxx:~# cat /proc/cpuinfo |
通过查阅资料发现 NEON 应该是在系统运行时使能的:
内核在遇到第一个NEON指令时会产生一个Undefined Instruction的异常,这会让内核自动重启NEON协处理器,内核还可以在上下文切换时关闭NEON来省电。
BY 《ARM平台NEON指令的编译和优化》
以及:
arm 论坛 “How to enable Neon in cortex A8?“
Yes you can’t enable it directly from user mode you have to have the privilege though the startup code for the process or an interrupt when such an instruction is first used should do that normally. For the actual instructions needed have you seen: ARM Compiler armcc User Guide : 5.5 Enabling NEON and FPU for bare-metal
直接在 uboot 中修订?http://lists.denx.de/pipermail/u-boot/2015-January/201269.html
TODO 后续再做验证。
FPU 基本只应用于图像处理、音视频处理,与我们无关,因此可以放心不用。
3. 编译问题及修订记录
3.1. python xattr 在 x86 平台上直接使用交叉编译结果
问题 log:
1 | NOTE: Preparing RunQueue |
原因:见 github issue
I don’t think it’s a cffi issue. I tried to cross compile for a 32 bit system from a 64 bit system. cffi module cffi_backend.so compiled OK for the target (that is 32 bit). The problem is that when cryptography tries to pre-cross compile (for 32 bit) cffi modules (_Cryptography_cffi*.so), it uses (host) 64 bit compiler flags and tries to load the 32 bit cross compiled _cffi_backend.so. This is why you get “wrong ELF class: ELFCLASS32”.
There needs to be some way to configure the C compiler flags from within the cryptography package while cross compiling the cffi modules. You can see how cffi module itself is allowing that in its setup.py file. Another python package I was able to configure the target c flags is python readline.
I got around this problem (dirty hack) by skipping the cffi modules pre-cross compilation process (Cryptography_cffi*.so) and copying (during the build time) those modules I compiled on the target system.
这种交叉编译时在 build 系统上直接使用编译给 host 的结果,很是蛋疼。
解决:
Well I could get it working myself by following midicase comment on vincentbernat/snimpy.
- build and install host cffi
- build and install target packages that depend in cffi
- build and install target cffi
I’ve created a detailed install instructions https://github.com/AndreMiras/km/wiki/CFFI-Cross-Compile.
依葫芦画瓢,也衔把 cffi 编译成 build 主机的结果,后续 ARM 设备上要用的话,再编译一个 ARM 架构的 .so。
优雅的做法是打 patch 改 xattr 编译 cffi 的配置文件,先编译成 build 机可用、再编译成 host 机可用的结果。
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/ops-build.rj/build/tmp/work/cortexa9-vfp-neon-openswitch-linux-gnueabi/python-xattr/0.8.0-r0/xattr-0.8.0/xattr/__pycache__$ gcc -o _cffi__xf88a1d89x3f40c4a9.so _cffi__xf88a1d89x3f40c4a9.c -shared -I/usr/include/python2.7/ -fPIC |
3.2. go 编译失败
go 编译不过,go 的依赖方是 ops-webui,应该是 web 操作界面相关的东西,目前还用不上直接删了。
1 | | WARNING: exit code 2 from a shell command. |
- 删除 ops-webui.bb
- 删除 recipes-go
- 删除 recipes-nodejs
1 | deleted: yocto meta-distro-openswitch mgmt/ops-webui.bb |
3.3. ops-* 多地方出现 VLOG format 和指针强转 Warning 导致编译失败
这纯粹是 ops 代码的问题,估计没有 porting 到 32 位机上。
出现 warning 的位置实在太多,暂不考虑直接改 .c/.h 源代码。考虑从编译选项入手。
由于带 -Werror
,所以 Warning 会被当成 Error 处理。在 local.conf
中配置 -Wno-error
可体现在编译选项中,但是这个编译选项在 -Werror
之前,经确认,要放在之后才能生效。
因此需要考虑打 patch 删除源码配置文件中编译选项带的 -Werror
。
ops-* 组件使用两种编译工具,CMake 与 autoconf。这里为快速适配,还没有使用打 patch 的方法打补丁。
3.3.1. CMake 类处理
查找所有 CMakeLists.txt
文件,删除文件中的所有 -Werror
。1
find . -name "CMakeLists.txt" | xargs sed -i "s/ -Werror//g"
3.3.2. autoconf 类处理
只有 ops-lldpd
组件用的 autoconf 且出现 warning。
- 删除
build/tmp/stamps
目录内ops-lldpd.do_configure.xxx
,这样做才能重新configure
; - 修改
build/tmp/work/armv4-openswitch-linux-gnueabi/ops-lldpd/gitAUTOINC+fd74e10ef2-r0/git/ 源码
configure.ac文件,将其中的
-Werror` 选项删除。
1 | diff --git a/configure.ac b/configure.ac |
这个定义没有的使用地方没有写好,导致好多 ops-lldpd 强转的地方编译不过:
1 | 104 /* |
log:
1 | /home/sunyongfeng/workshop/ops-build.rj/build/tmp/work/cortexa9-vfp-neon-openswitch-linux-gnueabi/ops-lldpd/gitAUTOINC+fd74e10ef2-r0/git/src/snmp/lldpPortConfigTable_interface.c: In function '_lldpPortConfigTable_get_column': |
3.4. openswitch-disk-image.bb task do_rootfs
失败
原因:usermod 命令找不到 group ovsdb-client 等 group。log:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20| NOTE: Performing usermod with [-R /home/sunyongfeng/workshop/ops-build.rj/build/tmp/work/xxx-openswitch-linux-gnueabi/openswitch-disk-image/1.0-r0/rootfs -g ovsdb-client opsd] and 1 times of retry
| usermod: group 'ovsdb-client' does not exist
| Server refused shutdown. Remaining client fds: 2
| Client pids: 2799 8830
| Server will shut down after all clients exit.
| WARNING: usermod command did not succeed. Retrying...
| ERROR: Tried running usermod command 1 times without success, giving up
| WARNING: exit code 1 from a shell command.
| DEBUG: Python function do_rootfs finished
| ERROR: Function failed: set_user_group (log file is located at /home/sunyongfeng/workshop/ops-build.rj/build/tmp/work/xxx-openswitch-linux-gnueabi/openswitch-disk-image/1.0-r0/temp/log.do_rootfs.2799)
ERROR: Task 7 (/home/sunyongfeng/workshop/ops-build.rj/yocto/openswitch/meta-distro-openswitch/recipes-core/images/openswitch-disk-image.bb, do_rootfs) failed with exit code '1'
NOTE: Tasks Summary: Attempted 4408 tasks of which 4407 didn't need to be rerun and 1 failed.
No currently running tasks (4405 of 4411)
Summary: 1 task failed:
/home/sunyongfeng/workshop/ops-build.rj/yocto/openswitch/meta-distro-openswitch/recipes-core/images/openswitch-disk-image.bb, do_rootfs
Summary: There was 1 WARNING message shown.
Summary: There was 1 ERROR message shown, returning a non-zero exit code.
tools/Rules.make:216: recipe for target '_fs' failed
make: *** [_fs] Error 1
看 rootfs 里面,没有看到 group 没有 ops_admin、ovsdb-client 等。而 yocto/openswitch/meta-distro-openswitch/classes/openswitch-image.bbclass
中的 EXTRA_USER_PARAMS 有添加用户到这几个 group 中。
1 | inherit core-image extrausers |
而 yocto/openswitch/meta-distro-openswitch/recipes-ops/openvswitch/ops-openvswitch.bb
中有配置添加 group:
1 | GROUPADD_PARAM_${PN} ="-g 1020 ovsdb-client;ops_netop;ops_admin" |
这个配置没在 rootsf 中生效:
1 | sunyongfeng-380:~/workshop/ops-build.rj/build/tmp/work/xxx-openswitch-linux-gnueabi/openswitch-disk-image/1.0-r0/rootfs$ cat etc/group -OptiPlex |
因此,在usermod 使用不存在的 group 前,先执行 groupadd。
1 | diff --git a/yocto/openswitch/meta-distro-openswitch/classes/openswitch-image.bbclass b/yocto/openswitch/meta-distro-openswitch/classes/openswitch-image.bbclass |
4. 编译太慢?
4.1. 下载源码慢的问题
编译的时候,会实时下载要编译的源代码包,由于 GFW 的缘故,代码下载得很慢,导致整个工程编译时间超长。因此可一次下载,多次使用,改 DL_DIR
。
- 原始位置,
tools/config/local.conf.in
和tools/config/site.conf.in
- 在
make configure xxx
之后,亦可直接修订build/conf/local.conf
4.2. 如果使用已编译的结果
利用 yocto sstate 特性。配置 SSTATE_DIR
4.1. 和 4.2. 的配置修订如下:
1 | diff --git a/tools/config/local.conf.in b/tools/config/local.conf.in |
4.3. parse recipe 实在太慢
改 ops-* 的源码路径为 github。但是 ops-tunnel github 上面还没有,需要自己改 DL_DIR 中的 ops-tunnel 包名。
1 | DL_DIR 请改成你自己的 DL_DIR |
patch:
1 | diff --git a/yocto/openswitch/meta-distro-openswitch/conf/distro/openswitch.conf b/yocto/openswitch/meta-distro-openswitch/conf/distro/openswitch.conf |
5. 其他配置
5.1. 如何新增 CFLAG、LDFLAG 选项?
在 local.conf 中添加对应 FLAG,以 -Wno-error 为例。
1 | BUILD_CFLAGS += " -Wno-error " |
5.2. 使用 pre-built 交叉编译工具链(linaro)
FAIL。
可研究 SDK,将交叉编译链一次编出,后续无需再编译。
5.3. 配置 ops-switchd-p4switch-plugin
修改 machine 的 conf,yocto/openswitch/meta-platform-openswitch-xxx/conf/machine/xxx.conf
:
1 | PREFERRED_PROVIDER_virtual/ops-switchd-switch-api-plugin ?= "ops-switchd-p4switch-plugin" |
官方 README 的说明应已过时:
The P4 plugin is activated adding the following line in /build/conf/local.conf EXTRA_IMAGE_FEATURES = “ops-p4” (use += if other image features are defined)
https://github.com/open-switch/ops-switchd-p4switch-plugin
6. 运行问题记录与解决
6.1. ops-switchd-p4switch-plugin 没有打包到 rootfs
6.2. 运行时出现 rsyslog、ops-init.servic 等业务起不来
log 如下:
1 | [20161110:184441.388][FAILED] Failed to start openswitch first boot process. |
进一步看 log:所有问题都是 open("/proc/self/ns/net"): No such file or directory
,原因是内核配置 namespace 没有开启。
1 | [20161110:184548.411]ops-xxx:~$ systemctl status ops-first-boot.service |
对应的 namespace 内核配置:
1 | CONFIG_NAMESPACES=y |
6.3. P4 交换机模拟器启动失败
log:
1 | [FAILED] Failed to start P4 Switch simulation Daemon. |
原因:内核配置没有开启支持 VNET
1 | ops-xxx:~$ systemctl status simple_switch.service |
6.4. CLI 不可用
log:
1 | root@ops-xxx:~# vtysh |
ip netns exec emulns ip tuntap add mode tap eth0
ip netns exec emulns ifconfig eth0 up
查看 bmv2 runtime command line 命令:https://github.com/p4lang/behavioral-model/blob/master/tools/runtime_CLI.py
runtime cli:ip netns exec emulns /usr/sbin/simple_switch -i 64@veth250 –thrift-port 10001 –nanolog ipc:///tmp/bm-log.ipc /usr/share/ovs_p4_plugin/switch_bmv2.json
1 | #!/bin/bash |
可能需要配置的地方:
- https://github.com/open-switch/ops-build/blob/55c9f56fd3fc7a87cd5c7273374b910998630203/yocto/openswitch/meta-platform-openswitch-genericx86-64/recipes-ops/platform/ops-hw-config.bbappend
- https://github.com/open-switch/ops-hw-config/tree/master/Generic-x86/X86-64/P4
- https://github.com/open-switch/ops-build/blob/55c9f56fd3fc7a87cd5c7273374b910998630203/yocto/openswitch/meta-distro-openswitch/recipes-ops/openvswitch/ops-openvswitch.bb
- IMAGE_FEATURES[validitems] += “ops-p4”
7. 其他问题
x86_64 上的一个 QA 问题
编译时提示:
1 | WARNING: QA Issue: ops-cli rdepends on libcap, but it isn't a build dependency? [build-deps] |
这个问题可能导致编译 ops-cli 时,configure 不过。