dpdk中udp包的接受与发送

news2024/12/18 5:28:47

预备知识

dpdk中一些关键宏定义与结构体定义

以太网帧相关

宏RTE_ETHER_ADDR_LEN mac地址长度,6字节48位

宏RTE_ETHER_TYPE_IPV4 代表ipv4

struct rte_ether_hdr 以太网帧头结构体,包含了三个成员变量,目的地址,源地址,IP类型。

ip相关

struct rte_ipv4_hdr ipv4头结构体, 包含版本,ttl,next_proto_id,源地址,目标地址等字段

rte_ipv4_cksum()计算校验和的函数

tcp/udp相关

宏IPPROTO_UDP 代表udp协议

IPPROTO_TCP 代表udp协议

struct rte_udp_hdr udp头结构体,包含源端口,目的端口,数据长度以及校验和

rte_ipv4_udptcp_cksum(ip头地址,udp头地址)计算校验和的函数

udp头

struct rte_udp_hdr {
    rte_be16_t src_port;   /**< 源端口 (16位,大端格式) */
    rte_be16_t dst_port;   /**< 目标端口 (16位,大端格式) */
    rte_be16_t dgram_len;  /**< UDP数据报总长度 (16位,大端格式,包括头部) */
    rte_be16_t dgram_cksum;/**< 校验和 (16位,大端格式) */
};

tcp头

struct rte_ipv4_hdr {
    uint8_t  version_ihl;        /**< 版本号 (4 bit) + 头部长度 (4 bit) */
    uint8_t  type_of_service;    /**< 服务类型 */
    rte_be16_t total_length;     /**< 整个 IPv4 数据包的总长度 (以字节为单位) */
    rte_be16_t packet_id;        /**< 包标识符 */
    rte_be16_t fragment_offset;  /**< 分片偏移量和标志位 */
    uint8_t  time_to_live;       /**< 生存时间 (TTL) */
    uint8_t  next_proto_id;      /**< 上层协议 (如 TCP=6, UDP=17) */
    rte_be16_t hdr_checksum;     /**< IPv4 头部的校验和 */
    rte_be32_t src_addr;         /**< 源 IP 地址 */
    rte_be32_t dst_addr;         /**< 目标 IP 地址 */
} 

内存池中 mbuf结构体的定义

struct rte_mbuf {
    void *buf_addr;               /* 缓冲区的起始地址 */
    uint16_t buf_len;             /* 缓冲区的总长度 */
    uint16_t data_off;            /* 数据在缓冲区中的偏移量 */
    
    uint64_t ol_flags;            /* Offload 标志,例如 checksum 校验等 */
    uint16_t pkt_len;             /* 数据包的总长度 */
    uint16_t data_len;            /* 数据包中有效数据的长度 */

    uint32_t pkt_type;            /* 数据包类型(如 IPv4, TCP, UDP 等) */
    uint64_t timestamp;           /* 时间戳 */

    struct rte_mempool *pool;     /* 指向内存池的指针 */
    struct rte_mbuf *next;        /* 链接到下一个 mbuf(用于分段数据包) */

    uint16_t refcnt;              /* 引用计数器(用于共享 mbuf) */
    uint8_t port;                 /* 接收端口编号 */
    uint8_t nb_segs;              /* 数据包的段数量(如多段数据包) */
};

内存池中的mbuf并不会直接存储数据包的信息,而是存储数据包的地址,大小等信息。可以通过buf_addr + data_off的方式,计算出实际数据的地址,读取数据信息。所以dpdk提供了相应的宏来进行实际数据地址的计算

rte_pktmbuf_mtod(mbuf, int*),把mbuf对应的缓冲区的地址转换为int*类型。

udp数据编码

其实就是如何封装一个以太网帧,把内容存放到mbuf中,通过dpdk发送到网卡的发送队列里。

static int ustack_encode_udp_pkt(uint8_t *msg, uint8_t *data, uint16_t total_len){
    //ether header
    struct rte_ether_hdr *eth = (struct rte_ether_hdr*) msg;
    rte_memcpy(eth->d_addr.addr_bytes, global_dmac, RTE_ETHER_ADDR_LEN);
    rte_memcpy(eth->s_addr.addr_bytes, global_smac, RTE_ETHER_ADDR_LEN);
    eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);

    //ip header
    struct rte_ipv4_hdr *iphdr = (struct rte_ipv4_hdr *) (eth + 1); //msg + sizeof(eht)
    iphdr->version_ihl = 0x45;
    iphdr->type_of_service = 0;
    iphdr->total_length = htons(total_len - sizeof(struct rte_ether_hdr));
    iphdr->packet_id = 0;
    iphdr->fragment_offset = 0;
    iphdr->time_to_live = 64;
    iphdr->next_proto_id = IPPROTO_UDP;
    iphdr->src_addr = global_sip;
    iphdr->dst_addr = global_dip;

    iphdr->hdr_checksum = 0;
    iphdr->hdr_checksum = rte_ipv4_cksum(iphdr);

    //udp header
    struct rte_udp_hdr * udphdr = (struct rte_udp_hdr *)(iphdr + 1);
    udphdr->src_port = global_sport;
    udphdr->dst_port = global_dport;
    uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);
    udphdr->dgram_len = htons(udplen);

    //填充数据
    rte_memcpy((uint8_t *)(udphdr + 1), data, udplen);
    udphdr->dgram_cksum = 0;
    udphdr->dgram_cksum = rte_ipv4_udptcp_cksum(iphdr, udphdr);

    return 0;
}

tcp数据的解码与编码

tcp数据的解码:从mbuf中获取实际信息的地址,再对信息进行解析。

与udp类似,都包含以太网头、ip头、tcp头等

static int ustack_decode_tcp_pkt(uint8_t *msg, uint16_t total_len){
    //ether header
    struct rte_ether_hdr *eth = (struct rte_ether_hdr*) msg;
    rte_memcpy(eth->d_addr.addr_bytes, global_dmac, RTE_ETHER_ADDR_LEN);
    rte_memcpy(eth->s_addr.addr_bytes, global_smac, RTE_ETHER_ADDR_LEN);
    eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);

    //ip header
    struct rte_ipv4_hdr *iphdr = (struct rte_ipv4_hdr *) (eth + 1); //msg + sizeof(eht)
    iphdr->version_ihl = 0x45;
    iphdr->type_of_service = 0;
    iphdr->total_length = htons(total_len - sizeof(struct rte_ether_hdr));
    iphdr->packet_id = 0;
    iphdr->fragment_offset = 0;
    iphdr->time_to_live = 64;
    iphdr->next_proto_id = IPPROTO_TCP;
    iphdr->src_addr = global_sip;
    iphdr->dst_addr = global_dip;

    iphdr->hdr_checksum = 0;
    iphdr->hdr_checksum = rte_ipv4_cksum(iphdr);

    //tcp header
    struct rte_tcp_hdr * tcphdr = (struct rte_tcp_hdr *)(iphdr + 1);
    tcphdr->src_port = global_sport;
    tcphdr->dst_port = global_dport;
    tcphdr->sent_seq = htonl(12345);
    tcphdr->recv_ack = 0x0;
    tcphdr->data_off = 0x50;
    tcphdr->tcp_flags = 0x1 << 1;
    tcphdr->rx_win = htons(4096);
    tcphdr->cksum = 0;
    tcphdr->cksum = rte_ipv4_udptcp_cksum(iphdr, tcphdr);
    

    return 0;
}

在主函数中调用该函数,进行解析

if(iphdr->next_proto_id == IPPROTO_TCP){
    struct rte_tcp_hdr *tcphdr = (struct rte_tcp_hdr *)(iphdr + 1);

    struct in_addr addr;
    addr.s_addr = iphdr->src_addr;
    printf("tcp\n src: %s:%d ----> ", inet_ntoa(addr), ntohs(tcphdr->src_port));

    addr.s_addr = iphdr->dst_addr;
    printf("des: %s:%d\n", inet_ntoa(addr), ntohs(tcphdr->dst_port));

    rte_memcpy(global_smac, ethhdr->d_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
    rte_memcpy(global_dmac, ethhdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);

    rte_memcpy(&global_sip, &iphdr->dst_addr, sizeof(uint32_t));
    rte_memcpy(&global_dip, &iphdr->src_addr, sizeof(uint32_t));

    rte_memcpy(&global_sport, &tcphdr->dst_port, sizeof(uint32_t));
    rte_memcpy(&global_dport, &tcphdr->src_port, sizeof(uint32_t));
    
    uint16_t total_len = sizeof(struct rte_tcp_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_ether_hdr);

    struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
    mbuf->pkt_len = total_len;
    mbuf->data_len = total_len;

    uint8_t *msg = rte_pktmbuf_mtod(mbuf, uint8_t *);
    ustack_decode_tcp_pkt(msg, total_len);
    rte_eth_tx_burst(global_portid, 0, &mbuf, 1);
} 

 项目地址:www.github.com/0voice

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

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

相关文章

C语言进阶(2) ---- 指针的进阶

前言&#xff1a;指针的主题&#xff0c;我们在初阶的《指针》章节已经接触过了&#xff0c;我们知道了指针的概念&#xff1a; 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2.指针的大小是固定的4/8个字节(32位平台/64位平台)。 3.指针是…

项目整体结构优化

文章目录 1.依赖配置方式1.作为专门管理依赖的模块2.作为父模块3.作为子模块4.注意事项1.关于relativePath的配置2.关于打包的配置3.遇到maven报错的解决方案1.首先刷新maven2.从子模块开始clean-install3.最终:在最顶级的模块clean-package 2.概览3.新建一个子模块sun-depende…

计算机视觉-边缘检测

图片分类 一张图片中可能有多个需要识别的物体&#xff0c;会用方框标注他们的位置和类别 例&#xff1a; 给出一张照片&#xff0c;计算机需要从中识别出这是一只猫 一张图片的计算量是较大的&#xff0c;这张图片的尺寸虽然是6464&#xff0c;因为每张图片有3个颜色通道&am…

多模块应用、发布使用第三方库(持续更新中)

目录: 1、多模块概述&#xff08;HAP、HSP、HAR&#xff09; HAR与HSP两种共享包的主要区别体现在&#xff1a; 2、三类模块&#xff1a; 3、创建项目&#xff1a;项目名&#xff1a;meituan &#xff08;1&#xff09;创建Ability类型的Module&#xff0c;编译后为HAP文件…

安卓 文件管理相关功能记录

文件管理细分为图片、视频、音乐、文件四类 目录 权限 静态声明权限 动态检查和声明权限方法 如何开始上述动态申请的流程 提示 图片 获取图片文件的对象列表 展示 删除 视频 获取视频文件的对象列表 获取视频file列表 按日期装载视频文件列表 展示 播放 删除…

CHIMA网络安全攻防大赛经验分享

比赛模式 第一轮&#xff1a;20分钟基础知识赛&#xff08;50道题&#xff09; 安全运维&#xff0c;法律法规&#xff0c;linux操作系统等 第二轮&#xff1a;50分钟CTF夺旗&#xff08;5道题&#xff09; 题目涵盖 密码学 运用多种工具&#xff0c;如ASCII对照&#xff0c…

QT 国际化(翻译)

QT国际化&#xff08;Internationalization&#xff0c;简称I18N&#xff09;是指将一个软件应用程序的界面、文本、日期、数字等元素转化为不同的语言和文化习惯的过程。这使得软件能够在不同的国家和地区使用&#xff0c;并且可以根据用户的语言和地区提供本地化的使用体验。…

[Java] 使用 VSCode 来开发 Java

目录 前言Java 环境怎么看自己是否已经配置完成&#xff1f;安装 JDK安装 Maven 环境修改 Maven 依赖源 完善 VS Code配置插件配置 Maven配置 Maven Settings配置 Maven 可执行文件地址 前言 由于使用 VSCode 编码已经成为习惯&#xff0c;并且它确实相对其他的 IDE 较为轻量化…

如何高效获取Twitter数据:Apify平台上的推特数据采集解决方案

引言 在数据分析和市场研究领域&#xff0c;Twitter&#xff08;现在的X&#xff09;数据一直是重要的信息来源。但是&#xff0c;自从Twitter更改API定价策略后&#xff0c;获取数据的成本大幅提升。本文将介绍一个经济实惠的替代方案。 为什么需要Twitter数据&#xff1f; …

vue3+ant design vue实现日期选择器不展示清除按钮

1、代码&#xff1a;只需设置:allowClear"false"即可 <a-date-pickerv-model:value"value1":disabledDate"disabledDate"change"queryRate":allowClear"false" />const disabledDate (current: Dayjs) > {// 获取…

S2CRNet 图像测评笔记 图像融合

空间分离曲线渲染网络用于高效高分辨率图像协调 开源地址&#xff1a; https://github.com/stefanLeong/S2CRNet 效果图&#xff1a; 左边是输入&#xff0c;最右边是效果&#xff1a;效果不是很理想&#xff0c;色差问题还在 本地代码&#xff1a; S2CRNet-demos-main

【计算机网络】Layer4-Transport layer

目录 传输层协议How demultiplexing works in transport layer&#xff08;传输层如何进行分用&#xff09;分用&#xff08;Demultiplexing&#xff09;的定义&#xff1a;TCP/UDP段格式&#xff1a; UDPUDP的特点&#xff1a;UDP Format端口号Trivial File Transfer Protocol…

【Excel】单元格分列

目录 分列&#xff08;新手友好&#xff09; 1. 选中需要分列的单元格后&#xff0c;选择 【数据】选项卡下的【分列】功能。 2. 按照分列向导提示选择适合的分列方式。 3. 分好就是这个样子 智能分列&#xff08;进阶&#xff09; 高级分列 Tips&#xff1a; 新手推荐基…

易语言鼠标轨迹算法(游戏防检测算法)

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

.net winform 实现CSS3.0 泼墨画效果

效果图 代码 private unsafe void BlendImages1(Bitmap img1, Bitmap img2) {// 确定两个图像的重叠区域Rectangle rect new Rectangle(0, 0,Math.Min(img1.Width, img2.Width),Math.Min(img1.Height, img2.Height));// 创建输出图像&#xff0c;尺寸为重叠区域大小Bitmap b…

Https身份鉴权(小迪网络安全笔记~

附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;若有错误欢迎指正&#xff01; 5.2 Https&身份鉴权 引子&#xff1a;上一篇主要对Http数据包结构、内容做了介绍&#xff0c;本篇则聊聊Https、身份鉴权等技术。 …

7.OPEN SQL

总学习目录请点击下面连接 SAP ABAP开发从0到入职&#xff0c;冷冬备战-CSDN博客 目录 ​编辑 1.OPEN-SQL 简单回顾 R3体系 OEPN-SQL 2.OPEN-SQL 读取数据 2.1Select 语句 select 1条数据 多条数据与into AS别名 2.2INTO 结构体 内表 例子 2.3FROM 选择动态表…

PLC网关,plc远程通信 —— 跨越距离远程控制运维升级

在日新月异的工业4.0时代&#xff0c;智能化、网络化已成为制造业转型升级的关键词。其中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;作为工业自动化控制的核心设备&#xff0c;其远程通信技术的突破&#xff0c;正引领着一场前所未有的工业变革。今天&#xff0…

Python-基于Pygame的小游戏(天空之战)(一)

前言:不久前接触了Python的游戏制作的相关第三方库&#xff0c;于是学习了pygame的相关内容&#xff0c;想制作一款基于pygame的小游戏。因为还不太熟悉游戏制作和pygame&#xff0c;部分内容我参考了《Python-从入门到精通》这本书。那么好&#xff0c;话不多说&#xff0c;我…

CV(4)--边缘提取和相机模型

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 边缘提取&#xff08;涉及语义分割&#xff09;&#xff1a; 图象的边缘是指图象局部区域亮度变化显著的部分,也有正负之分&#xff0c;暗到亮为正 求边缘的幅度&#xff1a;sobel&#xff0c;Canny算子 图像分高频分量和低…