This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-tfe/common/src/tfe_pkt_util.cpp
luwenpeng 1fe60d2428 废除 tfe-kmod, tfe 直接与 kni 通信
* 新增 enable_kni_v3=1 配置项
	* develop_build_release 分支关闭 ASAN 检测
	* 修正根据 CMSG 恢复 TCP 链接时没有正确填写 TCP 时间戳启用选项的问题
2021-04-21 13:26:07 +08:00

245 lines
5.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <string.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <linux/tcp.h>
#include <tfe_utils.h>
#include <tfe_pkt_util.h>
// always success
void tfe_pkt_parse_ipv4_header(const void *a_packet, struct pkt_info *pktinfo)
{
pktinfo->addr_type = ADDR_TYPE_IPV4;
pktinfo->iphdr.v4 = (struct iphdr *)a_packet;
pktinfo->iphdr_len = pktinfo->iphdr.v4->ihl * 4;
pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v4->tot_len);
pktinfo->tcphdr = (struct tcphdr *)((char *)pktinfo->iphdr.v4 + pktinfo->iphdr_len);
pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
pktinfo->data = (char *)pktinfo->tcphdr + pktinfo->tcphdr_len;
pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
pktinfo->parse_failed = 0;
}
// check pktinfo->parse_failed for status
void tfe_pkt_parse_ipv6_header(const void *a_packet, struct pkt_info *pktinfo)
{
pktinfo->addr_type = ADDR_TYPE_IPV6;
pktinfo->iphdr.v6 = (struct ip6_hdr *)a_packet;
pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v6->ip6_ctlun.ip6_un1.ip6_un1_plen) + sizeof(struct ip6_hdr);
uint8_t next_hdr_type = pktinfo->iphdr.v6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
char *next_hdr_ptr = (char *)pktinfo->iphdr.v6 + sizeof(struct ip6_hdr);
int skip_len = 0;
while (1)
{
switch(next_hdr_type)
{
case IPPROTO_TCP:
//parse tcphdr
pktinfo->iphdr_len = next_hdr_ptr - (char *)a_packet;
pktinfo->tcphdr = (struct tcphdr *)next_hdr_ptr;
pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
pktinfo->data = (char *)pktinfo->tcphdr + pktinfo->tcphdr_len;
pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
pktinfo->parse_failed = 0;
return;
case IPPROTO_HOPOPTS: /* fall through */
case IPPROTO_ROUTING: /* fall through */
case IPPROTO_AH: /* fall through */
case IPPROTO_DSTOPTS: /* fall through */
skip_len = (*(next_hdr_ptr + 1)) * 8 + 8;
next_hdr_type = *next_hdr_ptr;
next_hdr_ptr += skip_len;
break;
case IPPROTO_NONE: /* fall through */
default:
pktinfo->parse_failed = 1;
return;
}
}
}
uint16_t tfe_pkt_checksum_ip(const void *buf, size_t hdr_len)
{
unsigned long sum = 0;
const uint16_t *ip1;
ip1 = (const uint16_t *)buf;
while (hdr_len > 1)
{
sum += *ip1++;
if (sum & 0x80000000)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
hdr_len -= 2;
}
while (sum >> 16)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (~sum);
}
uint16_t tfe_pkt_checksum_tcp_v4(const void *_buf, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
{
const uint16_t *buf = (u_int16_t *)_buf;
uint16_t *ip_src = (uint16_t *)&src_addr;
uint16_t *ip_dst = (uint16_t *)&dest_addr;
uint32_t sum;
size_t length = len;
// Calculate the sum
sum = 0;
while (len > 1)
{
sum += *buf++;
if (sum & 0x80000000)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
len -= 2;
}
if (len & 1)
{
// Add the padding if the packet lenght is odd
sum += *((uint8_t *)buf);
}
// Add the pseudo-header
sum += *(ip_src++);
sum += *ip_src;
sum += *(ip_dst++);
sum += *ip_dst;
sum += htons(IPPROTO_TCP);
sum += htons(length);
// Add the carries
while (sum >> 16)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Return the one's complement of sum
return ((uint16_t)(~sum));
}
uint16_t tfe_pkt_checksum_tcp_v6(const void *_buf, size_t len, struct in6_addr src_addr, struct in6_addr dest_addr)
{
const uint16_t *buf = (u_int16_t *)_buf;
uint16_t *ip_src = (uint16_t *)&src_addr;
uint16_t *ip_dst = (uint16_t *)&dest_addr;
uint32_t sum;
size_t length = len;
int i = 0;
// Calculate the sum
sum = 0;
while (len > 1)
{
sum += *buf++;
if (sum & 0x80000000)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
len -= 2;
}
if (len & 1)
{
// Add the padding if the packet lenght is odd
sum += *((uint8_t *)buf);
}
// Add the pseudo-header
for (i = 0; i < 8; i++)
{
sum += *ip_src;
ip_src++;
}
for ( i = 0; i < 8; i++)
{
sum += *ip_dst;
ip_dst++;
}
sum += htons(IPPROTO_TCP);
sum += htons(length);
// Add the carries
while (sum >> 16)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Return the one's complement of sum
return ((uint16_t)(~sum));
}
/*
* 目的:在 IP 的 Payload ${data} 中查找指定的 tcp ${option}。
*
* 已知:
* 1.所有的 tcp options 所占的存储空间的长度为 ${optlen}
* 2.${out_opt_buff} 输出缓冲区的最大长度为 ${out_opt_buff_size}
*
* 返回值:
* 1.若找到指定的 tcp ${option} 则返回 1并将该 tcp ${option} 对应的值拷贝到 ${out_opt_buff} 中,并将拷贝的值所占的存储空间记录到 ${out_optlen} 中
* 2.若未找到指定的 tcp ${option} 则返回 0
*/
int tfe_pkt_find_tcp_option(uint8_t option, char *data, unsigned int opts_total_len, uint8_t *out_opt_len, char *out_opt_buff, unsigned int out_opt_buff_size)
{
const uint8_t *op;
unsigned int i;
if (!opts_total_len)
return 0;
op = (uint8_t *)(data + sizeof(struct tcphdr));
for (i = 0; i < opts_total_len;)
{
uint8_t __optlen;
uint8_t __valuelen;
if (op[i] == option)
{
if (op[i] < 2)
{
*out_opt_len = 0;
return 1;
}
__optlen = op[i + 1];
if (__optlen <= 2)
{
TFE_LOG_ERROR(g_default_logger, "failed at parse tcp options, tcp option length must be larger than 2, but the value is %u", __optlen);
return 0;
}
__valuelen = __optlen - 2;
if (__valuelen > out_opt_buff_size)
{
TFE_LOG_ERROR(g_default_logger, "failed at parse tcp options, tcp option length is larger than input buffer");
return 0;
}
*out_opt_len = __valuelen;
memcpy(out_opt_buff, &op[i + 2], __valuelen);
return 1;
}
if (op[i] < 2)
i++;
else
i += op[i + 1] ?: 1;
}
return 0;
}