#define PAGES_ORDER 9 unsigned long su1_2 su1_2 = __get_free_pages(GFP_KERNEL,PAGES_ORDER);
b. 向缓存中写入数据:真正IDS产品中的零拷贝实现应该是使用DMA数据传输把网卡硬件接收到的包直接写入该缓存。作为试验,我只是向该缓存中写入几个任意的字符串,如果不考虑DMA而又想向缓存中写入真正的网络数据包,可以在8139too.c的rtl8139_rx_interrupt()中调用 netif_rx()后插入以下代码:
c. 把该缓存的物理地址传到用户空间:由于在内核中申请的缓存地址为虚拟地址,而在用户空间需要得到的是该缓存的物理地址,所以首先要进行虚拟地址到物理地址的转换,在linux系统中可以使用内核虚拟地址减3G来获得对应的物理地址。把缓存的地址传到用户空间需要在内核与用户空间进行少量数据传输,这可以使用字符驱动、proc文件系统等方式实现,在这里采用了proc文件系统方式。
int main() { char *su1_2; char receive[1500]; int i,j; int fd; int fd_procaddr; unsigned int size; char addr[9]; unsigned long ADDR;
j = 0; /*open device 'mem' as a media to access the RAM*/ fd=open("/dev/mem",O_RDWR); fd_procaddr = open("/proc/nf_addr",O_RDONLY); read(fd_procaddr,addr,9); ADDR = atol(addr); close(fd_procaddr); printf("%u[%8lx]\n",ADDR,ADDR); /*Map the address in kernel to user space, use mmap function*/ su1_2 = mmap(0,PAGES*4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, ADDR); perror("mmap"); while(1) { bzero(receive,1500); i = get_mem(su1_2,receive,&size); if (i != 0) { j++; printf("%d:%s[size = %d]\n",j,receive,size); } else { printf("there have no data\n"); munmap(su1_2,PAGES*4*1024); close(fd); break; } } while(1); }
五.参考文献 1.CHRISTIAN KURMANN, FELIX RAUCH ,THOMAS M. STRICKER. Speculative Defragmentation - Leading Gigabit Ethernet to True Zero-Copy Communication 2.ALESSANDRO RUBINI,JONATHAN CORBET.《LINUX DEVICE DRIVERS 2》,O’Reilly & Associates 2002. 3.胡希明,毛德操.《LINUX 内核源代码情景分析》,浙江大学出版社 2001