前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vppinfra---socket api

vppinfra---socket api

作者头像
dpdk-vpp源码解读
发布2023-03-07 17:04:26
6220
发布2023-03-07 17:04:26
举报
文章被收录于专栏:DPDK VPP源码分析DPDK VPP源码分析

今天来学习一下vpp底层基础库--socket相关api及结构体,往期相关的文章请翻看文末链接。

结构体说明

socket.h文件就下面一个结构体clib_socket_t,保存socket一些基本属性。

代码语言:javascript
复制
typedef struct _socket_t
{
  i32 fd;/*socket 文件描述符 */
  char *config;/*配置字符串,用于解析hostname及端口号 Host:port or host*/
  u32 flags;
  #define CLIB_SOCKET_F_IS_SERVER (1 << 0)/*表示当前是server端*/
#define CLIB_SOCKET_F_IS_CLIENT (0 << 0)/*表示当前是client端*/
#define CLIB_SOCKET_F_RX_END_OF_FILE (1 << 2)/*表示对端关闭了socket链接*/
#define CLIB_SOCKET_F_NON_BLOCKING_CONNECT (1 << 3)/*需要设置成非阻塞模式*/
/*PF_LOCAL:本地域套接字类型下,置为下面标识,标识设置套接字对应文件的属性是用户组可写权限*/
#define CLIB_SOCKET_F_ALLOW_GROUP_WRITE (1 << 4)
#define CLIB_SOCKET_F_SEQPACKET (1 << 5)/*socket 类型SOCK_SEQPACKET : SOCK_STREAM*/
/*设置套接字SO_PASSCRED属性:允许或禁止SCM_CREDENTIALS 控制消息的接收。*/
#define CLIB_SOCKET_F_PASSCRED  (1 << 6)
  /* 报文发送缓存区*/
  u8 *tx_buffer;
  /* 报文接收缓存区*/
  u8 *rx_buffer;
  /* socket连接成功后,保存对端socket 信息*/
  struct sockaddr_in peer;
  /* Credentials, populated if CLIB_SOCKET_F_PASSCRED is set */
  pid_t pid;
  uid_t uid;
  gid_t gid;
  /*对应的处理函数指针,可以初始化时由用户指定,也可以使用缺省函数*/
  clib_error_t *(*write_func) (struct _socket_t * sock);
  clib_error_t *(*read_func) (struct _socket_t * sock, int min_bytes);
  clib_error_t *(*close_func) (struct _socket_t * sock);
  clib_error_t *(*recvmsg_func) (struct _socket_t * s, void *msg, int msglen,
                 int fds[], int num_fds);
  clib_error_t *(*sendmsg_func) (struct _socket_t * s, void *msg, int msglen,
                 int fds[], int num_fds);
  /* 私有字段*/
  uword private_data;
} clib_socket_t;

flags:在flags字段由用户指定,在clib_socket_init初始化时根据不同的flags参数设置socket信息。其中下面几个字段比较特殊: 1、CLIB_SOCKET_F_SEQPACKET:设置socket 类型,置位时设置成SOCK_SEQPACKET,否则设置成:SOCK_STREAM。 SOCK_SEQPACKET套接字类型类似于SOCK_STREAM类型,也是面向连接的。区别是使用SOCK_SEQPACKET类型维护记录边界。一个记录可以使用一个或多个输出操作发送,也可以使用一个或多个输入操作接收,但是一个操作从不传输多个记录的部分。通过recvmsg()函数返回的接收消息标志中的MSG_EOR标志,接收方可以看到记录边界。是否施加最大记录大小取决于协议。

在vpp代码中使用stat_segment模块在初始化时,flag标识位置位CLIB_SOCKET_F_SEQPACKET,对应在发送和接收函数使用sendmsg_func及recvmsg_func。

linux 系统使用man 2 socket 类型查询说明: SOCK_STREAM:提供提供顺序的、可靠的、双向的、基于连接的字节流稳定数据传输,即TCP协议。 SOCK_DGRAM:支持数据报(固定最大长度的无连接、不可靠的消息,UDP协议。 SOCK_SEQPACKET:提供连续可靠的数据包连接。为固定最大长度的数据报提供顺序的、可靠的、基于双向连接的数据传输路径;消费者需要读取每个输入系统调用的整个数据包。 SOCK_RAW:提供原始网络协议存取。 SOCK_RDM:提供可靠的数据包连接。 SOCK_PACKET:与网络驱动程序直接通信。

2、CLIB_SOCKET_F_PASSCRED 用于设置unix域套接字SO_PASSCRED属性。 下面man手册给的解释,看来这个字段置位时,会存储uid,gid,pid信息。此字段置位后,通信应该是recvmsg、secnmsg接口函数。

SO_PASSCRED启用此套接字选项将导致在随后接收到的每个消息中的SCM_CREDENTIALS辅助消息中接收到发送进程的凭据。返回的凭据是由发送方使用SCM_CREDENTIALS指定的凭据,或者是包含发送方的PID、真实用户ID和真实组ID(如果发送方没有指定SCM_CREDENTIALS辅助数据)的默认凭据。当设置了这个选项并且套接字还没有连接时,抽象命名空间中的唯一名称将自动生成。

3、收发报文函数指针。用户可以自己设定,如果不指定默认使用缺省函数。

在代码中,在插件memif接口信息使用的时注册时提供的函数接口。其他的目前看都是使用的缺省函数。

api函数

主要说明一下初始化和accept函数。其他api相对简单一些。 1、初始化

代码语言:javascript
复制
__clib_export clib_error_t *clib_socket_init (clib_socket_t * s)

根据用户设置s的参数完成socket初始化动作,包含回调函数初始化,socket初始化,server端(bind、listen)、client端(完成connet动作)等。并根据flags参数设定socket属性。

2、clib_socket_accept接收客户端连接

代码语言:javascript
复制
__clib_export clib_error_t *
clib_socket_accept (clib_socket_t * server, clib_socket_t * client)

服务器端accept客户端连接请求后,设置客户端套接字非阻塞模式,并保存客户端的地址信息。设置flag为CLIB_SOCKET_F_IS_CLIENT,初始化处理函数等。

这里需要主要client参数在clib_socket_accept 函数中会被初始化,所以需要主要clinet函数内的一些资源(config、tx or rx buffer),代码书写不当可能会导致泄漏

示例说明

下面以命令行cli为例说明socket使用: 1、startup设置cli-listen config vpp可以提供了三种cli-listen模式(如下所示)

代码语言:javascript
复制
unix {
  #cli-listen /run/vpp/cli.sock #unix域套接字。使用vppctl命令登录
  #cli-listen localhost:5002 #INADDR_LOOPBACK, 也就是绑定地址LOOPBAC, 往往是127.0.0.1, 只能收到127.0.0.1上面的连接请求。
  cli-listen 0.0.0.0:5002 #INADDR_ANY是ANY,是绑定地址0.0.0.0上的监听, 能收到任意一块网卡的连接。
}

2、解析配置文件并完成cli socket初始化

代码语言:javascript
复制
unix_cli_config
|    |--unix_config()/*用于解析startup.conf中unix模块字段*/
|    |--判断已经配置cli-listen,调用clib_socket_init完成初始化。
|    |--clib_file_add()/*调用file add将套接字加入到epool中*/

cli_file_add相关的可以看一下之前的文章:vppinfra--- file.h: unix file handling

3、查询命令行

代码语言:javascript
复制
#1、查询linux系统cli建立连接情况
[root@edge_auto_6 bin]# netstat -lantp | grep vpp
tcp        0      0 0.0.0.0:5002            0.0.0.0:*               LISTEN      17649/vpp  #server         
tcp        0      0 127.0.0.1:5002          127.0.0.1:51534         ESTABLISHED 17649/vpp #telnet 127.0.0.0 5002登录vppcli模式          
tcp        0      0 192.168.0.102:5002      192.168.0.100:64064     ESTABLISHED 17649/vpp #在主机192.168.0.100上telnet 192.168,0.102 5002主机
#2、查询unix files信息
其中文件描述符30:是cli server端,32-34时登录cli后建立的tcp连接
learning_vpp# show unix files 
 FD Thread         Read        Write        Error File Name                        Description
 11      0            0            0            0 socket:[86752]                   stats segment listener /run/vpp/stats.sock
 13      0            1            0            0 pipe:[86755]                     DPDK logging pipe
 30      0            3            0            0 socket:[86767]                   cli listener 0.0.0.0:5002
 31      0            0            0            0 socket:[86769]                   socksvr /run/vpp/api.sock
 32      0           34            1            0 socket:[86774]                   127.0.0.1:51534
 33      0           30            1            0 socket:[86785]                   192.168.0.100:64064
 34      0            1            1            0 socket:[87403]                   127.0.0.1:51536
#查询unix-cli 节点
cli建立后,为每个连接创建一个process 类型的node节点,用于接收cli输入。
unix-cli-127.0.0.1:51536       event wait                0               0               2          2.13e9            0.00
unix-cli-127.0.0.1:51538         active                  1               0              68          6.24e9            0.00
unix-cli-192.168.0.100:64064   event wait                0               0              31          1.13e8            0.00

总结

本文简单了解一下socket结构体及一些api接口,对于上层如何使用未深入介绍(如下面unix_cli_listen_read_ready中四个全局变量之间的关联关系),后续有机会需要深入介绍

代码语言:javascript
复制
static clib_error_t *
unix_cli_listen_read_ready (clib_file_t * uf)
{
  unix_main_t *um = &unix_main;
  clib_file_main_t *fm = &file_main;
  unix_cli_main_t *cm = &unix_cli_main;
  clib_socket_t *s = &um->cli_listen_socket
}
本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-06,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 DPDK VPP源码分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结构体说明
  • api函数
  • 示例说明
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com