netmap源码分析(四)用户态收包过程
来源:互联网 发布:淘宝swatch官方旗舰店 编辑:程序博客网 时间:2024/06/05 20:51
上篇文章 netmap源码分析(三)内核态收包过程 说了内核态收包过程以及如何映射到用户态,那么我们这次来看看用户态究竟如何使用。
netmap的用户态代码将打开和关闭/dev/netmap
过程都封装成函数并放在了netmap_user.h
下,简单的使用过程如下:
- nm_open( )
- 收包(这部分自己处理)
- nm_close( )
netmap 用户态的使用过程
下面通过我写的一个简单的小例子来大致感受一下 netmap 的使用过程:
#include <stdio.h>#include <poll.h>#define NETMAP_WITH_LIBS#include <net/netmap_user.h>int main(void){ struct nm_desc *d; struct pollfd fds; struct netmap_ring *ring; int i; d = nm_open("netmap:eth0", NULL, 0, 0); // 注意格式,netmap:ehtX // d 的返回值我这里就不判断了 fds.fd = d->fd; fds.events = POLLIN; while (1) { if (poll(&fds, 1, 1) < 0) { perror("poll()"); exit(1); } // 遍历所有的接收队列 for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) { ring = NETMAP_RXRING(d->nifp, i); receive_packets(ring); // 处理 ring } }}static void receive_packets(struct netmap_ring *ring){ int i; char *buf; // 遍历所有的槽位 while (!nm_ring_empty(ring)) { i = ring->cur; buf = NETMAP_BUF(ring, ring->slot[i].buf_idx); // buf 就是收到的报文喽 pps++; // 统计收包个数 ring->head = ring->cur = nm_ring_next(ring, i); // 下一个槽位 }}
还记得前几篇文章中的那个图么
| USERSPACE | struct netmap_ring +---->+---------------+ / | head,cur,tail | struct netmap_if (nifp, one per fd) / | buf_ofs | +---------------+ / | other fields | | ni_tx_rings | / +===============+ | ni_rx_rings | / | buf_idx, len | slot[0] | | / | flags, ptr | | | / +---------------+ +===============+ / | buf_idx, len | slot[1] | txring_ofs[0] | (rel.to nifp)--' | flags, ptr | | txring_ofs[1] | +---------------+ (tx+1 entries) (num_slots entries) | txring_ofs[t] | | buf_idx, len | slot[n-1] +---------------+ | flags, ptr | | rxring_ofs[0] | +---------------+ | rxring_ofs[1] | (rx+1 entries) | rxring_ofs[r] | +---------------+
NETMAP_RXRING
和NETMAP_BUF
如下:
// ring 起始位置 + offset 算出是哪个 ring#define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )// 通过偏移计算 buffer#define NETMAP_BUF(ring, index) \ ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
使用起来是不是很容易呢 ^_^
下面我们来看看nm_open
和nm_close
都做了些什么吧。
nm_open
static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req, uint64_t new_flags, const struct nm_desc *arg){ struct nm_desc *d = NULL; if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { // 判断是否是 netmap 模式接口名 errno = 0; return NULL; } nr_flags = NR_REG_ALL_NIC; d = (struct nm_desc *)calloc(1, sizeof(*d)); d->self = d; d->fd = open(NETMAP_DEVICE_NAME, O_RDWR); // NETMAP_DEVICE_NAME 是 /dev/netmap d->req.nr_version = NETMAP_API; d->req.nr_ringid &= ~NETMAP_RING_MASK; d->req.nr_ringid |= nr_ringid; d->req.nr_flags |= nr_flags; memcpy(d->req.nr_name, ifname, namelen); d->req.nr_name[namelen] = '\0'; if (ioctl(d->fd, NIOCREGIF, &d->req)) { // 注册命令 snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno)); goto fail; } if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) { // mmap 映射内存,下面分析细节过程 snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno)); goto fail; } return d;fail: nm_close(d); if (errno == 0) errno = EINVAL; return NULL; }
nm_close
nm_close( ) 代码比较少,关闭文件描述符和释放相关资源
static int nm_close(struct nm_desc *d){ static void *__xxzt[] __attribute__ ((unused)) = { (void *)nm_open, (void *)nm_inject, (void *)nm_dispatch, (void *)nm_nextpkt }; if (d == NULL || d->self != d) return EINVAL; if (d->done_mmap && d->mem) munmap(d->mem, d->memsize); // 解除内存映射 if (d->fd != -1) { close(d->fd); /* 关闭 /dev/netmap 的文件描述符 */ } bzero(d, sizeof(*d)); free(d); // 释放资源 return 0;}
nm_mmap
static int nm_mmap(struct nm_desc *d, const struct nm_desc *parent){ d->memsize = d->req.nr_memsize; // 映射内存区域的大小 d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, d->fd, 0); // 通过 offset 得到对应的 netmap_if 结构 struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); struct netmap_ring *r = NETMAP_RXRING(nifp, ); *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; // 区域的起始和结束位置 *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); *(void **)(uintptr_t)&d->buf_end = (char *)d->mem + d->memsize; return 0;}
0 0
- netmap源码分析(四)用户态收包过程
- netmap源码分析(三)内核态收包过程
- Netmap分析(四)
- netmap源码分析(五)ioctl 注册过程
- netmap源码分析(一)插入 netmap 代码到驱动程序
- Netmap分析(一)
- Netmap分析(二)
- Netmap分析(三)
- Netmap分析(五)
- Netmap分析(六)
- netmap源码分析(二)内核态关键结构的初始化
- netmap源码读后感(第二版)
- Elasticsearch2.4学习(四)------源码分析之启动过程
- Elasticsearch2.4学习(四)------源码分析之启动过程
- 高性能网络I/O框架-netmap源码分析(1)
- 高性能网络I/O框架-netmap源码分析(2)
- 高性能网络I/O框架-netmap源码分析(3)
- 高性能网络I/O框架-netmap源码分析(4)
- Android项目中的单元测试(Junit4)
- 工作流-JBPM(1)
- OpenGL -- 多颜色的立方体旋转
- HDU 1693 Eat the Trees
- 《驴得水》影评
- netmap源码分析(四)用户态收包过程
- 如何删除属性页和属性表单中的帮助按钮
- Java 数字操作类
- Android NDK开发(一) 入门
- nginx之gzip
- js对象篇(二)
- 数据挖掘学习笔记一:绪论
- delphi中combobox键值对
- Android 网络--我是怎么做的: Volley+OkHttp+Https