From 6b1e4e90ba598a76f89370bcb1cca426f89531f7 Mon Sep 17 00:00:00 2001 From: yangyanjun Date: Thu, 15 Sep 2022 10:15:02 +0800 Subject: [PATCH 1/6] =?UTF-8?q?readme=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- README_zh.md | 67 ++++++++++++++++++---------- figures/image-20220901155226078.png | Bin 5330 -> 0 bytes 2 files changed, 43 insertions(+), 24 deletions(-) delete mode 100644 figures/image-20220901155226078.png diff --git a/README_zh.md b/README_zh.md index 36e5e7b..cbc0fd1 100644 --- a/README_zh.md +++ b/README_zh.md @@ -2,18 +2,23 @@ ## 简介 -NewIP支持可变长多语义地址,可变长定制化报头封装,通过精简报文头开销,提升数据传输效率。 +网络差异化技术需求依赖于灵活的地址空间大小。低功耗物联网场景通过降低网络层封装开销为性能受限设备引入网络协议栈,其要求网络协议使用的地址空间尽可能小。高安全承诺网络场景通过将用户身份标识嵌入地址实现网络层安全验证,其要求网络协议使用地址空间尽可能大。目前IPv4与IPv6的地址空间分别为固定的32比特空间和128比特空间。 -``` -备注: -IPv4地址长度固定4字节,IPv6地址长度固定16字节。 -IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节。 -``` +网络差异化技术需求依赖于灵活的报头封装格式。低功耗物联网场景通过降低网络层封装开销为性能受限设备引入网络协议栈,其要求网络协议封装开销尽可能低。新兴网络场景通过构建自定义封装格式实现定制化的网络能力,要求网络层协议封装字段选择尽可能灵活且具有高可扩展性。目前IPv4与IPv6的报文头封装存在不可变的固定封装字段(IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节)。 + +NewIP支持可变长多语义地址,可变长定制化报头封装,通过精简报文头开销,提升数据传输效率。 NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 ![image-20220901152326770](figures/image-20220901152326770.png) +1) Dispatch:指示封装子类,数值0b0表示其为极简封装子类,长度为1比特;(0b表示后面数值为二进制)。 + +2) Bitmap:变长,Bitmap默认为紧跟在Dispatch有效位后面的7比特,Bitmap字段长度可持续扩展。Bitmap最后一位置0表示Bitmap结束,最后一位置1表示Bitmap向后扩展1 Byte,直至最后一位置0。 +3) Value: 标识字段的值,长度为1 Byte的整数倍,类型及长度由报头字段语义表确定。 + + + NewIP内核协议栈架构图如下,用户态调用Socket API创建NewIP socket,采用NewIP极简帧头封装进行收发包。 ![image-20220901152539801](figures/image-20220901152539801.png) @@ -52,7 +57,7 @@ CONFIG_NEWIP=y 代码编译完成后,通过下面命令可以确认newip协议栈代码是否使能成功。 ```c -root@nip-server:~/harmony_master/harmony# find out/ -name *nip*.o +find out/ -name *nip*.o out/rk3568/obj/third_party/glib/glib/glib_source/guniprop.o out/kernel/OBJ/linux-5.10/net/newip/nip_addrconf_core.o out/kernel/OBJ/linux-5.10/net/newip/nip_hdr_decap.o @@ -70,19 +75,6 @@ out/kernel/OBJ/linux-5.10/net/newip/tcp_nip_output.o ## 说明 -### 报头字段说明 - -NewIP报文格式由NewIP报头与Payload两部分组成,如下图所示: - -![image-20220901155226078](figures/image-20220901155226078.png) - -1) Dispatch:指示封装子类,数值0b0表示其为极简封装子类,长度为1比特;(0b表示后面数值为二进制)。 - -2) Bitmap:变长,Bitmap默认为紧跟在Dispatch有效位后面的7比特,Bitmap字段长度可持续扩展。Bitmap最后一位置0表示Bitmap结束,最后一位置1表示Bitmap向后扩展1 Byte,直至最后一位置0。 -2) Value: 标识字段的值,长度为1 Byte的整数倍,类型及长度由报头字段语义表确定。 - - - ### 可变长地址格式说明 NewIP采用自解释编码,编码格式如下所示: @@ -97,7 +89,6 @@ NewIP采用自解释编码,编码格式如下所示: | 0xDD | An 16-bit address, which is 0 + 256 * (0xDD - 0xDD) + the last byte value | 【2字节】221 ~ 255 (0x**DD**DD ~ 0x**DD**FF) | | 0xDE | An 16-bit address, which is 0 + 256 * (0xDE - 0xDD) + the last byte value | 【2字节】256 ~ 511 (0x**DE**00 ~ 0x**DE**FF) | | 0xDF | An 16-bit address, which is 0 + 256 * (0xDF - 0xDD) + the last byte value | 【2字节】512 ~ 767 (0x**DF**00 ~ 0x**DF**FF) | -| | | | | ... | ... | | | 0xF0 | An 16-bit address, which is 0 + 256 * (0xF0 - 0xDD) + the last byte value | 【2字节】4864 ~ 5119 (0x**F0**00 ~ 0x**F0**FF) | | 0xF1 | An 16-bit address is followed | 【3字节】5120 ~ 65535 (0x**F1** 1400 ~ 0x**F1** FFFF) | @@ -189,9 +180,7 @@ NewIP协议socket接口列表如下: ### 使用说明 -NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如下,NewIP协议栈用户态接口使用方法可以参考demo代码。 - -https://gitee.com/openharmony-sig/communication_sfc_newip/tree/master/examples +NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如下,NewIP协议栈用户态接口使用方法可以参考代码仓demo代码。 | 文件名 | 功能 | | --------------------- | ----------------------------- | @@ -205,6 +194,8 @@ https://gitee.com/openharmony-sig/communication_sfc_newip/tree/master/examples **基础操作步骤:** +1号开发板 ----- eth / wifi AP ----- 2号开发板,两块开发板通过eth网线或wifi AP连接。 + 1、将demo代码拷贝到Linux编译机上,make clean,make all编译demo代码。 2、将编译生成二级制文件上传到xxx开发板。 @@ -268,3 +259,31 @@ Received --1661760203 69254 NIP_TCP # 1 sock 3 success: 2/ 2/no= Received --1661760207 86544 NIP_TCP # 9 sock 3 success: 10/ 10/no= 9 ``` +### selinux规则说明 + +用户态进程操作NewIP socket需要添加selinux policy,否则操作会被拦截。 + +```sh +# base\security\selinux\sepolicy\ohos_policy\xxx\xxx.te +# socket 基础操作 +# avc: denied { create } for pid=540 comm="thread_xxx" scontext=u:r:thread_xxx:s0 tcontext=u:r:thread_xxx:s0 tclass=socket permissive=0 +allow thread_xxx thread_xxx:socket { create bind connect listen accept read write shutdown setopt getopt }; + +# ioctl 操作 +# 操作码在 linux-xxx\include\uapi\linux\sockios.h 中定义 +# 0x8933 : name -> if_index mapping +# 0x8916 : set PA address +# 0x890B : add routing table entry +allowxperm thread_xxx thread_xxx:socket ioctl { 0x8933 0x8916 0x890B }; +``` + +## 相关仓 + +[内核子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%86%85%E6%A0%B8%E5%AD%90%E7%B3%BB%E7%BB%9F.md) + +[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10) + +[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config) + +[kernel_linux_build](https://gitee.com/openharmony/kernel_linux_build) + diff --git a/figures/image-20220901155226078.png b/figures/image-20220901155226078.png deleted file mode 100644 index 5fe124d9130d2bea74d6c6efca190c1bb24de7c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5330 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 Date: Thu, 15 Sep 2022 16:59:43 +0800 Subject: [PATCH 2/6] =?UTF-8?q?readme=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- README_zh.md | 65 +++++++++++++++------------- figures/image-20220901152326770.png | Bin 14905 -> 0 bytes figures/image-20220915140627223.png | Bin 0 -> 14398 bytes figures/image-20220915162621809.png | Bin 0 -> 34600 bytes figures/image-20220915165414926.png | Bin 0 -> 11637 bytes 5 files changed, 35 insertions(+), 30 deletions(-) delete mode 100644 figures/image-20220901152326770.png create mode 100644 figures/image-20220915140627223.png create mode 100644 figures/image-20220915162621809.png create mode 100644 figures/image-20220915165414926.png diff --git a/README_zh.md b/README_zh.md index cbc0fd1..a7debbf 100644 --- a/README_zh.md +++ b/README_zh.md @@ -2,46 +2,40 @@ ## 简介 -网络差异化技术需求依赖于灵活的地址空间大小。低功耗物联网场景通过降低网络层封装开销为性能受限设备引入网络协议栈,其要求网络协议使用的地址空间尽可能小。高安全承诺网络场景通过将用户身份标识嵌入地址实现网络层安全验证,其要求网络协议使用地址空间尽可能大。目前IPv4与IPv6的地址空间分别为固定的32比特空间和128比特空间。 +OpenHarmony目前WiFi协议报文,三层报头和地址开销使得报文开销大,传输效率较低。 -网络差异化技术需求依赖于灵活的报头封装格式。低功耗物联网场景通过降低网络层封装开销为性能受限设备引入网络协议栈,其要求网络协议封装开销尽可能低。新兴网络场景通过构建自定义封装格式实现定制化的网络能力,要求网络层协议封装字段选择尽可能灵活且具有高可扩展性。目前IPv4与IPv6的报文头封装存在不可变的固定封装字段(IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节)。 +![image-20220915162621809](figures/image-20220915162621809.png) -NewIP支持可变长多语义地址,可变长定制化报头封装,通过精简报文头开销,提升数据传输效率。 - -NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 - -![image-20220901152326770](figures/image-20220901152326770.png) - -1) Dispatch:指示封装子类,数值0b0表示其为极简封装子类,长度为1比特;(0b表示后面数值为二进制)。 - -2) Bitmap:变长,Bitmap默认为紧跟在Dispatch有效位后面的7比特,Bitmap字段长度可持续扩展。Bitmap最后一位置0表示Bitmap结束,最后一位置1表示Bitmap向后扩展1 Byte,直至最后一位置0。 -3) Value: 标识字段的值,长度为1 Byte的整数倍,类型及长度由报头字段语义表确定。 +``` +IPv4地址长度固定4字节,IPv6地址长度固定16字节。 +IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节。 +``` +NewIP支持**可变长多语义地址**,**可变长定制化报头封装**,通过精简报文头开销,提升数据传输效率。 +## 系统架构 NewIP内核协议栈架构图如下,用户态调用Socket API创建NewIP socket,采用NewIP极简帧头封装进行收发包。 ![image-20220901152539801](figures/image-20220901152539801.png) - - ## 目录 NewIP内核协议栈主要代码目录结构如下: ``` /foundation/communication/sfc/newip -├── patches -│ └── linux-5.10 # NewIP内核侵入式修改对应的补丁文件 -└── code - ├── common # NewIP 通用代码 - └── linux # NewIP Linux内核代码 - ├── include # NewIP 头文件 - │ ├── linux - │ ├── net - │ └── uapi - └── net - └── newip # NewIP 功能代码 +├── examples # NewIP 用户态样例代码 +├── code +│ ├── common # NewIP 通用代码 +│ └── linux # NewIP Linux内核代码 +│ ├── include # NewIP 头文件 +│ │ ├── linux +│ │ ├── net +│ │ └── uapi +│ └── net +│ └── newip # NewIP 功能代码 +└── figures # ReadMe 内嵌图例 ``` ## 编译构建 @@ -75,7 +69,18 @@ out/kernel/OBJ/linux-5.10/net/newip/tcp_nip_output.o ## 说明 -### 可变长地址格式说明 +### 可变长报头格式 + +NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 + +![image-20220915140627223](figures/image-20220915140627223.png) + +1) Dispatch:指示封装子类,数值0b0表示其为极简封装子类,长度为1比特;(0b表示后面数值为二进制)。 + +2) Bitmap:变长,Bitmap默认为紧跟在Dispatch有效位后面的7比特,Bitmap字段长度可持续扩展。Bitmap最后一位置0表示Bitmap结束,最后一位置1表示Bitmap向后扩展1 Byte,直至最后一位置0。 +3) Value: 标识字段的值,长度为1 Byte的整数倍,类型及长度由报头字段语义表确定。 + +### 可变长地址格式 NewIP采用自解释编码,编码格式如下所示: @@ -194,17 +199,17 @@ NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如 **基础操作步骤:** -1号开发板 ----- eth / wifi AP ----- 2号开发板,两块开发板通过eth网线或wifi AP连接。 +![image-20220915165414926](figures/image-20220915165414926.png) 1、将demo代码拷贝到Linux编译机上,make clean,make all编译demo代码。 -2、将编译生成二级制文件上传到xxx开发板。 +2、将编译生成二级制文件上传到设备1,设备2。 3、执行“ifconfig xxx up”开启网卡设备,xxx表示网卡名,比如eth0,wlan0。 -4、在1号开发板sh下执行“./nip_addr_cfg_demo server”给服务端配置0xDE00(2字节)变长地址,在2号开发板sh下执行“./nip_addr_cfg_demo client”给客户端配置0x50(1字节)变长地址,通过“cat /proc/net/nip_addr”查看内核地址配置结果。 +4、在设备1的sh下执行“./nip_addr_cfg_demo server”给服务端配置0xDE00(2字节)变长地址,在设备2的sh下执行“./nip_addr_cfg_demo client”给客户端配置0x50(1字节)变长地址,通过“cat /proc/net/nip_addr”查看内核地址配置结果。 -5、在1号开发板sh下执行“./nip_route_cfg_demo server”给服务端配置路由,在2号开发板sh下执行“./nip_route_cfg_demo client”给客户端配置路由,通过“cat /proc/net/nip_route”查看内核路由配置结果。 +5、在设备1的sh下执行“./nip_route_cfg_demo server”给服务端配置路由,在设备2的sh下执行“./nip_route_cfg_demo client”给客户端配置路由,通过“cat /proc/net/nip_route”查看内核路由配置结果。 以上步骤操作完成后,可以进行UDP/TCP收发包,收发包demo默认使用上面步骤中配置的地址和路由。 diff --git a/figures/image-20220901152326770.png b/figures/image-20220901152326770.png deleted file mode 100644 index 37823919b253df5831f619fdca0201836e5955a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14905 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 literal 0 HcmV?d00001 diff --git a/figures/image-20220915162621809.png b/figures/image-20220915162621809.png new file mode 100644 index 0000000000000000000000000000000000000000..76a2d26c0af54daf903d70b8cee350bf34e83c78 GIT binary patch literal 34600 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 Bz>5F? literal 0 HcmV?d00001 diff --git a/figures/image-20220915165414926.png b/figures/image-20220915165414926.png new file mode 100644 index 0000000000000000000000000000000000000000..5635e7de0f5ff8a0f02fe778c5f38803e3f1b05a GIT binary patch literal 11637 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 literal 0 HcmV?d00001 -- Gitee From dcb8d3e9d748ba5cc810bca651afb619270cc759 Mon Sep 17 00:00:00 2001 From: yangyanjun Date: Tue, 20 Sep 2022 14:46:52 +0800 Subject: [PATCH 3/6] =?UTF-8?q?newip=E5=86=85=E6=A0=B8=E6=8F=92=E6=A1=A9?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- apply_newip.sh | 6 ++-- code/linux/include/linux/nip.h | 2 -- code/linux/include/trace/hooks/nip_hooks.h | 32 ++++++++++++++++++++++ code/linux/net/newip/Makefile | 6 ++-- code/linux/net/newip/af_ninet.c | 14 +++++++++- code/linux/net/newip/hooks/Kconfig | 20 ++++++++++++++ code/linux/net/newip/hooks/Makefile | 10 +++++++ code/linux/net/newip/hooks/nip_hooks.c | 13 +++++++++ code/linux/net/newip/ninet_hashtables.c | 1 + code/linux/net/newip/nip_hooks_register.c | 32 ++++++++++++++++++++++ code/linux/net/newip/nip_hooks_register.h | 14 ++++++++++ 11 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 code/linux/include/trace/hooks/nip_hooks.h create mode 100644 code/linux/net/newip/hooks/Kconfig create mode 100644 code/linux/net/newip/hooks/Makefile create mode 100644 code/linux/net/newip/hooks/nip_hooks.c create mode 100644 code/linux/net/newip/nip_hooks_register.c create mode 100644 code/linux/net/newip/nip_hooks_register.h diff --git a/apply_newip.sh b/apply_newip.sh index b8cf28c..bf1cfc2 100644 --- a/apply_newip.sh +++ b/apply_newip.sh @@ -40,6 +40,8 @@ function main() ln -s -f $NEWIP_SOURCE_ROOT/code/linux/include/uapi/linux/nip.h $KERNEL_BUILD_ROOT/include/uapi/linux/nip.h ln -s -f $NEWIP_SOURCE_ROOT/code/linux/include/uapi/linux/nip_icmp.h $KERNEL_BUILD_ROOT/include/uapi/linux/nip_icmp.h + ln -s -f $NEWIP_SOURCE_ROOT/code/linux/include/trace/hooks/nip_hooks.h $KERNEL_BUILD_ROOT/include/trace/hooks/nip_hooks.h + ln -s -f $NEWIP_SOURCE_ROOT/code/linux/net/newip $KERNEL_BUILD_ROOT/net ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.c $KERNEL_BUILD_ROOT/net/newip/nip_addr.c ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.h $KERNEL_BUILD_ROOT/net/newip/nip_addr.h @@ -49,10 +51,6 @@ function main() ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_hdr_decap.c $KERNEL_BUILD_ROOT/net/newip/nip_hdr_decap.c ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_hdr_encap.c $KERNEL_BUILD_ROOT/net/newip/nip_hdr_encap.c ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_hdr.h $KERNEL_BUILD_ROOT/net/newip/nip_hdr.h - ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.c $KERNEL_BUILD_ROOT/net/newip/nip_addr.c - ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.c $KERNEL_BUILD_ROOT/net/newip/nip_addr.c - ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.c $KERNEL_BUILD_ROOT/net/newip/nip_addr.c - ln -s -f $NEWIP_SOURCE_ROOT/code/common/nip_addr.c $KERNEL_BUILD_ROOT/net/newip/nip_addr.c cd - } diff --git a/code/linux/include/linux/nip.h b/code/linux/include/linux/nip.h index a80d8b3..2d3192e 100644 --- a/code/linux/include/linux/nip.h +++ b/code/linux/include/linux/nip.h @@ -66,6 +66,4 @@ struct tcp_nip_sock { struct tcp_sock tcp; }; -int find_nip_forward_stamp(struct net *net, void __user *arg); - #endif /* _NIP_H */ diff --git a/code/linux/include/trace/hooks/nip_hooks.h b/code/linux/include/trace/hooks/nip_hooks.h new file mode 100644 index 0000000..9d8c14d --- /dev/null +++ b/code/linux/include/trace/hooks/nip_hooks.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * NewIP Hooks + * + * Copyright (c) 2022, Huawei Tech. Co., Ltd. + */ +#ifdef CONFIG_NEWIP_HOOKS + +/* include/trace/hooks/nip_hooks.h */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM nip_hooks /* Header file name */ +#define TRACE_INCLUDE_PATH trace/hooks /* Header file directory */ + +/* Header files prevent duplicate definitions */ +#if !defined(_TRACE_HOOK_NIP_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_NIP_H +#include +#include + +struct net; +struct nip_addr; +DECLARE_HOOK(ninet_ehashfn_hook, + TP_PROTO(const struct net *net, const struct nip_addr *laddr, const u16 lport, + const struct nip_addr *faddr, const __be16 fport, u32 *ret), + TP_ARGS(net, laddr, lport, faddr, fport, ret) +); +#endif /* end of _TRACE_HOOK_NIP_H */ + +/* This part must be outside protection */ +#include + +#endif /* end of CONFIG_NEWIP_HOOKS */ \ No newline at end of file diff --git a/code/linux/net/newip/Makefile b/code/linux/net/newip/Makefile index c97368e..5cf0307 100644 --- a/code/linux/net/newip/Makefile +++ b/code/linux/net/newip/Makefile @@ -7,7 +7,9 @@ obj-$(CONFIG_NEWIP) += newip.o - newip-objs := nip_addr.o nip_hdr_encap.o nip_hdr_decap.o nip_checksum.o af_ninet.o nip_input.o udp.o protocol.o nip_output.o datagram.o nip_addrconf.o nip_addrconf_core.o route.o nip_fib.o nip_fib_rules.o nndisc.o icmp.o tcp_nip_parameter.o newip-objs += tcp_nip.o ninet_connection_sock.o ninet_hashtables.o tcp_nip_output.o tcp_nip_input.o tcp_nip_timer.o nip_sockglue.o -EXTRA_CFLAGS := -I$(src)/include + +ifeq ($(CONFIG_NEWIP_HOOKS), y) +newip-objs += nip_hooks_register.o +endif diff --git a/code/linux/net/newip/af_ninet.c b/code/linux/net/newip/af_ninet.c index 06a7c85..3d8dbdd 100644 --- a/code/linux/net/newip/af_ninet.c +++ b/code/linux/net/newip/af_ninet.c @@ -44,7 +44,12 @@ #include #include -MODULE_DESCRIPTION("NewiIP protocol stack for linux"); +#ifdef CONFIG_NEWIP_HOOKS +#include +#include "nip_hooks_register.h" +#endif + +MODULE_DESCRIPTION("NewIP protocol stack"); /* The inetsw_nip table contains everything that ninet_create needs to * build a new socket @@ -730,6 +735,13 @@ static int __init ninet_init(void) goto nip_packet_fail; } +#ifdef CONFIG_NEWIP_HOOKS + err = ninet_hooks_register(); + if (err) { + DEBUG("failed to register to nip hooks"); + goto nip_packet_fail; + } +#endif DEBUG("NewIP: init newip address family ok!"); out: diff --git a/code/linux/net/newip/hooks/Kconfig b/code/linux/net/newip/hooks/Kconfig new file mode 100644 index 0000000..83e2e44 --- /dev/null +++ b/code/linux/net/newip/hooks/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (c) 2022 Huawei Device Co., Ltd. +# +# NewIP Hooks configuration +# + +menu "NewIP Hooks" + +config NEWIP_HOOKS + tristate "NewIP Hooks" + depends on VENDOR_HOOKS && NEWIP + default n + help + Enable NewIP hooks implemented as tracepoints + + Allow NewIP modules to attach to tracepoint "hooks" defined via + DECLARE_TRACE or DECLARE_HOOK + +endmenu diff --git a/code/linux/net/newip/hooks/Makefile b/code/linux/net/newip/hooks/Makefile new file mode 100644 index 0000000..62e5a04 --- /dev/null +++ b/code/linux/net/newip/hooks/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2022 Huawei Device Co., Ltd. +# +# Makefile for NewIP Hooks +# + +ccflags-y += -I$(src) # needed for trace events + +obj-$(CONFIG_NEWIP_HOOKS) += nip_hooks.o diff --git a/code/linux/net/newip/hooks/nip_hooks.c b/code/linux/net/newip/hooks/nip_hooks.c new file mode 100644 index 0000000..af110c6 --- /dev/null +++ b/code/linux/net/newip/hooks/nip_hooks.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP Hooks + */ +#define CREATE_TRACE_POINTS +#include +#include + +#ifdef CONFIG_NEWIP_HOOKS +EXPORT_TRACEPOINT_SYMBOL_GPL(ninet_ehashfn_hook); +#endif diff --git a/code/linux/net/newip/ninet_hashtables.c b/code/linux/net/newip/ninet_hashtables.c index 0a7353e..b777636 100644 --- a/code/linux/net/newip/ninet_hashtables.c +++ b/code/linux/net/newip/ninet_hashtables.c @@ -335,6 +335,7 @@ static inline int nip_tcp_compute_score(struct sock *sk, struct net *net, return score; } +/* nip reuseport */ static struct sock *ninet_lhash2_lookup(struct net *net, struct inet_listen_hashbucket *ilb2, struct sk_buff *skb, int doff, diff --git a/code/linux/net/newip/nip_hooks_register.c b/code/linux/net/newip/nip_hooks_register.c new file mode 100644 index 0000000..9834112 --- /dev/null +++ b/code/linux/net/newip/nip_hooks_register.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * Definitions for the NewIP Hooks Register module. + */ +#ifdef CONFIG_NEWIP_HOOKS +#include /* ninet_ehashfn */ +#include + +void ninet_ehashfn_hook(void *data, const struct net *net, + const struct nip_addr *laddr, const u16 lport, + const struct nip_addr *faddr, const __be16 fport, u32 *ret) +{ + *ret = ninet_ehashfn(net, laddr, lport, faddr, fport); + pr_crit("[newip hook] %s ret=%u", __func__, *ret); +} + +int ninet_hooks_register(void) +{ + int ret; + + ret = register_trace_ninet_ehashfn_hook(&ninet_ehashfn_hook, NULL); + if (ret) { + DEBUG("failed to register to ninet_ehashfn_hook"); + return -1; + } + + return 0; +} +#endif /* CONFIG_NEWIP_HOOKS */ + diff --git a/code/linux/net/newip/nip_hooks_register.h b/code/linux/net/newip/nip_hooks_register.h new file mode 100644 index 0000000..1d3a0e0 --- /dev/null +++ b/code/linux/net/newip/nip_hooks_register.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * Definitions for the NewIP Hooks Register module. + */ +#ifndef _NIP_HOOKS_REGISTER_H +#define _NIP_HOOKS_REGISTER_H + +#ifdef CONFIG_NEWIP_HOOKS +int ninet_hooks_register(void); +#endif + +#endif /* _NIP_HOOKS_REGISTER_H */ -- Gitee From b27c34ca32eb7614f1185c878b458c7949ebdd23 Mon Sep 17 00:00:00 2001 From: yangyanjun Date: Tue, 20 Sep 2022 15:05:49 +0800 Subject: [PATCH 4/6] =?UTF-8?q?newip=E5=86=85=E6=A0=B8=E6=8F=92=E6=A1=A9?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- code/linux/net/newip/nip_hooks_register.c | 1 - 1 file changed, 1 deletion(-) diff --git a/code/linux/net/newip/nip_hooks_register.c b/code/linux/net/newip/nip_hooks_register.c index 9834112..5122286 100644 --- a/code/linux/net/newip/nip_hooks_register.c +++ b/code/linux/net/newip/nip_hooks_register.c @@ -13,7 +13,6 @@ void ninet_ehashfn_hook(void *data, const struct net *net, const struct nip_addr *faddr, const __be16 fport, u32 *ret) { *ret = ninet_ehashfn(net, laddr, lport, faddr, fport); - pr_crit("[newip hook] %s ret=%u", __func__, *ret); } int ninet_hooks_register(void) -- Gitee From 5b5c59bc371c8e9bc7979d6de621119dd1e44503 Mon Sep 17 00:00:00 2001 From: yangyanjun Date: Tue, 20 Sep 2022 19:58:13 +0800 Subject: [PATCH 5/6] =?UTF-8?q?readme=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- README_zh.md | 102 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/README_zh.md b/README_zh.md index a7debbf..9a09cc8 100644 --- a/README_zh.md +++ b/README_zh.md @@ -2,7 +2,9 @@ ## 简介 -OpenHarmony目前WiFi协议报文,三层报头和地址开销使得报文开销大,传输效率较低。 +NewIP(Network 2030 and the Future of IP)由网络5.0联盟,向联合国国际电信联盟(ITU)提议的一项新的网络技术新标准,在现有IP能力基础上,基于未来愿景,满足未来智能机器通信为主的全行业互联网和工业互联网需求。 + +目前WiFi协议报文,三层报头和地址开销使得报文开销大,传输效率较低。 ![image-20220915162621809](figures/image-20220915162621809.png) @@ -11,11 +13,21 @@ IPv4地址长度固定4字节,IPv6地址长度固定16字节。 IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节。 ``` -NewIP支持**可变长多语义地址**,**可变长定制化报头封装**,通过精简报文头开销,提升数据传输效率。 +NewIP支持**可变长多语义地址(最短1字节)**,**可变长定制化报头封装(最短5字节)**,通过精简报文头开销,提升数据传输效率。 + +NewIP报头开销,相比IPv4节省25.9%,相比IPv6节省44.9%。 + +NewIP载荷传输效率,相比IPv4提高1%,相比IPv6提高2.33%。 + +| 对比场景 | 报头开销 | 载荷传输效率(WiFi MTU=1500B,BT MTU=255B) | +| -------------- | ------------ | ------------------------------------------- | +| IPv4 for WiFi | 30+8+20=58 B | (1500-58)/1500=96.13% | +| IPv6 for WiFi | 30+8+40=78 B | (1500-78)/1500=94.8% | +| NewIP for WiFi | 30+8+5=43 B | (1500-43)/1500=97.13% | ## 系统架构 -NewIP内核协议栈架构图如下,用户态调用Socket API创建NewIP socket,采用NewIP极简帧头封装进行收发包。 +NewIP内核协议栈架构图如下,用户态应用程序调用Socket API创建NewIP socket,采用NewIP极简帧头封装进行收发包。 ![image-20220901152539801](figures/image-20220901152539801.png) @@ -45,9 +57,23 @@ NewIP内核协议栈使能,需要在对应款型的内核defconfig文件中设 kernel\linux\config\linux-5.10\arch\arm64\configs\rk3568_standard_defconfig ```c -CONFIG_NEWIP=y +CONFIG_NEWIP=y // 使能NewIP内核协议栈 +CONFIG_NEWIP_HOOKS=y // 使能NewIP内核侵入式修改插桩函数注册,使能NewIP的同时必须使用NewIP插桩功能 +``` + +另有部分CONFIG被依赖: + +```c +VENDOR_HOOKS=y // 使能内核插桩基础框架 ``` +备注: + +1. 只在Linux 5.10内核上支持NewIP内核协议栈。 +2. 鸿蒙linux内核要求所有原生内核代码侵入式修改,都要修改成插桩方式。 + + + 代码编译完成后,通过下面命令可以确认newip协议栈代码是否使能成功。 ```c @@ -65,13 +91,14 @@ out/kernel/OBJ/linux-5.10/net/newip/tcp_nip_output.o ```c # CONFIG_NEWIP is not set +# CONFIG_NEWIP_HOOKS is not set ``` ## 说明 ### 可变长报头格式 -NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 +NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识NewIP灵活极简报文。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 ![image-20220915140627223](figures/image-20220915140627223.png) @@ -80,6 +107,33 @@ NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0x 2) Bitmap:变长,Bitmap默认为紧跟在Dispatch有效位后面的7比特,Bitmap字段长度可持续扩展。Bitmap最后一位置0表示Bitmap结束,最后一位置1表示Bitmap向后扩展1 Byte,直至最后一位置0。 3) Value: 标识字段的值,长度为1 Byte的整数倍,类型及长度由报头字段语义表确定。 +**Bitmap字段定义如下:** + +| 极简Bitmap标识 | Bitops | 字段长度 | 置位策略 | 备注 | +| -------------------------- | ------ | ---------------- | -------------- | --------------------------------------- | +| Bitmap 1st Byte: | | | | | +| 标记位Dispatch | 0 | 不表示具体字段 | 置0 | 0:极简帧,1:普通帧。 | +| TTL | 1 | 1 Byte | 置1 | 剩余跳数。 | +| Total Length | 2 | 2 Byte | UDP置0,TCP置1 | NewIP报文总长度(包含报头长度)。 | +| Next Header | 3 | 1 Byte | 置1 | 协议类型。 | +| Reserve | 4 | 保留 | 置0 | 保留字段。 | +| Dest Address | 5 | 变长(1~8 Byte) | 置1 | 目的地址。 | +| Source Address | 6 | 变长(1~8 Byte) | 由协议自行确定 | 源地址。 | +| 标记位,标志是否有2nd Byte | 7 | 不表示具体字段 | | 0:bitmap结束,1:后跟另外8bit bitmap。 | +| Bitmap 2nd Byte: | | | | | +| Header Length | 0 | 1 Byte | | NewIP报头长度。 | +| Reserve | 1 | 保留 | 置0 | | +| Reserve | 2 | 保留 | 置0 | | +| Reserve | 3 | 保留 | 置0 | | +| Reserve | 4 | 保留 | 置0 | | +| Reserve | 5 | 保留 | 置0 | | +| Reserve | 6 | 保留 | 置0 | | +| 标记位,标志是否有3rd Byte | 7 | 不表示具体字段 | 置0 | 0:bitmap结束,1:后跟另外8bit bitmap。 | + +NewIP数据报头(极简模式)解析遇到新bitmap字段时的处理方法: + +仅解析当前版本协议中已定义的bitmap字段,从第一个未知语义的bitmap字段开始,跳过后面的所有bitmap字段,直接通过header length定位到报文开始位置并解析报文。如果报头中携带了未知语义的bitmap字段,且未携带header length字段,则丢弃该数据包。 + ### 可变长地址格式 NewIP采用自解释编码,编码格式如下所示: @@ -103,6 +157,22 @@ NewIP采用自解释编码,编码格式如下所示: ### 接口说明 +NewIP协议socket接口列表如下: + +| 函数 | 输入 | 输出 | 返回值 | 接口具体描述 | +| -------- | ------------------------------------------------------------ | ---------------------------------------------- | ---------------- | ------------------------------------------------------------ | +| socket | int **domain**, int type, int **protocol** | NA | Socket句柄sockfd | 创建NewIP 协议类型socket,并返回socket实例所对应的句柄。**domain参数填写 AF_NINET,表示创建NewIP协议类型socket。protocol参数填写IPPROTO_TCP或IPPROTO_UDP**。 | +| bind | int sockfd, const **struct sockaddr_nin** *myaddr, socklen_t addrlen | NA | int,返回错误码 | 将创建的socket绑定到指定的IP地址和端口上。**myaddr->sin_family填写AF_NINET**。 | +| listen | int socket, int backlog | NA | int,返回错误码 | 服务端监听NewIP地址和端口。 | +| connect | int sockfd, const **struct sockaddr_nin** *addr, aocklen_t addrlen | NA | int,返回错误码 | 客户端创建至服务端的连接。 | +| accept | int sockfd, **struct sockaddr_nin** *address, socklen_t *address_len | NA | 返回socket的fd | 服务端返回已建链成功的socket。 | +| send | int sockfd, const void *msg, int len, unsigned int flags, const **struct sockaddr_nin** *dst_addr, int addrlen | NA | int,返回错误码 | 用于socket已连接的NewIP类型数据发送。 | +| recv | int sockfd, size_t len, int flags, **struct sockaddr_nin** *src_addr, | void **buf, int* *fromlen | int,返回错误码 | 用于socket已连接的NewIP类型数据接收。 | +| close | int sockfd | NA | int,返回错误码 | 关闭socket,释放资源。 | +| ioctl | int sockfd, unsigned long cmd, ... | NA | int,返回错误码 | 对NewIP协议栈相关信息进行查询或更改。 | +| sendto | int sockfd, const void *msg, int len, unsigned int flags, const **struct sockaddr** *dst_addr, int addrlen | NA | int,返回错误码 | 用于socket无连接的NewIP类型数据发送。 | +| recvfrom | int sockfd, size_t len, int flags, | void *buf, struct sockaddr *from, int *fromlen | int,返回错误码 | 用于socket无连接的NewIP类型数据接收。 | + NewIP短地址结构如下: ```c @@ -165,27 +235,9 @@ struct sockaddr_nin { }; ``` +### NewIP收发包代码示例 - -NewIP协议socket接口列表如下: - -| 函数 | 输入 | 输出 | 返回值 | 接口具体描述 | -| -------- | ------------------------------------------------------------ | ---------------------------------------------- | ---------------- | ------------------------------------------------------------ | -| socket | int **domain**, int type, int **protocol** | NA | Socket句柄sockfd | 创建NewIP 协议类型socket,并返回socket实例所对应的句柄。**domain参数填写 AF_NINET,表示创建NewIP协议类型socket。protocol参数填写IPPROTO_TCP或IPPROTO_UDP**。 | -| bind | int sockfd, const **struct sockaddr_nin** *myaddr, socklen_t addrlen | NA | int,返回错误码 | 将创建的socket绑定到指定的IP地址和端口上。**myaddr->sin_family填写AF_NINET**。 | -| listen | int socket, int backlog | NA | int,返回错误码 | 服务端监听NewIP地址和端口 | -| connect | int sockfd, const **struct sockaddr_nin** *addr, aocklen_t addrlen | NA | int,返回错误码 | 客户端创建至服务端的连接 | -| accept | int sockfd, **struct sockaddr_nin** *address, socklen_t *address_len | NA | 返回socket的fd | 服务端返回已建链成功的socket | -| send | int sockfd, const void *msg, int len, unsigned int flags, const **struct sockaddr_nin** *dst_addr, int addrlen | NA | int,返回错误码 | 用于socket已连接的NewIP类型数据发送 | -| recv | int sockfd, size_t len, int flags, **struct sockaddr_nin** *src_addr, | void **buf, int* *fromlen | int,返回错误码 | 用于socket已连接的NewIP类型数据接收 | -| close | int sockfd | NA | int,返回错误码 | 关闭socket,释放资源 | -| ioctl | int sockfd, unsigned long cmd, ... | NA | int,返回错误码 | 对NewIP协议栈相关信息进行查询或更改。 | -| sendto | int sockfd, const void *msg, int len, unsigned int flags, const **struct sockaddr** *dst_addr, int addrlen | NA | int,返回错误码 | 用于socket无连接的NewIP类型数据发送 | -| recvfrom | int sockfd, size_t len, int flags, | void *buf, struct sockaddr *from, int *fromlen | int,返回错误码 | 用于socket无连接的NewIP类型数据接收 | - -### 使用说明 - -NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如下,NewIP协议栈用户态接口使用方法可以参考代码仓demo代码。 +NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如下,NewIP协议栈用户态接口使用方法可以参考[代码仓examples代码](https://gitee.com/openharmony-sig/communication_sfc_newip/tree/master/examples)。 | 文件名 | 功能 | | --------------------- | ----------------------------- | -- Gitee From e75f42714573068b615145205e926680bf7687c1 Mon Sep 17 00:00:00 2001 From: yangyanjun Date: Wed, 21 Sep 2022 11:18:01 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0OAT.xml=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangyanjun --- OAT.xml | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 OAT.xml diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000..256ed43 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,90 @@ + + + + + + COPYING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- Gitee