ipsec.c 编译问题修复记录:vici_conn_t 不透明类型与链接错误排查
ipsec.c 编译问题修复记录
一、原始编译错误
source/ipsec.c:37:17: error: field 'conn' has incomplete type 'vici_conn_t'
二、根因分析
include/libvici.h 中 vici_conn_t 是不透明类型(opaque type),只有前向声明,没有结构体定义:
typedef struct vici_conn_t vici_conn_t; // 仅声明,无定义
编译器不知道 vici_conn_t 的大小,所以不能在结构体中按值(by value)嵌入 vici_conn_t conn,必须用指针。
libvici 的 API 全部通过指针操作:
vici_connect()返回vici_conn_t *(堆上分配)vici_disconnect()接受vici_conn_t *vici_register()、vici_submit()等也都接受vici_conn_t *
三、修复内容(source/ipsec.c)
3.1 结构体字段改为指针
// 修改前
typedef struct {
vici_conn_t conn; // 编译错误:不完整类型
int connected;
int handleRegister;
int hbStatus;
uint32_t hbCnt;
} oam_ipsec_t;
// 修改后
typedef struct {
vici_conn_t *conn; // 改为指针
int handleRegister;
int hbStatus;
uint32_t hbCnt;
} oam_ipsec_t;
3.2 修复错误的类型转换(第136行)
// 修改前
oam_ipsec_t *oamIpsec = (vici_conn_t *)sc_ipsec->pdata;
// 修改后
oam_ipsec_t *oamIpsec = (oam_ipsec_t *)sc_ipsec->pdata;
3.3 memcpy 改为直接指针赋值
// 修改前(两处)
memcpy(&oamIpsec->conn, viciConn, sizeof(vici_conn_t));
// 修改后
oamIpsec->conn = viciConn;
sizeof(vici_conn_t) 对不透明类型也编译不过,所以 memcpy 方式根本行不通。
3.4 去掉取地址符 &
oamIpsec->conn 已是指针,不再需要 &。
// 修改前 // 修改后
sync_existing(&oamIpsec->conn); sync_existing(oamIpsec->conn);
vici_register(&oamIpsec->conn, ...) vici_register(oamIpsec->conn, ...)
vici_submit(req, &oamIpsec->conn) vici_submit(req, oamIpsec->conn)
vici_disconnect(&oamIpsec->conn) vici_disconnect(oamIpsec->conn)
3.5 删除冗余的 connected 字段
connected 和 conn == NULL 完全等价,删掉用一个状态即可。
// 删除前 // 删除后
if (oamIpsec->connected == 0) { if (oamIpsec->conn == NULL) {
oamIpsec->connected = 1; // 删除
...
oamIpsec->connected = 0; oamIpsec->conn = NULL;
...
oamIpsec->connected = 0; oamIpsec->conn = NULL;
每次 vici_disconnect() 后必须将 conn 置 NULL,否则 conn 变为悬空指针(dangling pointer)。
四、关于局部变量 viciConn 的说明
launch_ipsec_mod_unix_listener() 和 ipsec_timeout() 函数中 viciConn 确实是栈变量,但:
vici_conn_t *viciConn = vici_connect(...); // viciConn = 栈上的指针变量
// 指向的对象 = vici_connect() 内部在堆上分配
oamIpsec->conn = viciConn; // 复制地址到 oamIpsec->conn
// 函数结束:viciConn 栈变量销毁
// 但 oamIpsec->conn 仍然指向堆上的 vici_conn_t 对象,有效!
指针变量在栈上,但指针指向的 vici_conn_t 对象在堆上,函数返回后依然有效,无悬空指针问题。
五、后续链接错误(独立于 ipsec.c 修改)
../conf/lib/ipsec/libstrongswan.so: undefined reference to `gettid@GLIBC_2.30'
原因
libstrongswan.so 在 glibc >= 2.30 的环境下编译,依赖 gettid@GLIBC_2.30。但交叉编译环境的 rootfs(/home/xx/rootfs_lsdk2004_bsp1.9_dpdk)的 glibc 版本低于 2.30,不提供此符号。
为什么 Python 3.8 配置能过?
查看 Makefile:
# Python 3.6 的 LIBS 配置(不含 --allow-shlib-undefined)
LIBS += -lpython3.6m
Python 3.8 的 LIBS 配置(含 --allow-shlib-undefined)
LIBS += -L../conf/lib/python3.8.10/lib/python3.8/config-3.8-aarch64-linux-gnu
-lpython3.8 ... -Wl,--allow-shlib-undefined
-Wl,--allow-shlib-undefined 让链接器在链接共享库时不检查未定义符号,所以 Python 3.8 配置下链接可以通过。但运行时如果实际调用了 gettid,程序启动会崩溃(undefined symbol: gettid)。
解决方案(三选一)
| 方案 | 说明 | 优缺点 |
|---|---|---|
| ① 重新编译 strongSwan | 用当前交叉编译器(rootfs glibc < 2.30)重新编译 libstrongswan.so | 最彻底的解决,但需要 strongSwan 源码 |
| ② 升级 rootfs glibc | 将 rootfs 的 glibc 升级到 2.30+ | 可能影响整个系统 |
| ③ 加 --allow-shlib-undefined | 链接时跳过检查 | 只是绕过,运行时可能有风险 |
更多推荐


所有评论(0)