vppinfra----mpcap介绍

2023-03-07 17:00:40 浏览数 (1)

mpcap 是利用mmap 文件映射的方式把抓包文件映射进程的虚拟地址空间。从而减少了write函数一次内存拷贝到页缓存的过程,从而提高效率。

在简书上 《深入剖析mmap原理 - 从三个关键问题说起》

(https://www.jianshu.com/p/eece39beee20)及《深入浅出Linux】关于mmap的解析》(https://www.jianshu.com/p/755338d11865)有关于mmap的相关的数据分析。详细的可以去了解一下。

下面内容来源于简书,详细介绍了write系统调用写文件流程

  1. Step1:进程(用户态)调用write系统调用,并告诉内核需要写入数据的开始地址与长度(告诉内核写入的数据在哪)。
  2. Step2:内核write方法,将校验用户态的数据,然后复制到kernel buffer(这里是Page Cache)。 [ ps: 特意查了ext4 write的内核实现,write是直接将user buffer copy到page中 ]
  3. Step3: 由操作系统调用,将脏页回写到磁盘(通常这是异步的)

再来简单讲讲使用mmap时,写入文件流程:

  1. Step1:进程(用户态)将需要写入的数据直接copy到对应的mmap地址(内存copy)
  2. Step2: 2.1) 若mmap地址未对应物理内存,则产生缺页异常,由内核处理 2.2) 若已对应,则直接copy到对应的物理内存
  3. Step3:由操作系统调用,将脏页回写到磁盘(通常这是异步的)

可以看到mmap在100byte写入时已经基本达到最大写入性能,而write调用需要在4096(也就是一个page size)时,才能达到最大写入性能。 从测试结果可以看出,在写小数据时,mmap会比write调用快,但在写大数据时,反而没那么快。------本人也不清楚数据的可靠性,还要自己实际对比测试。

每次写入大小

mmap 耗时

write 耗时

100 bytes

2.84s

22.86s

512 bytes

2.51s

5.43s

1024 bytes

2.48s

3.48s

2048 bytes

2.47s

2.34s

4096 bytes

2.48s

1.74s

8192 bytes

2.45s

1.67s

10240 bytes

2.49s

1.65s

好了,回到正文,来介绍mpcap的结构及使用,mpcap所有代码就这四个文件。也体现了vpp的架构分层。

mpcap基础库mpcap_close、mpcap_init、mpcap_map

src/vppinfra/mpcap.h

src/vppinfra/mpcap.c

基于vlib_buffer_t结构的写文件接口函数mpcap_add_buffer

src/vnet/mpcap.h

mpcap 单元测试例子

src/plugins/unittest/mpcap_node.c :。

  • mpcap_main数据结构

结构体定义在src/vppinfra/mpcap.h文件中。

代码语言:javascript复制
typedef struct
{
  /** File name of mpcap output. */
  char *file_name;
  /** spinlock, initialized if flagged MPCAP_FLAG_THREAD_SAFE */
  clib_spinlock_t lock;
  /** Number of packets to capture. */
  u32 n_packets_to_capture;
  /** Packet type */
  mpcap_packet_type_t packet_type;
  /** Maximum file size */
  u64 max_file_size;
  /** Base address */
  u8 *file_baseva;
  /** current memory address */
  u8 *current_va;
  /** Number of packets currently captured. */
  u32 n_packets_captured;
  /** Pointer to file header in svm, for ease of updating */
  mpcap_file_header_t *file_header;
  /** flags */
  u32 flags;
#define MPCAP_FLAG_INIT_DONE (1 << 0)
#define MPCAP_FLAG_THREAD_SAFE (1 << 1)
#define MPCAP_FLAG_WRITE_ENABLE (1 << 2)
  /** Bytes written */
  u32 n_mpcap_data_written;
  /** Vector of mpcap data. */
  u8 *mpcap_data;
  /** Packets in mapped mpcap file. */
  u64 packets_read;
  /** Min/Max Packet bytes */
  u32 min_packet_bytes, max_packet_bytes;
} mpcap_main_t;

结构体字段还是比较容易理解的。主要说下最后三个字段是mpcap_map使用。是另外一个进程统计当前已经读了多少报文。及最大最小报文长度。

packets_read :统计当前读了多少报文。

min_packet_bytes:最小报文字节数。

max_packet_bytes:最大报文字节数。

  • mpcap 的使用

vpp提供了详细使用例子,可以在文件中src/plugins/unittest/mpcap_node.c看到。

1、定义自己的test_mpcap_main

这里有一点需要说明,默认flag标识是不开启多线程锁的。需要多线程使用的话,需要flag标识置位MPCAP_FLAG_THREAD_SAFE。

代码语言:javascript复制
static mpcap_main_t test_mpcap_main = {
  .file_name = "/tmp/mpcap_unittest.pcap",
  .n_packets_to_capture = 15,
  .packet_type = MPCAP_PACKET_TYPE_ethernet,
};

2、初始化test_mpcap_main

代码语言:javascript复制
mpcap_init (&test_mpcap_main);

3、将报文写入文件中

写报文函数在src/vnet/mpcap.h文件中。

代码语言:javascript复制
 mpcap_add_buffer (&test_mpcap_main, vm, now_time, b[0],pkt_lens)
  • 总结 mpcap相关函数的使用还是比较简单的。这里只是简单介绍了使用方法。可以根据mpcap的代码来实现自己的基于mmap的写文件接口。

0 人点赞