Zephyr网络传输Offloading--概览

本文简单介绍Zephyr网络传输offloading的架构。

本文说明网络传输offloading的大体框架,包含阅读代码的方向,不包括具体实现的分析。后续会有文章对具体实现进行分析。

概述 链接到标题

Zephyr有完备的TCP/IP协议栈,在TCP/IP之上使用socket作为应用层的标准接口。此外Zephyr提供了网络传输offloading框架,将设备供应商的TCP/IP协议栈或者socket挂接到Zephyr内,对于Zephyr应用来说使用使用标准的socket编程后,Zephyr替换了底层的TCP/IP的来源也不用修改应用代码。

架构 链接到标题

下面图示是基于Zephyr官方的网络栈架构图(参考文末链接)修改而来,可以比较清楚的说明offload的架构: 在Zephyr中网络传输offloading有两种方式:

  1. 网络offloading API
  2. Socket offloading API 下面分别进行介绍

网络offloading 链接到标题

网络offloadin让Zephyr使用设备供应商提供的TCP/IP协议栈。网络连接创建,数据传输等动作是在供应商的HAL中完成,而不是在Zephyr网络协议栈中完成。 上图中蓝色部分是网络offloading的路线,在驱动中使用设备供应商的HAL对struct net_offload中定义的函数指针进行函数实现。注册这些函数后,net_context层就可以使用这些函数来完成网络传输。函数原型如下:

struct net_offload {
	/**
	 * This function is called when the socket is to be opened.
	 */
	int (*get)(sa_family_t family,
		   enum net_sock_type type,
		   enum net_ip_protocol ip_proto,
		   struct net_context **context);

	/**
	 * This function is called when user wants to bind to local IP address.
	 */
	int (*bind)(struct net_context *context,
		    const struct sockaddr *addr,
		    socklen_t addrlen);

	/**
	 * This function is called when user wants to mark the socket
	 * to be a listening one.
	 */
	int (*listen)(struct net_context *context, int backlog);

	/**
	 * This function is called when user wants to create a connection
	 * to a peer host.
	 */
	int (*connect)(struct net_context *context,
		       const struct sockaddr *addr,
		       socklen_t addrlen,
		       net_context_connect_cb_t cb,
		       int32_t timeout,
		       void *user_data);

	/**
	 * This function is called when user wants to accept a connection
	 * being established.
	 */
	int (*accept)(struct net_context *context,
		      net_tcp_accept_cb_t cb,
		      int32_t timeout,
		      void *user_data);

	/**
	 * This function is called when user wants to send data to peer host.
	 */
	int (*send)(struct net_pkt *pkt,
		    net_context_send_cb_t cb,
		    int32_t timeout,
		    void *user_data);

	/**
	 * This function is called when user wants to send data to peer host.
	 */
	int (*sendto)(struct net_pkt *pkt,
		      const struct sockaddr *dst_addr,
		      socklen_t addrlen,
		      net_context_send_cb_t cb,
		      int32_t timeout,
		      void *user_data);

	/**
	 * This function is called when user wants to receive data from peer
	 * host.
	 */
	int (*recv)(struct net_context *context,
		    net_context_recv_cb_t cb,
		    int32_t timeout,
		    void *user_data);

	/**
	 * This function is called when user wants to close the socket.
	 */
	int (*put)(struct net_context *context);
};

esp8266 AT就使用了该种形式,可以参考代码drivers/wifi/esp, 主要是esp.c

Socket offloading 链接到标题

Socket的offloading, 提供设备供应商socket和Zephyr集成方式,让Zephyr可以直接使用设备供应商的socket。上图中黄色部分是socket offloading的路线,在驱动中使用设备供应商的socket对struct socket_op_vtable中定义的函数指针进行函数实现。这一组函数被注册到Zephyr的socket的虚方法表中,在实际socket进行调用时会通虚方法表查找到实际的供应商socket API并执行,要实现虚方法表内的socket的函数如下:

struct socket_op_vtable {
	struct fd_op_vtable fd_vtable;
	int (*bind)(void *obj, const struct sockaddr *addr, socklen_t addrlen);
	int (*connect)(void *obj, const struct sockaddr *addr,
		       socklen_t addrlen);
	int (*listen)(void *obj, int backlog);
	int (*accept)(void *obj, struct sockaddr *addr, socklen_t *addrlen);
	ssize_t (*sendto)(void *obj, const void *buf, size_t len, int flags,
			  const struct sockaddr *dest_addr, socklen_t addrlen);
	ssize_t (*recvfrom)(void *obj, void *buf, size_t max_len, int flags,
			    struct sockaddr *src_addr, socklen_t *addrlen);
	int (*getsockopt)(void *obj, int level, int optname,
			  void *optval, socklen_t *optlen);
	int (*setsockopt)(void *obj, int level, int optname,
			  const void *optval, socklen_t optlen);
	ssize_t (*sendmsg)(void *obj, const struct msghdr *msg, int flags);
	int (*getsockname)(void *obj, struct sockaddr *addr,
			   socklen_t *addrlen);
};

Inventek的esWifi就使用了该种形式,可以参考代码drivers/wifi/eswifi, 主要是eswifi_socket_offload.c

参考 链接到标题

https://docs.zephyrproject.org/latest/reference/networking/net_offload.html https://docs.zephyrproject.org/latest/guides/networking/net-stack-architecture.html