用户态协议栈04-定时arp-table的实现

之前有写过arp reply的实现,其中有写道,我们的系统内核中会维护一张ARP表,可以通过终端arp -a查看:

其中的dynamicstatic是动态arp的类型,之前的udp实验就是添加了一条静态arp达到了发送的目的。在我们需要发送一个数据包的时候。指定好ip,内核会在arp表中寻找对应的ip,然后向他发送。在用户太协议栈中,DPDK同样需要维护一张arp表,实现类似的功能。

链表实现的ARP表


#ifndef LN_ARP_TABLE
#define LN_ARP_TABLE

#include <rte_malloc.h>
#include <stdio.h>

#define ARP_ENTRY_STATUS_DYNAMIC 0
#define ARP_ENTRY_STATUS_STATIC 1

struct arp_entry {
	uint32_t ip;
	uint8_t hwaddr[RTE_ETHER_ADDR_LEN];
	int type;

	struct arp_entry* next;
	struct arp_entry* prev;
};

struct arp_table {
	struct arp_entry* entries;
	int count;
}

#define LL_ADD(item, list) do {		\
	item->next = NULL;		\
	item->prev = NULL;		\
	if(list != NULL) list->prev = NULL;		\
	list = item;	\
}while(0)

#define LL_REMOVE(item, list) do {		\
	if(item->prev != NULL) item->prev->next = item->next;	\
	if(item->next != NULL) item->next->prev = item->prev;	\
	if(item == list) list = list->next;		\
	item->prev = item->next = NULL;		\
}while(0)

static struct arp_table arpt = NULL;

static struct arp_table* arp_table_instance() {

	if(arpt == NULL) {
		
		arpt = rte_malloc("arp table", sizeof(struct arp_table), 0);

		if(arpt == NULL) {

			rte_exit(EXIT_FAILURE, "Error with arp table malloc\n");
		}

		memset(arpt, 0, sizeof(struct arp_table));
	}

	return arpt;
}

static uint8_t* arp_get_dst_macaddr(uint32_t dip) {

	struct arp_entry* ite;
	struct arp_table* table = arp_table_instance();

	for(ite = table->entries; ite != NULL; ite = ite->next) {

		if(dip == ite->ip) {

			return ite->hwaddr;
		}
	}

	return NULL;
}

#endif

这里采用的是一个单例模式,线程安全等后面再迭代。这里实现的是一个头单项链表,只能头插。arp表一般来说不会太大,所以使用链表就可以了。或者说其实再大胆一点,数组也是可以的。代码中有LL_ADDLL_REMOVE两个宏来进行链表的增加和删除节点。具体如何使用,需要看我们再主函数中的使用过程。

定时器

  • 为什么需要定时器?

    arp协议是一种广播协议,我们需要定时向局域网发起广播,公布自己的arp同时获取别人的arp来更新arp表。

这里是使用的DPDK提供出来的一个定时器组件,我直接抽离出来记录,避免代码繁多看起来眼花缭乱。

#define TIMER_RESOLUTION_CYCLES 120000000000ULL // 10ms * 1000 = 10s * 6 

首先是有一个宏,这个有点像单片机里的知识。根据始终的频率,再一秒钟之内的滴答次数不一样,这里是记录一个抵达次数如果到达这个次数就广播arp。那这个次数是如何计算出来的呢?其实是再例程里面有的:

这里说20000000ULL是对应的10ms的时间间隔,所以可以算出,我们这里的宏是一分钟,广播一次。

rte_timer_subsystem_init();

struct rte_timer arp_timer;
rte_timer_init(&arp_timer);

uint64_t hz = rte_get_timer_hz();
unsigned lcore_id = rte_lcore_id();
rte_timer_reset(&arp_timer, hz, PERIODICAL, lcore_id, arp_request_timer_cb, mbuf_pool);
  • rte_timer_subsystem_init()函数会初始化相关的数据结构和配置,以便后续使用计时器功能
  • rte_get_timer_hz取得系统计时器的频率
  • rte_lcore_id返回执行当前代码的逻辑核心ID
  • arp_request_timer_cb是自己写的定时器执行的回调函数,执行业务逻辑
static uint64_t prev_tsc = 0, cur_tsc;
uint64_t diff_tsc;

cur_tsc = rte_rdtsc();
diff_tsc = cur_tsc - prev_tsc;
if (diff_tsc > TIMER_RESOLUTION_CYCLES) {
    rte_timer_manage();
    prev_tsc = cur_tsc;
}
  • rte_timer_manage会检查所有注册的定时器,对超时任务进行处理。

具体实现

arp打包

static int ng_encode_arp_pkt(uint8_t *msg, uint16_t opcode, uint8_t *dst_mac, uint32_t sip, uint32_t dip) {

	// 1 ethhdr
	struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
	rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	if (!strncmp((const char *)dst_mac, (const char *)gDefaultArpMac, RTE_ETHER_ADDR_LEN)) {
		uint8_t mac[RTE_ETHER_ADDR_LEN] = {0x0};
		rte_memcpy(eth->d_addr.addr_bytes, mac, RTE_ETHER_ADDR_LEN);
	} else {
		rte_memcpy(eth->d_addr.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);
	}
	eth->ether_type = htons(RTE_ETHER_TYPE_ARP);

	// 2 arp 
	struct rte_arp_hdr *arp = (struct rte_arp_hdr *)(eth + 1);
	arp->arp_hardware = htons(1);
	arp->arp_protocol = htons(RTE_ETHER_TYPE_IPV4);
	arp->arp_hlen = RTE_ETHER_ADDR_LEN;
	arp->arp_plen = sizeof(uint32_t);
	arp->arp_opcode = htons(opcode);

	rte_memcpy(arp->arp_data.arp_sha.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	rte_memcpy( arp->arp_data.arp_tha.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);

	arp->arp_data.arp_sip = sip;
	arp->arp_data.arp_tip = dip;
	
	return 0;

}

static struct rte_mbuf *ng_send_arp(struct rte_mempool *mbuf_pool, uint16_t opcode, uint8_t *dst_mac, uint32_t sip, uint32_t dip) {

	const unsigned total_length = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);

	struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
	if (!mbuf) {
		rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");
	}

	mbuf->pkt_len = total_length;
	mbuf->data_len = total_length;

	uint8_t *pkt_data = rte_pktmbuf_mtod(mbuf, uint8_t *);
	ng_encode_arp_pkt(pkt_data, opcode, dst_mac, sip, dip);

	return mbuf;
}

这里的两个函数相较于之前的添加了一个opcode参数,因为之前的是默认reply的,这里需要区别是reply还是request,其他没什么变化。

arp广播

static void arp_request_timer_cb(__attribute__((unused)) struct rte_timer *tim, void *arg) {

	struct rte_mempool *mbuf_pool = (struct rte_mempool *)arg;
	
	int i = 0;
	for (i = 1;i <= 254;i ++) {

		uint32_t dstip = (gLocalIp & 0x00FFFFFF) | (0xFF000000 & (i << 24));

		struct in_addr addr;
		addr.s_addr = dstip;
		printf("arp ---> src: %s \n", inet_ntoa(addr));

		struct rte_mbuf *arpbuf = NULL;
		uint8_t *dstmac = ng_get_dst_macaddr(dstip);
		if (dstmac == NULL) {

			arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REQUEST, gDefaultArpMac, gLocalIp, dstip);
		
		} else {

			arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REQUEST, dstmac, gLocalIp, dstip);
		}

		rte_eth_tx_burst(gDpdkPortId, 0, &arpbuf, 1);
		rte_pktmbuf_free(arpbuf);
		
	}
	
}

这里是对网段中的所有ip发起request请求,我感觉这里有必要梳理一下这个dip的逻辑,毕竟这个代码看着怎么像寄存器[狗头]。假设本地ip是192.168.1.111:因为网络字节序是反的,所以(gLocalIp & 0x00FFFFFF)是把其中的111设为0;(0xFF000000 & (i << 24))从1-255分别将低位置1,这样就形成了目的ip;

完整代码



#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include <rte_malloc.h>
#include <rte_timer.h>


#include <stdio.h>
#include <arpa/inet.h>

#include "arp.h"

#define ENABLE_SEND		1
#define ENABLE_ARP		1
#define ENABLE_ICMP		1
#define ENABLE_ARP_REPLY	1

#define ENABLE_DEBUG		1

#define ENABLE_TIMER		1


#define NUM_MBUFS (4096-1)

#define BURST_SIZE	32


#define TIMER_RESOLUTION_CYCLES 120000000000ULL // 10ms * 1000 = 10s * 6 


#if ENABLE_SEND

#define MAKE_IPV4_ADDR(a, b, c, d) (a + (b<<8) + (c<<16) + (d<<24))

static uint32_t gLocalIp = MAKE_IPV4_ADDR(192, 168, 1, 184);

static uint32_t gSrcIp; //
static uint32_t gDstIp;

static uint8_t gSrcMac[RTE_ETHER_ADDR_LEN];
static uint8_t gDstMac[RTE_ETHER_ADDR_LEN];

static uint16_t gSrcPort;
static uint16_t gDstPort;

#endif

#if ENABLE_ARP_REPLY

static uint8_t gDefaultArpMac[RTE_ETHER_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

#endif




int gDpdkPortId = 0;



static const struct rte_eth_conf port_conf_default = {
	.rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN }
};

static void ng_init_port(struct rte_mempool *mbuf_pool) {

	uint16_t nb_sys_ports= rte_eth_dev_count_avail(); //
	if (nb_sys_ports == 0) {
		rte_exit(EXIT_FAILURE, "No Supported eth found\n");
	}

	struct rte_eth_dev_info dev_info;
	rte_eth_dev_info_get(gDpdkPortId, &dev_info); //
	
	const int num_rx_queues = 1;
	const int num_tx_queues = 1;
	struct rte_eth_conf port_conf = port_conf_default;
	rte_eth_dev_configure(gDpdkPortId, num_rx_queues, num_tx_queues, &port_conf);


	if (rte_eth_rx_queue_setup(gDpdkPortId, 0 , 1024, 
		rte_eth_dev_socket_id(gDpdkPortId),NULL, mbuf_pool) < 0) {

		rte_exit(EXIT_FAILURE, "Could not setup RX queue\n");

	}
	
#if ENABLE_SEND
	struct rte_eth_txconf txq_conf = dev_info.default_txconf;
	txq_conf.offloads = port_conf.rxmode.offloads;
	if (rte_eth_tx_queue_setup(gDpdkPortId, 0 , 1024, 
		rte_eth_dev_socket_id(gDpdkPortId), &txq_conf) < 0) {
		
		rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");
		
	}
#endif

	if (rte_eth_dev_start(gDpdkPortId) < 0 ) {
		rte_exit(EXIT_FAILURE, "Could not start\n");
	}

	

}


static int ng_encode_udp_pkt(uint8_t *msg, unsigned char *data, uint16_t total_len) {

	// encode 

	// 1 ethhdr
	struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
	rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	rte_memcpy(eth->d_addr.addr_bytes, gDstMac, RTE_ETHER_ADDR_LEN);
	eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
	

	// 2 iphdr 
	struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(msg + sizeof(struct rte_ether_hdr));
	ip->version_ihl = 0x45;
	ip->type_of_service = 0;
	ip->total_length = htons(total_len - sizeof(struct rte_ether_hdr));
	ip->packet_id = 0;
	ip->fragment_offset = 0;
	ip->time_to_live = 64; // ttl = 64
	ip->next_proto_id = IPPROTO_UDP;
	ip->src_addr = gSrcIp;
	ip->dst_addr = gDstIp;
	
	ip->hdr_checksum = 0;
	ip->hdr_checksum = rte_ipv4_cksum(ip);

	// 3 udphdr 

	struct rte_udp_hdr *udp = (struct rte_udp_hdr *)(msg + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
	udp->src_port = gSrcPort;
	udp->dst_port = gDstPort;
	uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);
	udp->dgram_len = htons(udplen);

	rte_memcpy((uint8_t*)(udp+1), data, udplen);

	udp->dgram_cksum = 0;
	udp->dgram_cksum = rte_ipv4_udptcp_cksum(ip, udp);

	struct in_addr addr;
	addr.s_addr = gSrcIp;
	printf(" --> src: %s:%d, ", inet_ntoa(addr), ntohs(gSrcPort));

	addr.s_addr = gDstIp;
	printf("dst: %s:%d\n", inet_ntoa(addr), ntohs(gDstPort));

	return 0;
}


static struct rte_mbuf * ng_send_udp(struct rte_mempool *mbuf_pool, uint8_t *data, uint16_t length) {

	// mempool --> mbuf

	const unsigned total_len = length + 42;

	struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
	if (!mbuf) {
		rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");
	}
	mbuf->pkt_len = total_len;
	mbuf->data_len = total_len;

	uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);

	ng_encode_udp_pkt(pktdata, data, total_len);

	return mbuf;

}



#if ENABLE_ARP


static int ng_encode_arp_pkt(uint8_t *msg, uint16_t opcode, uint8_t *dst_mac, uint32_t sip, uint32_t dip) {

	// 1 ethhdr
	struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
	rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	if (!strncmp((const char *)dst_mac, (const char *)gDefaultArpMac, RTE_ETHER_ADDR_LEN)) {
		uint8_t mac[RTE_ETHER_ADDR_LEN] = {0x0};
		rte_memcpy(eth->d_addr.addr_bytes, mac, RTE_ETHER_ADDR_LEN);
	} else {
		rte_memcpy(eth->d_addr.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);
	}
	eth->ether_type = htons(RTE_ETHER_TYPE_ARP);

	// 2 arp 
	struct rte_arp_hdr *arp = (struct rte_arp_hdr *)(eth + 1);
	arp->arp_hardware = htons(1);
	arp->arp_protocol = htons(RTE_ETHER_TYPE_IPV4);
	arp->arp_hlen = RTE_ETHER_ADDR_LEN;
	arp->arp_plen = sizeof(uint32_t);
	arp->arp_opcode = htons(opcode);

	rte_memcpy(arp->arp_data.arp_sha.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	rte_memcpy( arp->arp_data.arp_tha.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);

	arp->arp_data.arp_sip = sip;
	arp->arp_data.arp_tip = dip;
	
	return 0;

}

static struct rte_mbuf *ng_send_arp(struct rte_mempool *mbuf_pool, uint16_t opcode, uint8_t *dst_mac, uint32_t sip, uint32_t dip) {

	const unsigned total_length = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);

	struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
	if (!mbuf) {
		rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");
	}

	mbuf->pkt_len = total_length;
	mbuf->data_len = total_length;

	uint8_t *pkt_data = rte_pktmbuf_mtod(mbuf, uint8_t *);
	ng_encode_arp_pkt(pkt_data, opcode, dst_mac, sip, dip);

	return mbuf;
}

#endif


#if ENABLE_ICMP


static uint16_t ng_checksum(uint16_t *addr, int count) {

	register long sum = 0;

	while (count > 1) {

		sum += *(unsigned short*)addr++;
		count -= 2;
	
	}

	if (count > 0) {
		sum += *(unsigned char *)addr;
	}

	while (sum >> 16) {
		sum = (sum & 0xffff) + (sum >> 16);
	}

	return ~sum;
}

static int ng_encode_icmp_pkt(uint8_t *msg, uint8_t *dst_mac,
		uint32_t sip, uint32_t dip, uint16_t id, uint16_t seqnb) {

	// 1 ether
	struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
	rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
	rte_memcpy(eth->d_addr.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);
	eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);

	// 2 ip
	struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(msg + sizeof(struct rte_ether_hdr));
	ip->version_ihl = 0x45;
	ip->type_of_service = 0;
	ip->total_length = htons(sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr));
	ip->packet_id = 0;
	ip->fragment_offset = 0;
	ip->time_to_live = 64; // ttl = 64
	ip->next_proto_id = IPPROTO_ICMP;
	ip->src_addr = sip;
	ip->dst_addr = dip;
	
	ip->hdr_checksum = 0;
	ip->hdr_checksum = rte_ipv4_cksum(ip);

	// 3 icmp 
	struct rte_icmp_hdr *icmp = (struct rte_icmp_hdr *)(msg + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
	icmp->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
	icmp->icmp_code = 0;
	icmp->icmp_ident = id;
	icmp->icmp_seq_nb = seqnb;

	icmp->icmp_cksum = 0;
	icmp->icmp_cksum = ng_checksum((uint16_t*)icmp, sizeof(struct rte_icmp_hdr));

	return 0;
}


static struct rte_mbuf *ng_send_icmp(struct rte_mempool *mbuf_pool, uint8_t *dst_mac,
		uint32_t sip, uint32_t dip, uint16_t id, uint16_t seqnb) {

	const unsigned total_length = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr);

	struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
	if (!mbuf) {
		rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");
	}

	
	mbuf->pkt_len = total_length;
	mbuf->data_len = total_length;

	uint8_t *pkt_data = rte_pktmbuf_mtod(mbuf, uint8_t *);
	ng_encode_icmp_pkt(pkt_data, dst_mac, sip, dip, id, seqnb);

	return mbuf;

}


#endif

static void 
print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
{
	char buf[RTE_ETHER_ADDR_FMT_SIZE];
	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
	printf("%s%s", name, buf);
}


#if ENABLE_TIMER

static void
arp_request_timer_cb(__attribute__((unused)) struct rte_timer *tim,
	   void *arg) {

	struct rte_mempool *mbuf_pool = (struct rte_mempool *)arg;

#if 0
	struct rte_mbuf *arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REQUEST, ahdr->arp_data.arp_sha.addr_bytes, 
		ahdr->arp_data.arp_tip, ahdr->arp_data.arp_sip);

	rte_eth_tx_burst(gDpdkPortId, 0, &arpbuf, 1);
	rte_pktmbuf_free(arpbuf);

#endif
	
	int i = 0;
	for (i = 1;i <= 254;i ++) {

		uint32_t dstip = (gLocalIp & 0x00FFFFFF) | (0xFF000000 & (i << 24));

		struct in_addr addr;
		addr.s_addr = dstip;
		printf("arp ---> src: %s \n", inet_ntoa(addr));

		struct rte_mbuf *arpbuf = NULL;
		uint8_t *dstmac = ng_get_dst_macaddr(dstip);
		if (dstmac == NULL) {

			arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REQUEST, gDefaultArpMac, gLocalIp, dstip);
		
		} else {

			arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REQUEST, dstmac, gLocalIp, dstip);
		}

		rte_eth_tx_burst(gDpdkPortId, 0, &arpbuf, 1);
		rte_pktmbuf_free(arpbuf);
		
	}
	
}


#endif

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

	if (rte_eal_init(argc, argv) < 0) {
		rte_exit(EXIT_FAILURE, "Error with EAL init\n");
		
	}

	struct rte_mempool *mbuf_pool = rte_pktmbuf_pool_create("mbuf pool", NUM_MBUFS,
		0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
	if (mbuf_pool == NULL) {
		rte_exit(EXIT_FAILURE, "Could not create mbuf pool\n");
	}

	ng_init_port(mbuf_pool);

	rte_eth_macaddr_get(gDpdkPortId, (struct rte_ether_addr *)gSrcMac);

#if ENABLE_TIMER

	rte_timer_subsystem_init();

	struct rte_timer arp_timer;
	rte_timer_init(&arp_timer);

	uint64_t hz = rte_get_timer_hz();
	unsigned lcore_id = rte_lcore_id();
	rte_timer_reset(&arp_timer, hz, PERIODICAL, lcore_id, arp_request_timer_cb, mbuf_pool);

#endif

	while (1) {

		struct rte_mbuf *mbufs[BURST_SIZE];
		unsigned num_recvd = rte_eth_rx_burst(gDpdkPortId, 0, mbufs, BURST_SIZE);
		if (num_recvd > BURST_SIZE) {
			rte_exit(EXIT_FAILURE, "Error receiving from eth\n");
		}

		unsigned i = 0;
		for (i = 0;i < num_recvd;i ++) {

			struct rte_ether_hdr *ehdr = rte_pktmbuf_mtod(mbufs[i], struct rte_ether_hdr*);

#if ENABLE_ARP

			if (ehdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {

				struct rte_arp_hdr *ahdr = rte_pktmbuf_mtod_offset(mbufs[i], 
					struct rte_arp_hdr *, sizeof(struct rte_ether_hdr));

				
				struct in_addr addr;
				addr.s_addr = ahdr->arp_data.arp_tip;
				printf("arp ---> src: %s ", inet_ntoa(addr));

				addr.s_addr = gLocalIp;
				printf(" local: %s \n", inet_ntoa(addr));

				if (ahdr->arp_data.arp_tip == gLocalIp) {

					if (ahdr->arp_opcode == rte_cpu_to_be_16(RTE_ARP_OP_REQUEST)) {

						printf("arp --> request\n");

						struct rte_mbuf *arpbuf = ng_send_arp(mbuf_pool, RTE_ARP_OP_REPLY, ahdr->arp_data.arp_sha.addr_bytes, 
							ahdr->arp_data.arp_tip, ahdr->arp_data.arp_sip);

						rte_eth_tx_burst(gDpdkPortId, 0, &arpbuf, 1);
						rte_pktmbuf_free(arpbuf);

					} else if (ahdr->arp_opcode == rte_cpu_to_be_16(RTE_ARP_OP_REPLY)) {

						printf("arp --> reply\n");

						struct arp_table *table = arp_table_instance();

						uint8_t *hwaddr = ng_get_dst_macaddr(ahdr->arp_data.arp_sip);
						if (hwaddr == NULL) {

							struct arp_entry *entry = rte_malloc("arp_entry",sizeof(struct arp_entry), 0);
							if (entry) {
								memset(entry, 0, sizeof(struct arp_entry));

								entry->ip = ahdr->arp_data.arp_sip;
								rte_memcpy(entry->hwaddr, ahdr->arp_data.arp_sha.addr_bytes, RTE_ETHER_ADDR_LEN);
								entry->type = 0;
								
								LL_ADD(entry, table->entries);
								table->count ++;
							}

						}
#if ENABLE_DEBUG
						struct arp_entry *iter;
						for (iter = table->entries; iter != NULL; iter = iter->next) {
					
							struct in_addr addr;
							addr.s_addr = iter->ip;

							print_ethaddr("arp table --> mac: ", (struct rte_ether_addr *)iter->hwaddr);
								
							printf(" ip: %s \n", inet_ntoa(addr));
					
						}
#endif
						rte_pktmbuf_free(mbufs[i]);
					}
				
					continue;
				} 
			}
#endif

			if (ehdr->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
				continue;
			}

			struct rte_ipv4_hdr *iphdr =  rte_pktmbuf_mtod_offset(mbufs[i], struct rte_ipv4_hdr *, 
				sizeof(struct rte_ether_hdr));
			
			if (iphdr->next_proto_id == IPPROTO_UDP) {

				struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(iphdr + 1);

#if ENABLE_SEND //

				rte_memcpy(gDstMac, ehdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
				
				rte_memcpy(&gSrcIp, &iphdr->dst_addr, sizeof(uint32_t));
				rte_memcpy(&gDstIp, &iphdr->src_addr, sizeof(uint32_t));

				rte_memcpy(&gSrcPort, &udphdr->dst_port, sizeof(uint16_t));
				rte_memcpy(&gDstPort, &udphdr->src_port, sizeof(uint16_t));

#endif

				uint16_t length = ntohs(udphdr->dgram_len);
				*((char*)udphdr + length) = '\0';

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

				addr.s_addr = iphdr->dst_addr;
				printf("dst: %s:%d, %s\n", inet_ntoa(addr), ntohs(udphdr->dst_port), 
					(char *)(udphdr+1));

#if ENABLE_SEND

				struct rte_mbuf *txbuf = ng_send_udp(mbuf_pool, (uint8_t *)(udphdr+1), length);
				rte_eth_tx_burst(gDpdkPortId, 0, &txbuf, 1);
				rte_pktmbuf_free(txbuf);
				
#endif

				rte_pktmbuf_free(mbufs[i]);
			}

#if ENABLE_ICMP

			if (iphdr->next_proto_id == IPPROTO_ICMP) {

				struct rte_icmp_hdr *icmphdr = (struct rte_icmp_hdr *)(iphdr + 1);

				
				struct in_addr addr;
				addr.s_addr = iphdr->src_addr;
				printf("icmp ---> src: %s ", inet_ntoa(addr));

				
				if (icmphdr->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) {

					addr.s_addr = iphdr->dst_addr;
					printf(" local: %s , type : %d\n", inet_ntoa(addr), icmphdr->icmp_type);
				

					struct rte_mbuf *txbuf = ng_send_icmp(mbuf_pool, ehdr->s_addr.addr_bytes,
						iphdr->dst_addr, iphdr->src_addr, icmphdr->icmp_ident, icmphdr->icmp_seq_nb);

					rte_eth_tx_burst(gDpdkPortId, 0, &txbuf, 1);
					rte_pktmbuf_free(txbuf);

					rte_pktmbuf_free(mbufs[i]);
				}
				

			}


#endif
			
		}

#if ENABLE_TIMER

		static uint64_t prev_tsc = 0, cur_tsc;
		uint64_t diff_tsc;

		cur_tsc = rte_rdtsc();
		diff_tsc = cur_tsc - prev_tsc;
		if (diff_tsc > TIMER_RESOLUTION_CYCLES) {
			rte_timer_manage();
			prev_tsc = cur_tsc;
		}

#endif


	}

}

写在最后

  1. 后续对当前代码进行一些架构优化,并且添加别的协议,tcp还是比较麻烦的
  2. 昨天去面试,是一家头部的智能家具公司。虽然说应该是过了,但是回答的比较业余,要把八股文提上日程了哈哈哈。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

android在线阅读代码网站

android在线阅读代码社区&#xff1a; Android 1.6 到 Android 10 的源码&#xff1a; Android OS 在线源代码 - https://www.androidos.net.cn10.0.0_r6 - Android社区 - https://www.androidos.net.cn/ AndroidXRef https://cs.android.com/ https://cs.android.com/android…

FFmpeg源码:AV_RB32宏定义分析

一、AV_RB32宏定义的作用 AV_RB32是FFmpeg源码中经常出现的一个宏&#xff0c;其定义如下&#xff1a; #ifndef AV_RB32 # define AV_RB32(p) AV_RB(32, p) #endif 该宏定义有多层。把它简化为函数&#xff0c;其函数声明可以等价于&#xff1a; uint32_t AV_RB32(uint…

【尚庭公寓SpringBoot + Vue 项目实战】移动端找房功能(二十一)

【尚庭公寓SpringBoot Vue 项目实战】移动端找房功能&#xff08;二十一&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】移动端找房功能&#xff08;二十一&#xff09;1、业务介绍2、接口开发2.1、地区信息2.2、获取全部支付方式列表2.3、房间信息2.2.1. 根据条…

Android翻转动画(卡片翻转效果)

前言 最近好友问计蒙翻转动画&#xff0c;恰好在大二那年看Android Api Demo时记了笔记&#xff0c;由此写一篇文章。 需求 屏幕右滑事件触发卡片的翻转效果 &#xff0c;为了方便&#xff0c;在例子中将右滑事件改成按钮点击事件 老规矩&#xff0c;最后有源码 一、先介绍三…

算法金 | 奇奇怪怪的正则化

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 开篇引言正则化定义正则化通俗理解正则化类型 L1正则化&#xff08;Lasso回归&#xff09; L2正则化&#xff08;Ridge回归&#xff09…

[C++][数据结构][跳表]详细讲解

目录 0.什么是跳表&#xff1f;1.SkipList的优化思路2.SkipList的效率如何保证&#xff1f;3.SkipList实现4.SkipList VS 平衡搜索树 && Hash 0.什么是跳表&#xff1f; SkipList本质上也是一种查找结构&#xff0c;用于解决算法中的查找问题&#xff0c;跟平衡搜索树…

网络安全:Web 安全 面试题.(SQL注入)

网络安全&#xff1a;Web 安全 面试题.&#xff08;SQL注入&#xff09; 网络安全面试是指在招聘过程中,面试官会针对应聘者的网络安全相关知识和技能进行评估和考察。这种面试通常包括以下几个方面&#xff1a; &#xff08;1&#xff09;基础知识:包括网络基础知识、操作系…

php,python aes加密反解

1. python版本 import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpadclass AESUtilCBC:def __init__(self, key, iv):self.key key.encode(utf-8)self.iv iv.encode(utf-8)self.pad_length AES.block_sizedef encrypt(self, data):try…

WPF文本绑定显示格式StringFormat设置-特殊格式时间日期和多数据绑定

WPF文本绑定显示格式StringFormat设置 特殊格式设置日期/时间使用系统默认样式自定义格式&#xff1a; 绑定多个属性&#xff08;多重绑定&#xff09;多重绑定中的特殊字符示例&#xff1a; 特殊格式设置 在Textblock等文本控件中&#xff0c;我们经常要显示一些日期和时间&a…

第3章 小功能大用处-发布订阅

Redis提供了基于“发布/订阅”模式的消息机制&#xff0c;此种模式下&#xff0c;消息发布者和订阅者不进行直接通信&#xff0c;发布者客户端向指定的频道&#xff08;channel&#xff09;发布消息&#xff0c;订阅该频道的每个客户端都可以收到该消息。 命令&#xff1a;Red…

AI落地不容乐观-从神话到现实

开篇 在这儿我不是给大家泼冷水&#xff0c;而是我们一起来看一下从2022年11月左右GPT3.0掀起了一股“AI狂潮”后到现在&#xff0c;AI在商用、工业、军用下到底有没有得到了大规模应用呢&#xff1f; 这个答案每一个参与者其实心里有数那就是&#xff1a;没有。 但是呢它的…

win10修改远程桌面端口号,在Windows 10中修改远程桌面端口号的步骤

在Windows 10中&#xff0c;远程桌面服务&#xff08;Remote Desktop Services, RDS&#xff09;允许用户从远程位置访问和操作计算机。默认情况下&#xff0c;远程桌面协议&#xff08;RDP&#xff09;使用端口3389进行通信。然而&#xff0c;出于安全考虑&#xff0c;管理员可…

时序预测 | Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测&#xff1b; 2.多变量时间序列数据集&#xff08;负荷数据集&#xff09;&#xff0c;采用前96个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&…

Mac安装多个jdk环境(jdk8+jdk17)保姆级

Mac安装多个jdk环境&#xff08;jdk8jdk17&#xff09;保姆级 背景&#xff1a;新机安装开发环境发现需要找很多文章&#xff0c;&#xff0c;&#xff0c;&#xff0c;这里一篇文章安装所有环境 文章目录 Mac安装多个jdk环境&#xff08;jdk8jdk17&#xff09;保姆级&#x1f…

异步FIFO

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请根据题目中给出的双口RAM代码和接口描述&#xff0c;实现异步FIFO&#xff0c;要求FIFO位宽和深度参数化可配置。 电路的接口如下图所示。 双口RAM端口说明&#xff1a; 端口名 I/O 描述 wclk i…

微信小程序简易录音机

首先先创建一个项目&#xff08;想必大家都会啦那就直接开干&#xff09; 首先上html结构 <view class"wx-container"><view id"title">录音机</view><view id"time">{{hours}}:{{minute}}:{{second}}</view>&l…

锐捷统一上网行为管理与审计系统 static_convert.php 前台RCE漏洞复现

0x01 产品简介 锐捷统一上网行为管理与审计RG-UAC系列是星网锐捷网络有限公司自主研发的上网行为管理与审计产品,具备的上网行为日志审计功能,能够全面、准确、细致的审计并记录多种上网行为日志,包括网页、搜索、外发文件、邮件、论坛、IM等等,并对日志数据进行统计分析,…

React的服务器端渲染(SSR)和客户端渲染(CSR)有什么区别?

React的服务器端渲染&#xff08;SSR&#xff09;和客户端渲染&#xff08;CSR&#xff09;是两种不同的页面渲染方式&#xff0c;它们各自有不同的特点和适用场景&#xff1a; 服务器端渲染&#xff08;SSR&#xff09; 页面渲染: 页面在服务器上生成&#xff0c;然后将完整的…

USB2.0网卡安装驱动

有三种安装方式&#xff1a; 驱动精灵驱动总裁USB2.0网卡自带安装程序 前两种很简单&#xff0c;下载驱动精灵或者驱动总裁&#xff0c;然后检测本地硬件&#xff0c;安装相应驱动。 本文重点要介绍的是第三种&#xff0c;利用USB2.0网卡自带的安装程序。有的时候驱动精灵或…