IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> dpdk从环形队列ring获取解析数据包,并使用hashtable统计 -> 正文阅读

[C++知识库]dpdk从环形队列ring获取解析数据包,并使用hashtable统计

简介

本文是上一篇的延续继dpdk从给定的port/queue捕获流量_晓镁的博客-CSDN博客

rte_ring_dequeue_burst

result = rte_ring_dequeue_burst(arg0,arg1,arg2,arg3)
将多个对象从一个环形队列ring取出,直到达到最大数量。
该函数调用多消费者或单消费者批量出队列,取决于在创建ring时指定的默认行为。

arg0为环形队列ring指针
arg1为 指用数据包填充的void*指针数组指针,示例为void* dequeued[]数组
arg2为从环出列到 obj_table 的对象数。
arg3如果如果非NULL,则为返回出队完成后剩余的环条目数。
返回值为出队的对象数。

#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <arpa/inet.h>

#include <dpdk/rte_ring.h>
#include <dpdk/rte_lcore.h>
#include <dpdk/rte_log.h>
#include <dpdk/rte_mbuf.h>
#include <dpdk/rte_branch_prediction.h>
#include <dpdk/rte_tcp.h>
#include <dpdk/rte_ethdev.h>
#include <dpdk/rte_ether.h>
#include <dpdk/rte_ethdev.h>
#include <dpdk/rte_ip.h>
#include <dpdk/rte_eal.h>

#include "core_write.h"
#include "redis.h"
#define MIN(a,b) (((a)<(b))?(a):(b))

#define RTE_LOGTYPE_DPDKCAP RTE_LOGTYPE_USER1


#include <time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "hash.h"
#include "redis.h"

#include <dpdk/rte_lcore.h>
#include <dpdk/rte_log.h>
#include <dpdk/rte_tcp.h>
#include <dpdk/rte_ethdev.h>
#include <dpdk/rte_ether.h>
#include <dpdk/rte_ethdev.h>
#include <dpdk/rte_ip.h>
#include <dpdk/rte_eal.h>

#define RTE_LOGTYPE_DPDKCAP RTE_LOGTYPE_USER1


/*
 * process the packets form the ring
 */
int write_core(const struct core_write_config * config) {
  unsigned int packet_length, wire_packet_length = 0;
  int result;
  void* dequeued[DPDKCAP_WRITE_BURST_SIZE];
  struct rte_mbuf* bufptr;
  int retval = 0;
  //Init current time
  int i = 0;

  //Init stats
  *(config->stats) = (struct core_write_stats) {
    .core_id=rte_lcore_id(),
      .packets = 0,
      .bytes = 0,
      .compressed_bytes = 0,
  };


  RTE_LOG(INFO, DPDKCAP, "Core %d is process packet.\n",
      rte_lcore_id());

  for (;;) {
    if (unlikely(*(config->stop_condition))) {
      break;
    }

    //从环形队列ring获取packets
    result = rte_ring_dequeue_burst(config->ring,
        dequeued, DPDKCAP_WRITE_BURST_SIZE);
    if (result == 0) {
      continue;
    }

    //从环形ring取到数据计数
    config->stats->packets += result;

    for (i = 0; i < result; i++) {
      // 逐一处理数据包
      bufptr = dequeued[i];
  
      // 基于hashtable对数据包进行分析统计
      addPacket(config->table,bufptr);
  
      // 数据流量统计
      packet_length = wire_packet_length;
      config->stats->bytes += packet_length;

      // Free buffer
      rte_pktmbuf_free(bufptr);
    }
  }
  RTE_LOG(INFO, DPDKCAP, "count core %d\n", rte_lcore_id());
  return retval;
}

数据包分析hash表统计

addPacket()函数pkt为数据包结构体。

数据包分析时首先从以太头、ip报文、tcp/udp/icmp逐层offset偏移进行解包分析。
通过原目的ip计算哈希key值,value为struct info结构体,该结构体记录数据包分析结果。


如果哈希冲突怎么办?

如果哈希冲突,那么基于原有的哈希节点创建链表,把原有哈希节点的next指针指向冲突的节点。
这是典型的哈希冲突处理方式。

/* 计算hashtable下标 */
int getIndex(uint32_t src,uint32_t dst){
        uint32_t index = src+dst;
        return ((index>>16) + (index&65535))&65535;
}

/* 增加一个数据包 */
int addPacket(struct info **table,struct rte_mbuf *pkt){
	struct ipv4_hdr *ip;
	struct ether_hdr *eth_hdr = rte_pktmbuf_mtod_offset(pkt, struct ether_hdr *,0);
	ip = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,sizeof(struct ether_hdr));
	/* 处理IPv4数据包 */
	if (eth_hdr->ether_type == 0x0008) {
		int index = getIndex(ip->src_addr,ip->dst_addr);
		struct info *p;
		/* 查找hash table中该数据包对应的节点 */
		if(table[index]==NULL){
			p = (struct info *)malloc(sizeof(struct info));
			p->src = ip->src_addr;
			p->dst = ip->dst_addr;
                        p->icmp = 0;
                        p->tcp = 0;
                        p->http = 0;
                        p->udp = 0;
                        p->syn = 0;
                        p->ack = 0;
                        p->count = 0;
                        p->other = 0;
			p->next = NULL;
			p->time = time(0);
			table[index] = p;
		}else{
			p = table[index];
			while(p->next != NULL){
				if(p->src == ip->src_addr && p->dst == ip->dst_addr){
					break;
				}
				p = p->next;
			}
			/* p是尾节点并且和当前数据包信息不匹配 */
			if(p->next != NULL){
				if(p->src != ip->src_addr || p->dst != ip->dst_addr){
					p->next =  (struct info *)malloc(sizeof(struct info));
					p = p->next;
					p->src = ip->src_addr;
					p->dst = ip->dst_addr;
					p->icmp = 0;
					p->tcp = 0;
					p->http = 0;
					p->udp = 0;
					p->syn = 0;
					p->ack = 0;
					p->count = 0;
					p->other = 0;
					p->time = time(0);
					p->next = NULL;
				}
			}
		}
		p->count += pkt->data_len;
		/* 处理tcp数据包 */
		if(ip->next_proto_id ==6){
			p->tcp++;
		struct tcp_hdr *tcp = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
						   sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr));
		if(ntohs(tcp->src_port) == 80 || ntohs(tcp->src_port) == 443 || ntohs(tcp->src_port) == 8080 || ntohs(tcp->dst_port)==443 || ntohs(tcp->dst_port)==80 || ntohs(tcp->dst_port)==8080){
			p->http++;
		}
			if(tcp->tcp_flags & 2){
				p->syn++;
			}else if(tcp->tcp_flags & 16){
				p->ack++;
			}
		/* 处理udp数据包 */
		}else if(ip->next_proto_id ==17){
			p->udp++;
		/* 处理icmp数据包 */
		}else if(ip->next_proto_id ==1){
			p->icmp++;
		/* 其它协议的包 */
		}else{
			p->other++;
		}
	} else if (RTE_ETH_IS_IPV6_HDR(pkt->packet_type)) {
		/* Fill acl structure */

	} else {
		/* Unknown type, drop the packet */
	}
	return 0;
}

void initTable(struct info **table){
	int i;
	for(i=0;i<HASH_TABLE_SIZE;i++){
		table[i]=NULL;
	}
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:17:37  更:2022-04-22 18:18:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:52:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码