DPDK(F-Stack) 实现UDP通信

news2024/11/7 17:43:09

因刚开始学习DPDK,在学习过程中了解到需使用用户态协议栈,在网上找到F-Stack的相关介绍,但是缺乏DPDK的相关知识,导致使用F-Stack 时UDP数据无法收到

  • 一文了解dpdk rte_ring无锁队列
  • F-Stack实现UDP服务端、客户端,并进行吞吐量测试的实现
  • github F-Stack

环境

在一台机器上,系统为Ubuntu 22.4

硬件上是一张100G网卡 两个网口,光纤直连两个网口

UDPServer 的port0.ini配置文件中设置IP如下并使用网卡的PORT0端口

[port0]
addr=192.168.2.15
netmask=255.255.255.0
broadcast=192.168.2.255
gateway=192.168.2.1

UDPClient 的port1.ini配置文件中设置IP如下并使用网卡的PORT1端口

[port1]
addr=192.168.2.16
netmask=255.255.255.0
broadcast=192.168.2.255
gateway=192.168.2.1

问题

服务端可以接收到客户端的arp请求报文并且应答了arp报文,然后就卡住了,ff_envent()函数无法检测到sockfd有数据
UDPServer配置文件中的 lcore_mask 参数我配置的是f0

lcore_mask=f0

本意是想启动一个UDPServer程序使用4个逻辑核心,经过测试启动一个程序只能使用配置的第一个逻辑核心,此时去使用UDPClient发送数据到UDPServer时就无法收到数据,不知道是我个人有这个问题,还是在同一电脑上的同一张网卡配置多个逻辑核心时都无法收到数据,就是这么设计的吗

解决

后续又买了一块相同的100G网卡,放在另一台电脑,光纤直连,然后发送数据,此时竟然可以收到数据。那就证明代码收发是正确的

后续查看源码时在源码文件 ff_dpdk_if.cmain_loop() 函数中有调用 process_dispatch_ring() 函数,函数内调用了 rte_ring_dequeue_burst(),大概了解了一下,我猜测因为我配置了4个核心,在初始化时创建了4个ring队列

从打印的信息来看也是这样的:

create ring:dispatch_ring_p0_q0 success, 2047 ring entries are now free!
create ring:dispatch_ring_p0_q1 success, 2047 ring entries are now free!
create ring:dispatch_ring_p0_q2 success, 2047 ring entries are now free!
create ring:dispatch_ring_p0_q3 success, 2047 ring entries are now free!

我个人猜测,很有可能是因为接收UDP数据被分发给了其它的队列上,我只启动一个程序也就是只是用了第一个ring队列,那么就不可能收到数据,然后我相应的启动了4个程序,终于收到了数据,老天爷,对于一个刚学习DPDK的人简直是折磨。

$ ./UDPServer -c port0.ini -p 0 &
$ ./UDPServer -c port0.ini -p 1 &
$ ./UDPServer -c port0.ini -p 2 &
$ ./UDPServer -c port0.ini -p 3 &

如果不想启动多个进程的话,把配置文件中的核心数配置为1个,启动一个程序就可以收发数据了。

代码

UDPserver


#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <cerrno>
#include <stdlib.h>
#include <rte_ethdev.h>


// F-stack
#include <ff_api.h>
#include <ff_config.h>

#define MAX_EVENTS 512
#define MAXLINE 512

int kq;
int sockfd;
/* kevent set */
struct kevent kevSet;
/* events */
struct kevent events[MAX_EVENTS];

int loop(void *arg){

    char buf[MAXLINE] = {"0"};
    
    struct sockaddr_in cliAddr;
    socklen_t recvAddrLen = sizeof(cliAddr);
    
    int nevents = ff_kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
    if (nevents < 0) {
        printf("ff_kevent failed:%d, %s\n", errno, strerror(errno));
        return -1;
    }

    for (int i = 0; i < nevents; ++i) {
        struct kevent event = events[i];
        int clientfd = (int)event.ident;

        printf("event.data = %d \n", (int)event.data);
        printf("listen event %d\n", nevents);
        printf("clientfd %d\n", clientfd);
        printf("sockfd %d\n", sockfd);
        printf("event.flags = %d \n", event.flags);
        if (clientfd == sockfd) {
            int n = ff_recvfrom(sockfd, buf, MAXLINE, 0,  (struct linux_sockaddr *)&cliAddr, &recvAddrLen);
            if(n < 0){
                printf("ff_recvfrom failed, errno:%d, %s\n", errno, strerror(errno));
            }else{
                // 接收数据 并打印
                printf("Server recv   %s\n", buf);
                printf("Client Family %d\n", cliAddr.sin_family);
                printf("Client Addr   %s\n", inet_ntoa(cliAddr.sin_addr));
                printf("Client Port   %u\n", ntohs(cliAddr.sin_port));

                strcpy(buf, "hello client, i am server");
                int num = ff_sendto(sockfd, buf, sizeof(buf) / sizeof(buf[0]), 0, (struct linux_sockaddr *)&cliAddr, recvAddrLen);
                if(num < 0){
                    printf("ff_sendto failed, errno:%d, %s\n", errno, strerror(errno));
                    ff_stop_run();
                }else{
                    printf("Server send %d bytes\n", num);
                }
            }
        }
    }

    return 1;
}


int main(int argc, char **argv){

    int on = 1;
    struct sockaddr_in my_addr;

    ff_init(argc, argv);

    kq = ff_kqueue();
    if (kq < 0) {
        printf("ff_kqueue failed, errno:%d, %s\n", errno, strerror(errno));
        exit(1);
    }

    sockfd = ff_socket(AF_INET, SOCK_DGRAM, 0);
    ff_ioctl(sockfd, FIONBIO, &on);

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(34824);
    my_addr.sin_addr.s_addr =  htonl(INADDR_ANY);

    
    int ret = ff_bind(sockfd, (struct linux_sockaddr *)&my_addr, sizeof(my_addr));
    if (ret < 0) {
        printf("ff_bind failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
        exit(1);
    }

    EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
    /* Update kqueue */
    ff_kevent(kq, &kevSet, 1, NULL, 0, NULL);

    ff_run(loop, NULL);

    if(rte_eth_dev_stop(0) < 0)
        rte_exit(EXIT_FAILURE, "Cannot close eth %" PRIu16 "\n", 0);

    rte_eal_cleanup();

    return 1;
}

UDPClient

#include <stdio.h>

#include <sys/ioctl.h>
#include <string.h>
#include <cerrno>
#include <stdlib.h>
#include <rte_ethdev.h>

// F-stack
#include <ff_api.h>
#include <ff_config.h>

#define MAX_EVENTS 512
#define MAXLINE 512
int kq;
int sockfd;
/* kevent set */
struct kevent kevSet;
/* events */
struct kevent events[MAX_EVENTS];
struct sockaddr_in serverAddr;


int loop(void *arg){
    int num;
    char buf[MAXLINE] = {"0"};

    struct sockaddr_in recvAddr;
    socklen_t recvAddrLen = sizeof(recvAddr);
    
    strcpy(buf,"hello, i am client");
    num = ff_sendto(sockfd, buf, sizeof(buf)/sizeof(buf[0]), 0, (struct linux_sockaddr *)&serverAddr, sizeof(serverAddr));
    if(num < 0){
        printf("ff_kevent failed:%d, %s\n", errno, strerror(errno));
        ff_stop_run();
    }else
        printf("sendto num:%d\n", num);
    
    int nevents = ff_kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
    if (nevents < 0) {
        printf("ff_kevent failed:%d, %s\n", errno, strerror(errno));
        ff_stop_run();
        return -1;
    }

    for (int i = 0; i < nevents; ++i) {
        printf("listen nevents !!! \n");
        struct kevent event = events[i];
        int serverfd = (int)event.ident;

        printf("event.data = %d \n", (int)event.data);
        printf("event.flags = %d \n", event.flags);
        printf("serverfd = %d \n", serverfd);
        printf("sockfd = %d \n", sockfd);
        if (serverfd == sockfd) {
            int n = ff_recvfrom(sockfd, buf, MAXLINE, 0,  (struct linux_sockaddr *)&recvAddr, &recvAddrLen);
            if(n < 0){
                printf("ff_recvfrom failed, errno:%d, %s\n", errno, strerror(errno));
            }else{
                // 接收数据 并打印
                printf("Client recv   %s\n", buf);
                printf("Server Family %d\n", recvAddr.sin_family);
                printf("Server Addr   %s\n", inet_ntoa(recvAddr.sin_addr));
                printf("Server Port   %u\n", ntohs(recvAddr.sin_port));
                ff_stop_run();
            }
        }
    }
    return 1;
}


int main(int argc, char **argv){

    struct sockaddr_in my_addr;
    int on = 1;
    
    ff_init(argc, argv);

    kq = ff_kqueue();
    if (kq < 0) {
        printf("ff_kqueue failed, errno:%d, %s\n", errno, strerror(errno));
        exit(1);
    }

    sockfd = ff_socket(AF_INET, SOCK_DGRAM, 0);

    ff_ioctl(sockfd, FIONBIO, &on);

    
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(34825);
    my_addr.sin_addr.s_addr = inet_addr( "192.168.2.16" );

    ff_bind(sockfd, (struct linux_sockaddr *)&my_addr, sizeof(my_addr));

    // 指定发送的地址和端口号
    bzero(&serverAddr, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(34824);
    serverAddr.sin_addr.s_addr = inet_addr( "192.168.2.15" );


    EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
    /* Update kqueue */
    ff_kevent(kq, &kevSet, 1, NULL, 0, NULL);
    
    ff_run(loop, NULL);
   
    ff_close(sockfd);
    return 1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LangChain Ollama实战文献检索助手(二)少样本提示FewShotPromptTemplate示例选择器

本期是用样例来提示大模型生成我们想要的答案。即在输入中给定提示的样例&#xff0c;以及提示模板&#xff0c;然后匹配较相关的样例进行文献综述。 创建示例样本FewShotPromptTemplate 这里我用GTP-o1生成了几个回答&#xff0c;作为样本 samples [{"theme": &…

R语言*号标识显著性差异判断组间差异是否具有统计意义

前言 该R代码用于对Iris数据集进行多组比较分析&#xff0c;探讨不同鸢尾花品种在不同测量变量&#xff08;花萼和花瓣长度与宽度&#xff09;上的显著性差异。通过将数据转换为长格式&#xff0c;并利用ANOVA和Tukey检验&#xff0c;代码生成了不同品种间的显著性标记&#x…

AUTOSAR CP NVRAM Manager规范导读

一、NVRAM Manager功能概述 NVRAM Manager是AUTOSAR(AUTomotive Open System ARchitecture)框架中的一个模块,负责管理非易失性随机访问存储器(NVRAM)。它提供了一组服务和API,用于在汽车环境中存储、维护和恢复NV数据。以下是NVRAM Manager的一些关键功能: 数据存储和…

PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)

Adobe Acrobat DC 2023 是 Adobe 公司推出的一款功能强大的 PDF 文档处理软件。它不仅支持创建、编辑和签署 PDF 文件&#xff0c;还提供了丰富的工具来管理和优化这些文件。以下是 Acrobat DC 2023 的一些主要特点&#xff1a; 1.PDF 创建与编辑&#xff1a;用户可以直接从多…

Tornado简单使用

Tornado简单使用 1 介绍 Tornado 是一个基于Python的Web服务框架和 异步网络库&#xff0c;它最初由 FriendFeed 开发&#xff0c;后来被 Facebook 收购并开源&#xff0c;通过利用非阻塞网络 I/O, Tornado 可以承载成千上万的活动连接&#xff0c;完美的实现了 长连接、WebS…

基于SpringBoot的城镇保障性住房管理策略

3系统分析 3.1可行性分析 通过对本城镇保障性住房管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本城镇保障性住房管理系统采用SSM框架&#xff0c;JA…

【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值

设置方法 mini 中提供了 imageUrlLoaderOption 和 postcss.url 。 其中&#xff1a; config.limit 和 imageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js &#xff0c; 值的写法要 &#xff08;&#xff09;KB * 1024。 config.maxSize 服务于 postcss-url 的…

[实战-11] FlinkSql 设置时区对TIMESTAMP和TIMESTAMP_LTZ的影响

table.local-time-zone table.local-time-zoneDataStream-to-Table Conversion&#xff08;拓展知识&#xff09;代码测试flinksql代码执行结果截图1. Asia/Shanghai 结果如下2. UTC结果如下 table.local-time-zone table.local-time-zone可用于设置flinksql的时区。 flink的内…

Bypassuac之白名单结合注册表方式

参考 Bypass UAC 原来这么简单 本章记录一下系统白名单文件结合注册表bypassuac&#xff0c;uac这个东西并不是Windows设置的防御机制而是相当于保护机制&#xff0c;只是用来控制用户行为的&#xff0c;弹个窗来提醒一下用户的行为&#xff0c;和直接的杀软是不一样的性质&am…

【力扣打卡系列】单调栈

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day20 单调栈 题目描述 解题思路 单调栈 后进先出 记录的数据加在最上面丢掉数据也先从最上面开始 单调性 记录t[i]之前会先把所有小于等于t[i]的数据丢掉&#xff0c;不可能出现上面大下面小的…

如何通过CDN加速提升电商网站双十一购物节用户体验

随着双十一购物节的到来&#xff0c;电商平台迎来了一年中流量的高峰。各大电商平台如天猫、京东和抖音等纷纷推出了全新的促销活动和玩法。在这场购物狂欢中&#xff0c;用户体验成为了电商网站能否脱颖而出的关键。而CDN&#xff08;内容分发网络&#xff09;加速服务&#x…

Linux信号_信号的产生

信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 异步&#xff1a;在异步操作中&#xff0c;任务可以独立执行。一个任务的开始或完成不依赖于其他任务的状态。 同步&#xff1a;在同步操作中&#xff0c;任务之间的执行是相互依赖的。一个任务必须等待…

Docker学习—Docker核心概念总结

核心概念总结 容器&#xff1a;容器就是将应用运行所需的所有内容比如代码、运行时环境&#xff0c;进行打包和隔离。 容器和虚拟机的对比 虚拟机是在同一个硬件上虚拟化出多个操作系统&#xff08;OS&#xff09;实例。 容器是在操作系统上进行虚拟化&#xff0c;用于隔离…

51单片机教程(六)- LED流水灯

1 项目分析 基于点亮LED灯、LED灯闪烁&#xff0c;扩展到构成最简单、花样流水灯。 2 技术准备 1 流水灯硬件及原理图 流水灯是由多个LED灯组成的 2 C语言知识点 数组 数组声明&#xff1a;长度不可变 数据类型 数组名称[长度n] // 整数型默认为0&#xff0c;小数型默认…

供热的一些基础技术数据

1、应该了解的几个实用数据:(1)室内采暖达标温度182℃(2)建筑面积采暖热负荷 4060kcal/h㎡(4570W/㎡)(3)建筑面积采暖所需合理流量 2.53.5kg/h㎡(节能建筑12 kg/h㎡)(4)一次网严寒期外网总供、回水温度5570℃(5)热网的补水量应小于热网循环量的1%(6)1蒸吨的热量可供11.5 万平方…

【1个月速成Java】基于Android平台开发个人记账app学习日记——第7天,申请阿里云SMS短信服务SDK

系列专栏链接如下&#xff0c;方便跟进&#xff1a; https://blog.csdn.net/weixin_62588253/category_12821860.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12821860&sharereferPC&sharesourceweixin_62588253&sharefromfrom_link 同时篇幅…

A02、JVM性能监测调优

1、JVM内存模型 1.1、介绍 JVM 自动内存分配管理机制的好处很多&#xff0c;但实则是把双刃剑。这个机制在提升 Java 开发效率的同时&#xff0c;也容易使 Java 开发人员过度依赖于自动化&#xff0c;弱化对内存的管理能力&#xff0c;这样系统就很容易发生 JVM 的堆内存异常&…

钉钉调试微应用整理2

第一步 新建应用 钉钉开放平台](https://open-dev.dingtalk.com/) 去新增应用 第二步 配置应用信息 把本地代码运行起来&#xff0c;并设置本地地址 第三步 在本地代码添加调试命令 这里有2中添加方式 哪一种都可以 方式一&#xff1a; index.html页面中 <!DOCTYPE h…

《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列

《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列 《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列分配给套接字的IP地址和端口号网络地址网络地址分类和主机地址边界用于区分套接字的端口号数据传输过程示例 地址信息的表示表示IPv4…

飞牛fnOs内网穿透-使用Lucky实现ipv6动态解析+HTTPS访问NAS服务

&#x1f9ed;Lucky官方介绍 Lucky最初是作为一个小工具&#xff0c;由开发者为自己的个人使用而开发&#xff0c;用于替代socat&#xff0c;在小米路由AX6000官方系统上实现公网IPv6转内网IPv4的功能。Lucky的设计始终致力于让更多的Linux嵌入式设备运行&#xff0c;以实现或…