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
int
main(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;
}
else
last_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;
}
staticvoid
l2fwd_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);
}
}
}
}
staticvoid
l2fwd_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内置对 ...
随机推荐
- Mybatis学习笔记(三) 之Dao开发
使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法,常用还是Mapper接口开发. SqlSession的使用范围 public class test1 { ...
- __import__简介
__import__() import 语句通过调用__import__()来完成工作,提供这个函数是为了让有特殊需要的用户覆盖他,实现自定义.__import__最大的好处就是可以使程序在r ...
- Angularjs中的嵌套路由ui-router
先看看ng-router和ui-router的区别 (1)ng-route的局限性:一个页面无法嵌套多个视图,也就是说一个页面只能有包含一个页面一个控制器的切换. (2)ui-route的改进:在具 ...
- cache数据库学习周结
学习cache数据库只有两周,下面说一下对这一数据库的理解吧.不一定对 cache数据库最大的特点是global: global就像全区变量一样,是一个广义的全局变量.数据库表中的一些重要的字段名以字 ...
- java 异常的捕获及处理
在没有异常处理的程序中如果要回避异常,需要使用大量的判断语句,配合所想到的错误状况来捕捉程序中可能发生的错误.但是这样势必会导致程序运行效率降低.java异常处理机制具有易于使用,可自定义异常类,处理 ...
- laravel-1 安装.配置
听说laravel一直是一个很牛B的框架,之前接触过tp ci 也还只是一个小白,具体的核心没搞过,但对于我来说,框架都是拿来用的,会用即可. 以下内容为观看视频和自己查看资料后的整理,方便大家和自己 ...
- FZU 2243 Daxia like uber
枚举,最短路. 求出5个点出发的最短路,然后枚举一下这些点之间走的顺序. #pragma comment(linker, "/STACK:1024000000,1024000000" ...
- hdu 3507 Print Article(斜率优化DP)
题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...
- [Q]关于无法进入主界面问题解答
打图精灵适用于AutoCAD2007或更高版,低于2007版无法使用. 若在安装打图精灵前AutoCAD已经打开,则需要将AutoCAD重新打开,然后使用“QPlot”命令. 若重新打开仍然调不出界面 ...
- [河南省ACM省赛-第三届] 房间安排 (nyoj 168)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=168 分析:找到一天中需要最多的房间即可 #include<iostream> ...