DPDK Samples 02l2fwd

来源:互联网 发布:淘宝细节图片尺寸 编辑:程序博客网 时间:2024/06/03 18:36
2. 使用DPDK抓包和发包
    通过hello world,知道了如何启动DPDK多核程序
    那么每个核如何抓某个网卡的数据报文,以及如何从某个网卡发送报文
    
    下面分析l2fwd样例程序:
    1. rte_eal_init
    2. l2fwd_parse_args(argc, argv)
    DPDK应用程序可以带有自己的参数通过--和eal参数区分如:
    ./test -cf -n4 -- -p f
    3. 创建pkt mbuf pool 初始化接收缓存
    l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create();
    4. 计算时间周期
    timer_period *= rte_get_timer_hz()
    5. 获取网卡数量
    nb_ports = rte_eth_dev_count()
    
    6. 设置每个端口的发送目的端口
    int last_port = 0;
    int count = 0;
    for (portid = 0; portid < nb_ports; portid++) {
        if ((port_mask & (1 << portid)) == 0) continue;
        if (count % 2 == 0) {
            last_port = portid;
        } else {
            dst_port[portid] = last_port;
            dst_port[last_port] = portid;
        }
        count++;
    }
    7. 设置每个lcore的rx接口
    8. 初始化接口
        A. 配置端口:
        int rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_queue,
        uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf);
        rte_eth_dev_configure(portid, 1, 1, &port_conf);
        B. 获取端口MAC地址
        rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr);
        rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
        C. 初始化接收队列
        int rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
        uint16_t nb_rx_desc, unsigned int socket_id,
        const struct rte_eth_rxconf *rx_conf,
        struct rte_mempool *mb_pool);
        rte_eth_rx_queue_setup(portid, 0, nb_rxd,
            rte_eth_dev_socket_id(portid), NULL, l2fwd_pktmbuf_pool);
        D. 初始化发送队列
        int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
        uint16_t nb_tx_desc, unsigned int socket_id,
        const struct rte_eth_txconf *tx_conf);
        rte_eth_tx_queue_setup(portid, 0, nb_txd,
            rte_eth_dev_socket_id(portid), NULL);
    
        E. 初始化发送缓存
        void *
        rte_zmalloc_socket(const char *type,
        size_t size, unsigned align, int socket);
        tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
            RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
            rte_eth_dev_socket_id(portid));
        
        rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
        
        rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
        rte_eth_tx_buffer_count_callback,
        &port_statistics[portid].dropped);
        
        F. 开启接口设备
        rte_eth_dev_start(portid);
        
        G. 让设备进入混杂模式
        rte_eth_promiscuous_enable(portid);
        
    9. 检查每个接口的链接状态
    rte_eth_link_get_nowait(portid, &link);
    
    10. 每个核执行l2fwd_launch_one_lcore函数,主核也进入,然后等待从核
    rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASK);
    
    11. rte_eal_mp_remote_launch() 执行 l2fwd_main_loop();
    
    12. l2fwd_main_loop()
        A. 如果此lcore有接收接口,就放这个接收接口的目的端口,发送数据到这个接口
        portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
        buffer = tx_buffer[portid];
        rte_eth_tx_buffer_flush(portid, 0, buffer);
        static inline uint16_t
        rte_eth_tx_buffer_flush(uint8_t port_id, uint16_t queue_id,
        struct rte_eth_dev_tx_buffer *buffer)
        B. 周期性显示统计信息
        
        C. 接收数据
        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
        portid = qconf->rx_port_list[i];
        nb_rx = rte_eth_tx_burst(portid, 0, pkts_burst, MAX_PKT_BURST);
        l2fwd_simple_forward(m, portid)
        
    13. l2fwd_simple_forward()
        l2fwd_mac_updating
        rte_eth_tx_buffer(dst_port, 0, buffer, m);
    
    14. 等待核心结束
        rte_eal_wait_lcore(lcore_id)
        
    15. 关闭接口释放内存
        rte_eth_dev_stop()
        rte_eth_dev_close()
        rte_mbuf_free();
        
    现在我们能够启动多核程序,以及在每个核中进行抓包,发包
    之后就是对报文进行处理,也就是数据开发
    这就得继续学习DPDK的<<程序开发指南>>和<<API指南>> <<Examples>>