diff --git a/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915140627223.png b/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915140627223.png new file mode 100644 index 0000000000000000000000000000000000000000..5d27f2620ca837e6b90416e16aa7456919762104 Binary files /dev/null and b/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915140627223.png differ diff --git a/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915165414926.png b/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915165414926.png new file mode 100644 index 0000000000000000000000000000000000000000..5635e7de0f5ff8a0f02fe778c5f38803e3f1b05a Binary files /dev/null and b/zh-cn/device-dev/kernel/figures/zh-cn_image-20220915165414926.png differ diff --git a/zh-cn/device-dev/kernel/kernel-standard-newip.md b/zh-cn/device-dev/kernel/kernel-standard-newip.md new file mode 100644 index 0000000000000000000000000000000000000000..6dab0b9d06493717b2869f5150da1181aa6e4f3c --- /dev/null +++ b/zh-cn/device-dev/kernel/kernel-standard-newip.md @@ -0,0 +1,214 @@ +# NewIP内核协议栈介绍 + + +## 基本概念 + +NewIP支持**可变长多语义地址**,**可变长定制化报头封装**,通过精简报文头开销,提升数据传输效率。 + +NewIP灵活极简报文头如下图所示,通过LLC Header中的EtherType = 0xEADD标识。Bitmap是一组由0和1组成的二进制序列,每个二进制位的数值用于表示特定目标特性的存在性。 + +![zh-cn_image-20220915140627223](figures/zh-cn_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配置指导 + +启用NewIP,需要通过编译内核时打开相应的配置项及依赖,NewIP相关CONFIG如下: + +``` +CONFIG_NEWIP=y +CONFIG_NEWIP_HOOKS=y +``` + +另有部分CONFIG被依赖: + +``` +VENDOR_HOOKS=y +``` + + +## NewIP相关接口 + +用户态应用程序调用Socket API创建NewIP socket,采用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 +enum nip_8bit_addr_index { + NIP_8BIT_ADDR_INDEX_0 = 0, + NIP_8BIT_ADDR_INDEX_1 = 1, + NIP_8BIT_ADDR_INDEX_2 = 2, + NIP_8BIT_ADDR_INDEX_3 = 3, + NIP_8BIT_ADDR_INDEX_4 = 4, + NIP_8BIT_ADDR_INDEX_5 = 5, + NIP_8BIT_ADDR_INDEX_6 = 6, + NIP_8BIT_ADDR_INDEX_7 = 7, + NIP_8BIT_ADDR_INDEX_MAX, +}; + +enum nip_16bit_addr_index { + NIP_16BIT_ADDR_INDEX_0 = 0, + NIP_16BIT_ADDR_INDEX_1 = 1, + NIP_16BIT_ADDR_INDEX_2 = 2, + NIP_16BIT_ADDR_INDEX_3 = 3, + NIP_16BIT_ADDR_INDEX_MAX, +}; + +enum nip_32bit_addr_index { + NIP_32BIT_ADDR_INDEX_0 = 0, + NIP_32BIT_ADDR_INDEX_1 = 1, + NIP_32BIT_ADDR_INDEX_MAX, +}; + +#define nip_addr_field8 v.u.field8 +#define nip_addr_field16 v.u.field16 +#define nip_addr_field32 v.u.field32 + +#pragma pack(1) +struct nip_addr_field { + union { + unsigned char field8[NIP_8BIT_ADDR_INDEX_MAX]; + unsigned short field16[NIP_16BIT_ADDR_INDEX_MAX]; /* big-endian */ + unsigned int field32[NIP_32BIT_ADDR_INDEX_MAX]; /* big-endian */ + } u; +}; + +struct nip_addr { + unsigned char bitlen; /* The address length is in bit (not byte) */ + struct nip_addr_field v; +}; +#pragma pack() + +/* The following structure must be larger than V4. System calls use V4. + * If the definition is smaller than V4, the read process will have memory overruns + * v4: include\linux\socket.h --> sockaddr (16Byte) + */ +#define POD_SOCKADDR_SIZE 3 +struct sockaddr_nin { + unsigned short sin_family; /* [2Byte] AF_NINET */ + unsigned short sin_port; /* [2Byte] Transport layer port, big-endian */ + struct nip_addr sin_addr; /* [9Byte] NIP address */ + + unsigned char sin_zero[POD_SOCKADDR_SIZE]; /* [3Byte] Byte alignment */ +}; +``` + +## NewIP收发包代码示例 + +NewIP可变长地址配置,路由配置,UDP/TCP收发包demo代码链接如下,NewIP协议栈用户态接口使用方法可以参考代码仓examples代码。 + +| 文件名 | 功能 | +| --------------------- | ----------------------------- | +| nip_addr_cfg_demo.c | NewIP可变长地址配置demo代码 | +| nip_route_cfg_demo.c | NewIP路由配置demo代码 | +| nip_udp_server_demo.c | NewIP UDP收发包服务端demo代码 | +| nip_udp_client_demo.c | NewIP UDP收发包客户端demo代码 | +| nip_tcp_server_demo.c | NewIP TCP收发包服务端demo代码 | +| nip_tcp_client_demo.c | NewIP TCP收发包客户端demo代码 | +| nip_lib.c | 接口索引获取等API接口demo代码 | + +**基础操作步骤:** + +![zh-cn_image-20220915165414926](figures/zh-cn_image-20220915165414926.png) + +1、将demo代码拷贝到Linux编译机上,make clean,make all编译demo代码。 + +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”查看内核地址配置结果。 + +5、在设备1的sh下执行“./nip_route_cfg_demo server”给服务端配置路由,在设备2的sh下执行“./nip_route_cfg_demo client”给客户端配置路由,通过“cat /proc/net/nip_route”查看内核路由配置结果。 + +以上步骤操作完成后,可以进行UDP/TCP收发包,收发包demo默认使用上面步骤中配置的地址和路由。 + + + +**UDP收发包操作步骤:** + +先在服务端执行“./nip_udp_server_demo”,然后再在客户端执行“./nip_udp_client_demo”,客户端会发送10个NewIP报文,客户端收到报文后再发送给服务端。 + +``` +服务端sh窗口打印内容: +Received -- 1661826989 498038 NIP_UDP # 0 -- from 0x50:57605 +Sending -- 1661826989 498038 NIP_UDP # 0 -- to 0x50:57605 +Received -- 1661826990 14641 NIP_UDP # 1 -- from 0x50:57605 +Sending -- 1661826990 14641 NIP_UDP # 1 -- to 0x50:57605 +Received -- 1661826990 518388 NIP_UDP # 2 -- from 0x50:57605 +Sending -- 1661826990 518388 NIP_UDP # 2 -- to 0x50:57605 +... +Received -- 1661827011 590576 NIP_UDP # 9 -- from 0x50:37758 +Sending -- 1661827011 590576 NIP_UDP # 9 -- to 0x50:37758 + +客户端sh窗口打印内容: +Received --1661827007 55221 NIP_UDP # 0 sock 3 success: 1/ 1/no= 0 +Received --1661827007 557926 NIP_UDP # 1 sock 3 success: 2/ 2/no= 1 +Received --1661827008 62653 NIP_UDP # 2 sock 3 success: 3/ 3/no= 2 +... +Received --1661827011 590576 NIP_UDP # 9 sock 3 success: 10/ 10/no= 9 +``` + + + +**TCP收发包操作步骤:** + +先在服务端执行“./nip_tcp_server_demo”,然后再在客户端执行“./nip_tcp_client_demo”,客户端会发送10个NewIP报文,客户端收到报文后再发送给服务端。 + +``` +服务端sh窗口打印内容: +Received -- 1661760202 560605 NIP_TCP # 0 --:1024 +Sending -- 1661760202 560605 NIP_TCP # 0 --:1024 +Received -- 1661760203 69254 NIP_TCP # 1 --:1024 +Sending -- 1661760203 69254 NIP_TCP # 1 --:1024 +Received -- 1661760203 571604 NIP_TCP # 2 --:1024 +Sending -- 1661760203 571604 NIP_TCP # 2 --:1024 +... +Received -- 1661760207 86544 NIP_TCP # 9 --:1024 +Sending -- 1661760207 86544 NIP_TCP # 9 --:1024 + +客户端sh窗口打印内容: +Received --1661760202 560605 NIP_TCP # 0 sock 3 success: 1/ 1/no= 0 +Received --1661760203 69254 NIP_TCP # 1 sock 3 success: 2/ 2/no= 1 +... +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 }; +``` + +## +