DPDK l2fwd 浅注


































l2fwd是DPDK中的非常经典的例子。二层转发模型。
./l2fwd [EAL options]---p PORTMASK [-q NQ]--[no-]mac-updating
-c 3-n 2
-c 表示的是整个程序会使用哪些核例如:-c f 表示 20+21+22+23- 表示 四个核都会用上。
---p 3
-q 1
./l2fwd -c3 -n2 ---p 3-q 1
intmain(int argc,char**argv){struct lcore_queue_conf *qconf;struct rte_eth_dev_info dev_info;int ret;uint8_t nb_ports;uint8_t nb_ports_available;uint8_t portid, last_port;unsigned lcore_id, rx_lcore_id;unsigned nb_ports_in_mask =0;/* init EAL */ret = rte_eal_init(argc, argv); //EAL的初使化。if(ret <0)rte_exit(EXIT_FAILURE,"Invalid EAL arguments\n");argc -= ret;argv += ret;force_quit =false;signal(SIGINT, signal_handler);signal(SIGTERM, signal_handler);/* parse application arguments (after the EAL ones) */ret = l2fwd_parse_args(argc, argv);//这里是解析后面的---p 3-q 1 参数,用于获得这些参数的值。if(ret <0)rte_exit(EXIT_FAILURE,"Invalid L2FWD arguments\n");/* convert to number of cycles */timer_period *= rte_get_timer_hz();/* create the mbuf pool */l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF,MEMPOOL_CACHE_SIZE,0, RTE_MBUF_DEFAULT_BUF_SIZE, //创建内存池,rte_socket_id());if(l2fwd_pktmbuf_pool == NULL)rte_exit(EXIT_FAILURE,"Cannot init mbuf pool\n");nb_ports = rte_eth_dev_count(); //获得当初可用的最大网口数,是从PCI中获得的。if(nb_ports ==0)rte_exit(EXIT_FAILURE,"No Ethernet ports - bye\n");/* reset l2fwd_dst_ports */for(portid =0; portid < RTE_MAX_ETHPORTS; portid++)l2fwd_dst_ports[portid]=0;last_port =0;/** Each logical core is assigned a dedicated TX queue on each port.*/for(portid =0; portid < nb_ports; portid++){ //这里其实就是确定每个网口的发包对象。如网口0的报文传给网口1,。。。。这里就是初使化一个数组。/* skip ports that are not enabled */if((l2fwd_enabled_port_mask &(1<< portid))==0)continue;if(nb_ports_in_mask %2){l2fwd_dst_ports[portid]= last_port;l2fwd_dst_ports[last_port]= portid;}elselast_port = portid;nb_ports_in_mask++;rte_eth_dev_info_get(portid,&dev_info);}if(nb_ports_in_mask %2){printf("Notice: odd number of ports in portmask.\n");l2fwd_dst_ports[last_port]= last_port;}rx_lcore_id =0;qconf = NULL;/* Initialize the port/queue configuration of each logical core */for(portid =0; portid < nb_ports; portid++){//给每一个网口分配一个可用的,你配置过的逻辑核/* skip ports that are not enabled */if((l2fwd_enabled_port_mask &(1<< portid))==0)continue;/* get the lcore_id for this port */while(rte_lcore_is_enabled(rx_lcore_id)==0||lcore_queue_conf[rx_lcore_id].n_rx_port ==l2fwd_rx_queue_per_lcore){rx_lcore_id++;if(rx_lcore_id >= RTE_MAX_LCORE)rte_exit(EXIT_FAILURE,"Not enough cores\n");}if(qconf !=&lcore_queue_conf[rx_lcore_id])/* Assigned a new logical core in the loop above. */qconf =&lcore_queue_conf[rx_lcore_id];qconf->rx_port_list[qconf->n_rx_port]= portid;qconf->n_rx_port++;printf("Lcore %u: RX port %u\n", rx_lcore_id,(unsigned) portid);}nb_ports_available = nb_ports;/* Initialise each port */for(portid =0; portid < nb_ports; portid++){//就是初使化网口,给每个网口分配接收的缓存,分配接收和发送的队列。/* skip ports that are not enabled */if((l2fwd_enabled_port_mask &(1<< portid))==0){printf("Skipping disabled port %u\n",(unsigned) portid);nb_ports_available--;continue;}/* init port */printf("Initializing port %u... ",(unsigned) portid);fflush(stdout);ret = rte_eth_dev_configure(portid,1,1,&port_conf);//设置portid这个网口一个接收和一个发送的队列。if(ret <0)rte_exit(EXIT_FAILURE,"Cannot configure device: err=%d, port=%u\n",ret,(unsigned) portid);rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);/* init one RX queue */fflush(stdout);ret = rte_eth_rx_queue_setup(portid,0, nb_rxd, //给对应的网口分配接收队列。rte_eth_dev_socket_id(portid),NULL,l2fwd_pktmbuf_pool);if(ret <0)rte_exit(EXIT_FAILURE,"rte_eth_rx_queue_setup:err=%d, port=%u\n",ret,(unsigned) portid);/* init one TX queue on each port */fflush(stdout);ret = rte_eth_tx_queue_setup(portid,0, nb_txd,//给对应的网口分配发送队列。rte_eth_dev_socket_id(portid),NULL);if(ret <0)rte_exit(EXIT_FAILURE,"rte_eth_tx_queue_setup:err=%d, port=%u\n",ret,(unsigned) portid);/* Initialize TX buffers */tx_buffer[portid]= rte_zmalloc_socket("tx_buffer",//分配接收缓存空间,就是收包的缓存。RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST),0,rte_eth_dev_socket_id(portid));if(tx_buffer[portid]== NULL)rte_exit(EXIT_FAILURE,"Cannot allocate buffer for tx on port %u\n",(unsigned) portid);rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],//当报文发送失败后要调用的回调函数rte_eth_tx_buffer_count_callback,&port_statistics[portid].dropped);if(ret <0)rte_exit(EXIT_FAILURE,"Cannot set error callback for ""tx buffer on port %u\n",(unsigned) portid);/* Start device */ret = rte_eth_dev_start(portid);if(ret <0)rte_exit(EXIT_FAILURE,"rte_eth_dev_start:err=%d, port=%u\n",ret,(unsigned) portid);printf("done: \n");rte_eth_promiscuous_enable(portid);//设置该网口为混杂模式,就是接收所有的报文。printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",//初使化报文统计(unsigned) portid,l2fwd_ports_eth_addr[portid].addr_bytes[0],l2fwd_ports_eth_addr[portid].addr_bytes[1],l2fwd_ports_eth_addr[portid].addr_bytes[2],l2fwd_ports_eth_addr[portid].addr_bytes[3],l2fwd_ports_eth_addr[portid].addr_bytes[4],l2fwd_ports_eth_addr[portid].addr_bytes[5]);/* initialize port stats */memset(&port_statistics,0,sizeof(port_statistics));}if(!nb_ports_available){rte_exit(EXIT_FAILURE,"All available ports are disabled. Please set portmask.\n");}check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);//检查这些网口是否可以用。ret =0;/* launch per-lcore init on every lcore */rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);//在所有的逻辑核(包括管理核,一般DPDK会默认将第一个可用的逻辑核当管理核)上执行l2fwd_launch_one_lcore这个函数。RTE_LCORE_FOREACH_SLAVE(lcore_id){if(rte_eal_wait_lcore(lcore_id)<0){//等待从逻辑核的结束。ret =-1;break;}}for(portid =0; portid < nb_ports; portid++){ //down掉网口,结束。if((l2fwd_enabled_port_mask &(1<< portid))==0)continue;printf("Closing port %d...", portid);rte_eth_dev_stop(portid);rte_eth_dev_close(portid);printf(" Done\n");}printf("Bye...\n");return ret;}
staticvoidl2fwd_main_loop(void){struct rte_mbuf *pkts_burst[MAX_PKT_BURST];struct rte_mbuf *m;int sent;unsigned lcore_id;uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;unsigned i, j, portid, nb_rx;struct lcore_queue_conf *qconf;constuint64_t drain_tsc =(rte_get_tsc_hz()+ US_PER_S -1)/ US_PER_S *BURST_TX_DRAIN_US;struct rte_eth_dev_tx_buffer *buffer;prev_tsc =0;timer_tsc =0;lcore_id = rte_lcore_id();qconf =&lcore_queue_conf[lcore_id];//获得我们初使化的时候配置的逻辑核与网口的对应关系列表。if(qconf->n_rx_port ==0){RTE_LOG(INFO, L2FWD,"lcore %u has nothing to do\n", lcore_id);return;}RTE_LOG(INFO, L2FWD,"entering main loop on lcore %u\n", lcore_id);for(i =0; i < qconf->n_rx_port; i++){portid = qconf->rx_port_list[i];RTE_LOG(INFO, L2FWD," -- lcoreid=%u portid=%u\n", lcore_id,portid);}while(!force_quit){cur_tsc = rte_rdtsc();/** TX burst queue drain*/diff_tsc = cur_tsc - prev_tsc;if(unlikely(diff_tsc > drain_tsc)){//时间时隔到了就刷新发送所有网口上的待发送的报文。for(i =0; i < qconf->n_rx_port; i++){portid = l2fwd_dst_ports[qconf->rx_port_list[i]];buffer = tx_buffer[portid];sent = rte_eth_tx_buffer_flush(portid,0, buffer);if(sent)port_statistics[portid].tx += sent;}/* if timer is enabled */if(timer_period >0){/* advance the timer */timer_tsc += diff_tsc;/* if timer has reached its timeout */if(unlikely(timer_tsc >= timer_period)){/* do this only on master core */if(lcore_id == rte_get_master_lcore()){//如果是在逻辑核上,且符合条件,就打印统计信息。print_stats();/* reset the timer */timer_tsc =0;}}}prev_tsc = cur_tsc;}/** Read packet from RX queues*/for(i =0; i < qconf->n_rx_port; i++){//轮询每个网口,进行接收报文。portid = qconf->rx_port_list[i];nb_rx = rte_eth_rx_burst((uint8_t) portid,0,pkts_burst, MAX_PKT_BURST);port_statistics[portid].rx += nb_rx;for(j =0; j < nb_rx; j++){m = pkts_burst[j];rte_prefetch0(rte_pktmbuf_mtod(m,void*));l2fwd_simple_forward(m, portid);}}}}
staticvoidl2fwd_simple_forward(struct rte_mbuf *m,unsigned portid){struct ether_hdr *eth;void*tmp;unsigned dst_port;int sent;struct rte_eth_dev_tx_buffer *buffer;dst_port = l2fwd_dst_ports[portid];//获得发送的网口,相当于就是做转发。eth = rte_pktmbuf_mtod(m,struct ether_hdr *);/* 02:00:00:00:00:xx */tmp =ð->d_addr.addr_bytes[0];*((uint64_t*)tmp)=0x000000000002+((uint64_t)dst_port <<40);/* src addr */ether_addr_copy(&l2fwd_ports_eth_addr[dst_port],ð->s_addr);buffer = tx_buffer[dst_port];//获得初使化的时候配置的发送缓存。sent = rte_eth_tx_buffer(dst_port,0, buffer, m);//预发送,其实并没有真正的发送。if(sent)port_statistics[dst_port].tx += sent;}
DPDK l2fwd 浅注的更多相关文章
- DPDK L2fwd 源码阅读
代码部分 /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2016 Intel Corporation */ #include ...
- DPDK l2fwd
dpdk的l2fwd主要做二层转发,代码分析如下. #include <stdio.h> #include <stdlib.h> #include <string.h&g ...
- dpdk l2fwd 应用流程分析
int MAIN(int argc, char **argv) { struct lcore_queue_conf *qconf; struct rte_eth_dev_info dev_info; ...
- 浅谈.net core如何使用EFCore为一个上下文注类型注入多个实例用于连接主从数据库
在很多一主多从数据库的场景下,很多开发同学为了复用DbContext往往采用创建一个包含所有DbSet<Model>父类通过继承派生出Write和ReadOnly类型来实现,其实可以通过命 ...
- 浅谈Hybrid技术的设计与实现第三弹——落地篇
前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...
- 浅谈Android编码规范及命名规范
前言: 目前工作负责两个医疗APP项目的开发,同时使用LeanCloud进行云端配合开发,完全单挑. 现大框架已经完成,正在进行细节模块上的开发 抽空总结一下Android项目的开发规范:1.编码规范 ...
- 浅谈Vue.js
作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的 ...
- 浅谈php生成静态页面
一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权 ...
- jsp内置对象浅谈
jsp内置对象浅谈 | 浏览:1184 | 更新:2013-12-11 16:01 JSP内置对象:我们在使用JSP进行页面编程时可以直接使用而不需自己创建的一些Web容器已为用户创建好的JSP内置对 ...
随机推荐
- Angular2中的Service并不是单例模式
2015年做了一个使用angularjs 1框架的项目,2016年伊始公司的项目转为使用Angular2框架. 在开发过程中发现了一个坑,这个坑就是在Angular JS 1.x中的Service是单 ...
- android浏览器 源码共享
浏览器源码共享 [天天浏览器]拥有极为精简的内核,手机App大小在2MB以内,是市场上极省用户手机内存,极少占用手机资源,速度极快的浏览器,本身功能完整强大,是极速上网必备的利器. 源代码下载地址:h ...
- 【NOIP2012】DAY1+DAY2题解
不贴代码的原因是我的代码在初中机房.忘记带过来了. DAY 1 T1随便搞,但是字符串相关的题我经常犯蠢 T2 一个结论题,OAO但是需要高精度写. 具体就是按左手的数除右手的数(还是怎么的来着)排个 ...
- C# 3.0相比C# 2.0增加的功能
1.自动属性 (1)自动属性(Auto-Implemented Properties),C#自动属性可以避免原来我们手工的来声明一个私有成员变量以及和属性get,set的书写. public clas ...
- WPF中TextBox的PreviewMouseLeftButtonUp事件
当使用TextBox的PreviewMouseLeftButtonUp事件时(例如,鼠标点击进入TextBox时,清除当前的输入内容),会很意外地发现,这时候不论怎么点击都无法点击到其他控件,焦点一直 ...
- .NET中的SqlBulkCopy类用法
在开发过程中,经常会遇到向数据库插入大量数据的情况,那么如果是百万条数据,一条条的插入实在是太慢了,所以就有了SqlBulkCopy类. 本文中我将示范SqlBulkCopy类的不同应用. 以下面三张 ...
- 去掉UItableview section headerview黏性
UITabelView在style为plain时,在上拉是section始终粘在最顶上而不是跟随滚动而消失或者出现 可以通过设置UIEdgeInsetsMake: - (void)scrollView ...
- vue跨组件通信的几种方法
http://www.tuicool.com/articles/jyM32mA 在开发组件的时候,一定会遇到组件的通信,比如点击一个图标出现弹窗和蒙层,这三个分别是不同的组件.管理他们之间的状态就成了 ...
- Chapter 18_0 数学库
从今天起,开始接触Lua的标准库(数学库.table库.字符库.I/O库.操作系统库.调试库). 一路走来,从最基本的变量.函数.迭代器.协同程序到稍微复杂的元表.元方法.环境.模块,以及最后被整蒙了 ...
- CodeForces 546D
Description 两个士兵在玩一个游戏,开始的时候第一个士兵选择一个数n,并把这个数交给第二个士兵,第二个士兵必须选择一个x满足x>1 且n能被x整除,然后将n变为n/x,然后把这个数交给 ...