DPDK实现TCP/IP协议(一)----组包

一、协议结构

以太网协议
在DPDK中,采用struct rte_ether_hdr定义以太网协议头
以下是DPDK中以太网头的结构体

struct rte_ether_hdr {
	struct rte_ether_addr dst_addr; //目的地址
	struct rte_ether_addr src_addr; //源地址
	rte_be16_t ether_type; //协议类型
} __rte_aligned(2);

IP协议头
DPDK中IP协议头的结构体

**
 * IPv4 Header
 */
struct rte_ipv4_hdr {
	__extension__
	union {
		uint8_t version_ihl;  //协议长度
		struct {
#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
			uint8_t ihl:4;    //头长度
			uint8_t version:4; //协议版本
#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
			uint8_t version:4; //版本
			uint8_t ihl:4;     //头长度
#endif
		};
	};
	uint8_t  type_of_service;	//服务类型
	rte_be16_t total_length;	//包长度
	rte_be16_t packet_id;		//包id
	rte_be16_t fragment_offset;	//
	uint8_t  time_to_live;		/**< time to live */
	uint8_t  next_proto_id;		//协议IP
	rte_be16_t hdr_checksum;	//校验头
	rte_be32_t src_addr;		//源地址
	rte_be32_t dst_addr;		//目的地址
} __rte_packed;

TCP/IP协议头
DPDK中IP协议头的结构体

struct rte_tcp_hdr {
	rte_be16_t src_port; //tcp源端口
	rte_be16_t dst_port; //tcp目的端口
	rte_be32_t sent_seq; //发送数据队列
	rte_be32_t recv_ack; //接收数据队列
	uint8_t  data_off;   //数据偏移指示了TCP段中数据的起始位置
	uint8_t  tcp_flags;  //tcp标志
	rte_be16_t rx_win;   //流量控制窗口,用于流量控制和拥塞控制
	rte_be16_t cksum;    //tcp校验码
	rte_be16_t tcp_urp;  //Urgent Pointer(紧急指针)是用于标识紧急数据的位置
} __rte_packed;

二、封装TCP协议的步骤

  1. 生成要传输的数据Data
  2. 在传输层为要传输的数据Data添加TCP头部信息,形成TCP段
  3. 计算TCP段校验和,用于确保数据在传输过程中未被损害
  4. 讲TCP段传输给网络层,在网络层添加IP头部,形成IP数据报
  5. 传输数据

三、组包代码示例

#include <rte_ethdev.h>
static void build_tcpPackget(struct rte_mempool *mbuf_pool, uint16_t port)
{
    struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
    if (mbuf == NULL) {
        printf("Failed to allocate mbuf\n");
        return;
    }
    struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
    //
    eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
    struct rte_ipv4_hdr *ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
    ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
    ip_hdr->type_of_service = 0;
    ip_hdr->total_length = rte_cpu_to_be_16(sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_tcp_hdr));
    ip_hdr->packet_id = rte_cpu_to_be_16(1);
    ip_hdr->fragment_offset = 0;
    ip_hdr->time_to_live = 64;
    ip_hdr->next_proto_id = IPPROTO_TCP; 
    ip_hdr->hdr_checksum = 0;
    ip_hdr->src_addr = rte_cpu_to_be_32(RTE_IPV4(192, 168, 0, 1)); 
    ip_hdr->dst_addr = rte_cpu_to_be_32(RTE_IPV4(192, 168, 0, 2)); 

    ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr);

    struct rte_tcp_hdr *tcp_hdr = (struct rte_tcp_hdr *)(ip_hdr + 1);

    tcp_hdr->src_port = rte_cpu_to_be_16(1234);  
    tcp_hdr->dst_port = rte_cpu_to_be_16(5678);  
    tcp_hdr->sent_seq = rte_cpu_to_be_32(0);     
    tcp_hdr->recv_ack = rte_cpu_to_be_32(0);     
    tcp_hdr->data_off = (sizeof(struct rte_tcp_hdr) / 4) << 4;  
    tcp_hdr->tcp_flags = RTE_TCP_SYN_FLAG;      
    tcp_hdr->rx_win = rte_cpu_to_be_16(8192);   
    tcp_hdr->cksum = 0;                          
    tcp_hdr->tcp_urp = 0;                        

    char *payload = (char *)(tcp_hdr + 1);
    strcpy(payload, "Hello, DPDK!");

    // Calculate TCP checksum
    tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ip_hdr, tcp_hdr);

    // Set the packet length
    mbuf->data_len = 14 + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_tcp_hdr) + strlen(payload);
    mbuf->pkt_len = mbuf->data_len;

}

四、头部协议结构

IPv4数据包的标准头部结构如下(20字节):

0                   1                   2                   3  
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|Version|  IHL  |Type of Service|        Total Length           |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|        Identification         |Flags|      Fragment Offset    |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|  Time to Live |    Protocol   |         Header Checksum       |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|                       Source Address                          |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|                    Destination Address                        |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
|                    Options                    |    Padding    |  
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

字段说明

  • Version(4位):IP协议版本号,IPv4中为4。
  • IHL(4位):IP头部长度,表示IP头部的32位字的数量(最小值为5)。
  • Type of Service(8位):服务类型,用于指定分组的优先级。
  • Total Length(16位):整个IP数据包的长度(头部和数据
  • Identification(16位):用于标识数据包的唯一值。
  • Flags(3位):标志位,控制分片。
  • Fragment Offset(13位):用于标识分片数据在原始数据中的位置
  • Time to Live(8位):数据包的生存时间,防止数据包在网络中无限循环。
  • Protocol(8位):表示使用的传输协议,如TCP(6)或UDP(17)
  • Header Checksum(16位):头部校验和,用于校验头部数据的完整性。
  • Source Address(32位):源IP地址。
  • Destination Address(32位):目的IP地址。
  • Options(可变长度):可选项,灵活的附加信息。
  • Padding:为了对齐选项字段而填充的字节。
    TCP头部结构
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          源端口(16)          |       目的端口(16)          
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        序列号(32)                           
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        确认号(32)                           
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据  ||U|A|P|R|S|F|                               
| 偏移  ||R|C|S|S|Y|I|           窗口大小(16)      
| 4|  3|G|K|H|T|N|N|                               
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           校验和(16)         |         紧急指针(16)        
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    选项                       |   填充         
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             应用数据                           
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

详细字段说明:

  • 源端口:发送方应用程序的端口号,用于识别应用进程。
  • 目的端口:接收方应用程序的端口号
  • 序列号:表示本报文段数据的第一个字节在整个数据流中的序号。
  • 确认号:期待接收的下一个字节的序列号,即对上一个报文段的确认。
  • 数据偏移:TCP头部的长度(以32位字为单位),用于确定数据部分的起始位置。
  • 保留位:保留为将来使用,应置为0。
  • Flags(标志位,9位):
    • URG(紧急位):紧急指针有效。
    • ACK(确认位):确认号有效。
    • PSH(推送位):要求接收方立即将数据推送给应用层。
    • RST(复位位):重置连接。
    • SYN(同步|位):请求建立连接。
    • FIN(结束位):释放连接。
  • 窗口大小:接收方用于流量控制,指明可以接收的字节数。
  • 校验和:用于校验TCP段的完整性。
  • 紧急指针:指示紧急数据的结束位置,仅在URG位为1时有效。
  • 选项,可变长度:用于指定其他功能,如最大报文段大小(MSS)。
  • 填充,可变长度:为了使TCP头部长度是4字节的整数倍。

五、TCP在IP数据包的封装

>---------------数据报--------------------------------<
	                  >-------TCP报文段---------<			  					
|IP头部协议(ipv4或ipv6)|TCP头部|TCP(应用程序)数据|
------------------------------------------------------
>ipv4 20字节,不带选项
>ipv6 40字节
>tcp头部20字节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值