Zephyr网络管理模块分析-注册请求机制

Creative Commons
本作品采用知识共享署名

本文说明Zephyr网络管理模块的作用和注册请求机制的使用方法与实现原理

概要

网络管理API允许应用程序和网络层本身调用网络协议栈中定义的功能,并接收有关网络事件的通知。目前Zhphyr中主要使用在TCP/IP获取状态和L2的控制和配置,例如wifi scan, 设置网卡mac地址等。
网络管理的代码是net_mgmt.h和net_mgmt.c,并不提供实际的网络功能,主要是提供一个功能框架涵盖以下内容:

  1. 提供网络功能Handle注册请求机制
  2. 提供网络功能的event机制,让应用
    本文先分析说明注册请求机制.

注册请求机制

使用方法

以wifi scan为例,分析wifi_mgmt如何透过net_mgmt将功能提供给应用层。

  1. 在wifi_mgmt中实现wifi scan的static函数wifi_scan

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    static int wifi_scan(uint32_t mgmt_request, struct net_if *iface,
    void *data, size_t len)
    {
    const struct device *dev = net_if_get_device(iface);
    struct net_wifi_mgmt_offload *off_api =
    (struct net_wifi_mgmt_offload *) dev->api;

    if (off_api == NULL || off_api->scan == NULL) {
    return -ENOTSUP;
    }

    return off_api->scan(dev, scan_result_cb);
    }
  2. 使用宏NET_MGMT_REGISTER_REQUEST_HANDLER注册request handler

    1
    NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN, wifi_scan);
  3. 在wifi_mgmt.h中使用NET_MGMT_DEFINE_REQUEST_HANDLER声明request handle

    1
    NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN);
  4. 应用使用net_mgmt调用声明的request handle

    1
    net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)

原理分析

注册

NET_MGMT_REGISTER_REQUEST_HANDLER注册的相关宏如下

1
2
3
4
5
6
7
#define NET_MGMT_REGISTER_REQUEST_HANDLER(_mgmt_request, _func)	\
FUNC_ALIAS(_func, net_mgmt_##_mgmt_request, int)

#define ALIAS_OF(of) __attribute__((alias(#of)))

#define FUNC_ALIAS(real_func, new_alias, return_type) \
return_type new_alias() ALIAS_OF(real_func)

对于对wifi_mgmt.c的注册代码NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN, wifi_scan);展开为如下

1
int net_mgmt_NET_REQUEST_WIFI_SCAN_mgmt_request() __attribute__(("wifi_scan")))

也就是将static函数wifi_scan取了一个别名net_mgmt_NET_REQUEST_WIFI_SCAN_mgmt_request。

声明

NET_MGMT_DEFINE_REQUEST_HANDLER声明的宏如下

1
2
3
4
#define NET_MGMT_DEFINE_REQUEST_HANDLER(_mgmt_request)			\
extern int net_mgmt_##_mgmt_request(uint32_t mgmt_request, \
struct net_if *iface, \
void *data, size_t len)

将wifi_mgmt.h中NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN);展开为如下

1
2
3
extern int net_mgmt_NET_REQUEST_WIFI_SCAN_mgmt_request(uint32_t mgmt_request,	\
struct net_if *iface, \
void *data, size_t len);

请求

net_mgmt请求的宏如下

1
2
#define net_mgmt(_mgmt_request, _iface, _data, _len)			\
net_mgmt_##_mgmt_request(_mgmt_request, _iface, _data, _len)

对应用程序调用net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)展开为

1
net_mgmt_NET_REQUEST_WIFI_SCAN_mgmt_request(NET_REQUEST_WIFI_SCAN, iface, NULL, 0);

而net_mgmt_NET_REQUEST_WIFI_SCAN_mgmt_request是wifi_scan的别名,因此相当于应用程序调用了

1
wifi_scan(NET_REQUEST_WIFI_SCAN, iface, NULL, 0);

其它

在Zephyr官方文档中有如下描述

The Network Management API implementation is designed to save memory by eliminating code at build time for management routines that are not used. Distinct and statically defined APIs for network management procedures are not used. Instead, defined procedure handlers are registered by using a NET_MGMT_REGISTER_REQUEST_HANDLER macro. Procedure requests are done through a single net_mgmt() API that invokes the registered handler for the corresponding request.

前面段描述构建时了节省内存,后半段所描述的请求注册机制,二者并不是因果关系。我的分析如下:

1. 构建节省内存的实现

依靠zephyr\arch\common\CMakeLists.txt内编译选项将函数和data section

1
2
3
# Put functions and data in their own binary sections so that ld can
# garbage collect them
zephyr_cc_option(-ffunction-sections -fdata-sections)

和linker/ld/target_base.cmake内链接选项将没有使用的section移除来达到节省内存

1
2
3
4
5
zephyr_ld_options(
${TOOLCHAIN_LD_FLAGS}
${LINKERFLAGPREFIX},--gc-sections
${LINKERFLAGPREFIX},--build-id=none
)

2. 使用请求注册机制的目的

使用请求注册机制的目的,是为了统一网络管理API,在接口形式上都是通过请求ID来完成

参考

https://docs.zephyrproject.org/latest/reference/networking/net_mgmt.html