netmap源码阅读笔记
来源:互联网 发布:gcp网络培训 编辑:程序博客网 时间:2024/04/29 09:48
netmap源码涉及的技术非常多,本人以前从未做过驱动开发或者内核开发,阅读代码的过程中深感吃力,不过,不管怎样,还是有些收获,这些知识如果不加整理记录,后面再回忆起来可能又要重新思考一次,很不明智;况且,目前只是梳理了个框架,细节方面还需要日后再继续研究整理,是以为记。
首先要说明的是,netmap的代码质量很高,在FreeBSD中已经与内核代码一起发布,且注释非常清晰,里面有大段的注释,相当于设计文档,大家要细细研究。
其次,我个人觉得,要彻底弄清楚实现机理,还需要对内核原理、驱动开发有相当的了解,否则看起来会比较吃力,我就属于这种。
以下是我的一部分阅读笔记:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1. 数据结构
文件: netmap.h
描述: netmap把一个netmap_slot结构称为"buffer descriptor",这点一定要记住,netmap
源码中,有很多处出现descriptor,大家要能够明白所指之物。当然,作者这样称呼
的原因是因为netmap_slot结构本身并不包含slot内存,它只是"描述"slot的属性。
我们最关心的slot所指内存使用buf_idx表示,其真实所在其实是在内存池中。
作用: 报文(收/发)存储的场所
创建: when - 注册netmap设备时。
who - 由内核创建,并且mmap到用户空间。
where - 使用kmalloc申请,处于内核空间。
struct netmap_slot {uint32_t buf_idx;/* buffer index */uint16_t len; /* length for this slot */uint16_t flags;/* buf changed, etc. */uint64_t ptr; /* pointer for indirect buffers */};
文件: netmap.h
描述: 顾名思义,此结构代表的是netmap的一个ring,简单来讲就是一个环形缓冲区,基本上可以这样认为。slot[0]成员指示的就是ring的组成成分——netmap_slot,这只是一 个占位符,真正申请内存的时候,这后面会跟着一堆netmap_slot。提醒一下,前面我们讲过,netmap_slot只是一个描述符,里面并不包含真正拷贝报文所需内存。
作用: 表示一个环形缓冲区
创建: when - 注册netmap设备时。
who - 由内核创建,并且mmap到用户空间。
where - 使用kmalloc申请,处于内核空间。
struct netmap_ring { // buffer在内存池中的偏移,主要用于宏计算const int64_t buf_ofs;// 此ring包含多少个slotconst uint32_tnum_slots;// 每一个slot的内存大小const uint32_tnr_buf_size;// 当前netmap_ring索引(可能分配多个netmap_ring)const uint16_tringid;// 标识此ring是用于发送还是接受,0: tx, 1: rxconst uint16_tdir; // uint32_t head;/* (u) first user slot */uint32_t cur;/* (u) wakeup point */uint32_t tail; /* (k) first kernel slot */uint32_t flags;struct timevalts; /* (k) time of last *sync() */uint8_t sem[128] __attribute__((__aligned__(NM_CACHE_ALIGN))); // 一堆netmap_slotstruct netmap_slot slot[0];/* array of slots. */};
文件: netmap.h
描述: 代表一个网络接口及接口上的队列。此结构在绑定一个文件描述符到
一个端口的时候进行初始化,对于用户程序来说是只读的,内核不使用
此结构。
作用:
创建: when - 注册netmap设备时。
who - 内核模块创建。
where - 用户空间使用。
struct netmap_if {char ni_name[IFNAMSIZ];/* name of the interface. */const uint32_tni_version; /* API version, currently unused */const uint32_tni_flags; /* properties */const uint32_tni_tx_rings; /* number of HW tx rings */const uint32_tni_rx_rings; /* number of HW rx rings */uint32_t ni_bufs_head; /* head index for extra bufs */uint32_t ni_spare1[5];const ssize_t ring_ofs[0];};
所在文件: netmap.h
struct nmreq {char nr_name[IFNAMSIZ];uint32_t nr_version; /* API version */uint32_t nr_offset; /* nifp offset in the shared region */uint32_t nr_memsize; /* size of the shared region */uint32_t nr_tx_slots; /* slots in tx rings */uint32_t nr_rx_slots; /* slots in rx rings */uint16_t nr_tx_rings; /* number of tx rings */uint16_t nr_rx_rings; /* number of rx rings */uint16_t nr_ringid; /* ring(s) we care about */uint16_t nr_cmd;uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */uint16_t nr_arg2;uint32_t nr_arg3; /* req. extra buffers in NIOCREGIF */uint32_t nr_flags;uint32_t spare2[1]; /* various modes, extends nr_ringid */};
文件: netmap.h
描述: 与ixgbe_adapter对应,代表逻辑上的一个netmap适配器。
作用:
创建: when - 加载驱动时创建。
who - 内核模块创建。
where - 内核使用。
struct netmap_adapter {uint32_t magic;uint32_t na_flags;/* enabled, and other flags */int active_fds; u_int num_rx_rings; /* number of adapter receive rings */u_int num_tx_rings; /* number of adapter transmit rings */u_int num_tx_desc; /* number of descriptor in each queue */u_int num_rx_desc;struct netmap_kring *tx_rings; /* array of TX rings. */struct netmap_kring *rx_rings; /* array of RX rings. */void *tailroom; /* space below the rings array */NM_SELINFO_T tx_si, rx_si;/* global wait queues */int tx_si_users, rx_si_users;int (*if_transmit)(struct ifnet *, struct mbuf *);void (*if_input)(struct ifnet *, struct mbuf *);struct ifnet *ifp; /* adapter is ifp->if_softc *//*---- callbacks for this netmap adapter -----*/void (*nm_dtor)(struct netmap_adapter *);int (*nm_register)(struct netmap_adapter *, int onoff);int (*nm_txsync)(struct netmap_kring *kring, int flags);int (*nm_rxsync)(struct netmap_kring *kring, int flags);int (*nm_config)(struct netmap_adapter *, u_int *txr, u_int *txd, u_int *rxr, u_int *rxd);int (*nm_krings_create)(struct netmap_adapter *);void (*nm_krings_delete)(struct netmap_adapter *);int (*nm_notify)(struct netmap_adapter *, u_int ring, enum txrx, int flags);int na_refcount;struct netmap_mem_d *nm_mem;struct lut_entry *na_lut;uint32_t na_lut_objtotal;/* max buffer index */void *na_private;#ifdef WITH_PIPESstruct netmap_pipe_adapter **na_pipes;int na_next_pipe;int na_max_pipes;#endif /* WITH_PIPES */};
1) 用户空间可见的数据结构,都是由内核申请内存,然后mmap到用户空间的。
2) netmap中大量使用内存偏移或者索引来代替指针,这样更容易在内核与用户之间使用。(?)
2. 处理流程
1) 加载netmap_lin.ko
a) 初始化全局锁(全局锁干啥用的?)
b) 初始化内存池的信号量(?)
c) 使用misc_register创建/dev/netmap设备。这个操作同时也注册了netmap支持的设备操作接口,
后续,对netmap的操作就可以像访问普通设备一样了。
static struct file_operations netmap_fops = { .owner = THIS_MODULE, .open = linux_netmap_open, .mmap = linux_netmap_mmap, .ioctl = linux_netmap_ioctl, .poll = linux_netmap_poll, .release = linux_netmap_release,};d) VALE初始化
2) 加载ixgbe.ko
module_init -> ixgbe_init_module -> pci_register_driver(dca_register_notify)
static struct pci_driver ixgbe_driver = {.name = ixgbe_driver_name,.id_table = ixgbe_pci_tbl,.probe = ixgbe_probe,.remove = __devexit_p(ixgbe_remove),#ifdef CONFIG_PM.suspend = ixgbe_suspend,.resume = ixgbe_resume,#endif.shutdown = ixgbe_shutdown,.err_handler = &ixgbe_err_handler};
简单来讲就是注册PCI设备,不过,这里需要注意,由于ixgbe驱动被修改适配netmap框架,
ixgbe.ko依赖于netmap_lin.ko,换句话说ixgbe.ko需要使用netmap_lin.ko中的导出符号,
所以,加载顺序必须是先加载netmap_lin.ko再加载ixgbe.ko。
内核注册完驱动后,就会调用其初始化函数ixgbe_probe,此函数会做一堆初始化,这里
摘取出几项比较重要的分析下:
a) 设置ixgbe netdev的回调函数:netdev->netdev_ops = &ixgbe_netdev_ops;
b) 设置ixgbe ethtool的回调函数:ixgbe_set_ethtool_ops(netdev);
c) ixgbe_init_interrupt_scheme:设置RSS等的队列个数和申请中断向量。
这里面还会设置NAPI的回调接口为ixgbe_poll,这样报文接收通道就构建好了。
d) ixgbe_netmap_attach:创建netmap_adapter赋值到net_device的ax25_ptr成员,
这样,netmap与ixgbe就建立一种联系,可以说是netmap attach到ixgbe了。
3) up/open事件(以RX为例)
ixgbe_up/ixgbe_open --> ixgbe_configure -> ixgbe_configure_rx
-> ixgbe_configure_rx_ring -> ixgbe_netmap_configure_rx_ring
a) DMA资源和中断资源都是在这个流程申请的。而加载驱动时只是设置DMA工作参数等。
b) 每一个ring都需要申请独立的dma资源
4) 使用netmap设备
nm_open -> open("/dev/netmap", O_RDWR) -> ioctl(d->fd, NIOCREGIF, &d->req) -> mmap
a) 用户使用的API都在netmap_user.h中声明。
b) 调用nm_open会以netmap方式打开网卡设备,内部包含一系列动作。
c) open操作最终会调用之前加载的内核模块netmap_lin.ko中的linux_netmap_open。
d) ioctl操作会在内核申请
e) mmap操作将内核空间映射到用户空间来,
5) 接收报文
NAPI -> ixgbe_poll -> ixgbe_clean_rx_irq -> netmap_rx_irq -> netmap_common_irq -> netmap_notify
a) netmap底层也是使用NAPI来接收报文的。
b) ixgbe_poll是遍历所有ring来逐个通知上层的。
c) netmap_rx_irq劫持了ixgbe驱动的报文接收,从这个函数往下,报文接收就完全由netmap接管了。
- netmap源码阅读笔记
- LZ77源码阅读笔记
- Boa 源码阅读笔记
- VNC源码阅读笔记
- osqa源码阅读笔记
- VNC源码阅读笔记
- MPlayer 源码阅读笔记
- PyEmu源码阅读笔记
- JSONModel源码阅读笔记
- JSONModel源码阅读笔记
- HSF源码阅读笔记
- memcached 源码阅读笔记
- ALLJOYN源码阅读笔记
- ArrayList源码阅读笔记
- Flask 源码阅读笔记
- memcached 源码阅读笔记
- NASM源码阅读笔记
- CFRunloop 源码阅读笔记
- 网络基础知识备忘
- 初来乍到,学习一下
- jquery+ajax+servlet实现无刷新图片上传
- 企业中间件调查
- LeetCode: Insert Interval [056]
- netmap源码阅读笔记
- tinyxml
- 1.中国象棋将帅问题
- 儿童歌热帖供热
- rtl81xxe vlan部分处理原理以及GPIO处理原理。
- Codeforces Round #247 Div2
- Iterator方法解析
- Java平台介绍
- rman跨平台数据库移动