DPDK系列之四十二DPDK应用网络编程UDP编程
一、UDP编程
UDP编程的应用和TCP编程的应用同样非常广泛,如果说真得想使用UDP编程,一般情况下还真得不至于运用DPDK这种重量级的框架。但一个框架的优秀与否,不仅仅在于自身的整体设计优秀,更重要的在于其对应用的支持更完善。
正如DPDK对TCP的支持一样,其实对于DPDK这种更侧重于底层的应用来说,实现UDP和TCP没有本质的区别,只是套的一层解析的协议不同罢了。同样,UDP与TCP的不同及其协议的内容如有不明白可自行查看相关资料,此处不再赘述。
二、DPDK实现UDP源码分析
下面看一下例程(代码来源与TCP相同):
1、数据结构和协议
// arp表的单个条目
struct arp_entry
{uint32_t ip;unsigned char hwaddr[RTE_ETHER_ADDR_LEN];unsigned char type;struct arp_entry *next;struct arp_entry *prev;
};// arp表结构
struct arp_table
{struct arp_entry *entries;int count;pthread_spinlock_t spinlock;
};
// udp control block
struct localhost
{int fd;//unsigned int status; //uint32_t localip; // ip --> macunsigned char localmac[RTE_ETHER_ADDR_LEN];uint16_t localport;unsigned char protocol;struct rte_ring *sndbuf;struct rte_ring *rcvbuf;struct localhost *prev;struct localhost *next;pthread_cond_t cond;pthread_mutex_t mutex;
};
//UDP的数据包
struct offload
{uint32_t sip;uint32_t dip;uint16_t sport;uint16_t dport;int protocol;unsigned char *data;uint16_t length;};
//common.c
int ng_arp_entry_insert(uint32_t ip, unsigned char *mac)
{struct arp_table *pstTbl = arp_table_instance();struct arp_entry *pstEntry = NULL;unsigned char *pstHwaddr = NULL;pstHwaddr = ng_get_dst_macaddr(ip);if(pstHwaddr == NULL){pstEntry = rte_malloc("arp_entry", sizeof(struct arp_entry), 0);if (pstEntry){memset(pstEntry, 0, sizeof(struct arp_entry));pstEntry->ip = ip;rte_memcpy(pstEntry->hwaddr, mac, RTE_ETHER_ADDR_LEN);pstEntry->type = 0;pthread_spin_lock(&pstTbl->spinlock);LL_ADD(pstEntry, pstTbl->entries);pstTbl->count ++;pthread_spin_unlock(&pstTbl->spinlock);}return 1;}return 0;
}static struct arp_table *arp_table_instance(void)
{if (g_pstArpTbl == NULL){g_pstArpTbl = rte_malloc("arp table", sizeof(struct arp_table), 0);if (g_pstArpTbl == NULL)rte_exit(EXIT_FAILURE, "rte_malloc arp table failed\n");memset(g_pstArpTbl, 0, sizeof(struct arp_table));pthread_spin_init(&g_pstArpTbl->spinlock, PTHREAD_PROCESS_SHARED);}return g_pstArpTbl;
}unsigned char* ng_get_dst_macaddr(uint32_t dip)
{struct arp_entry *pstIter;struct arp_table *pstTbl = arp_table_instance();int count = pstTbl->count;for (pstIter = pstTbl->entries; count-- != 0 && pstIter != NULL; pstIter = pstIter->next){if (dip == pstIter->ip)return pstIter->hwaddr;}return NULL;
}
UDP数据处理分为两类一类是控制包,一类是负载包也就是数据包。arp表的作用类似于快递小哥的作用,查找IP与MAC的映射并实现数据包的准确传输,即其有两个出口,一个是数据发送时的出口,保存发送时的IP和MAC(没有则先广播);一个是接收时的出口,用来保存收到的数据包对应的IP和MAC。代码没有什么难度,大家对照着相关的协议实现就明白了。
int nsocket(__attribute__((unused)) int domain, int type, __attribute__((unused)) int protocol)
{int iFd;struct localhost *pstHost;pthread_cond_t pctCond = PTHREAD_COND_INITIALIZER;pthread_mutex_t pmtMutex = PTHREAD_MUTEX_INITIALIZER;iFd = get_fd_frombitmap();if(type == SOCK_DGRAM) // udp{pstHost = rte_malloc("localhost", sizeof(struct localhost), 0);if(pstHost == NULL){printf("[%s][%d]: rte_malloc fail!\n", __FUNCTION__, __LINE__);return -1;}memset(pstHost, 0x00, sizeof(struct localhost));pstHost->fd = iFd;pstHost->protocol = IPPROTO_UDP;pstHost->rcvbuf = rte_ring_create("recv buffer", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);if (pstHost->rcvbuf == NULL){printf("[%s][%d]: rte_ring_create fail!\n", __FUNCTION__, __LINE__);rte_free(pstHost);return -1;}pstHost->sndbuf = rte_ring_create("send buffer", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);if (pstHost->sndbuf == NULL){printf("[%s][%d]: rte_ring_create fail!\n", __FUNCTION__, __LINE__);rte_ring_free(pstHost->rcvbuf);rte_free(pstHost);return -1;}rte_memcpy(&pstHost->cond, &pctCond, sizeof(pthread_cond_t));rte_memcpy(&pstHost->mutex, &pmtMutex, sizeof(pthread_mutex_t));LL_ADD(pstHost, g_pstHost);}else if(type == SOCK_STREAM) // tcp{struct tcp_stream *pstStream = rte_malloc("tcp_stream", sizeof(struct tcp_stream), 0);if (pstStream == NULL)return -1;memset(pstStream, 0, sizeof(struct tcp_stream));pstStream->fd = iFd;pstStream->protocol = IPPROTO_TCP;pstStream->next = pstStream->prev = NULL;pstStream->rcvbuf = rte_ring_create("tcp recv buffer", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);if (pstStream->rcvbuf == NULL){rte_free(pstStream);return -1;}pstStream->sndbuf = rte_ring_create("tcp send buffer", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);if (pstStream->sndbuf == NULL){rte_ring_free(pstStream->rcvbuf);rte_free(pstStream);return -1;}pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;rte_memcpy(&pstStream->cond, &blank_cond, sizeof(pthread_cond_t));pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;rte_memcpy(&pstStream->mutex, &blank_mutex, sizeof(pthread_mutex_t));g_pstTcpTbl = tcpInstance();LL_ADD(pstStream, g_pstTcpTbl->tcb_set); // todo :hash}return iFd;
}
int nbind(int sockfd, const struct sockaddr *addr, __attribute__((unused)) socklen_t addrlen)
{void *info = NULL;info = get_hostinfo_fromfd(sockfd);if(info == NULL)return -1;struct localhost *pstHostInfo = (struct localhost *)info;if(pstHostInfo->protocol == IPPROTO_UDP){const struct sockaddr_in *pstAddr = (const struct sockaddr_in *)addr;pstHostInfo->localport = pstAddr->sin_port;rte_memcpy(&pstHostInfo->localip, &pstAddr->sin_addr.s_addr, sizeof(uint32_t));rte_memcpy(pstHostInfo->localmac, &g_stCpuMac, RTE_ETHER_ADDR_LEN);}else if(pstHostInfo->protocol == IPPROTO_TCP){struct tcp_stream* pstStream = (struct tcp_stream*)pstHostInfo;const struct sockaddr_in *pstAddr = (const struct sockaddr_in *)addr;pstStream->dport = pstAddr->sin_port;rte_memcpy(&pstStream->dip, &pstAddr->sin_addr.s_addr, sizeof(uint32_t));rte_memcpy(pstStream->localmac, &g_stCpuMac, RTE_ETHER_ADDR_LEN);pstStream->status = TCP_STATUS_CLOSED;}return 0;
}
ssize_t nrecvfrom(int sockfd, void *buf, size_t len, __attribute__((unused)) int flags,struct sockaddr *src_addr, __attribute__((unused)) socklen_t *addrlen)
{struct localhost *pstHostInfo = NULL;struct offload *pstOffLoad = NULL;struct sockaddr_in *pstAddr = NULL;unsigned char *pucPtr = NULL;int iLen = 0;int iRet = -1;pstHostInfo = (struct localhost *)get_hostinfo_fromfd(sockfd);if(pstHostInfo == NULL)return -1;pthread_mutex_lock(&pstHostInfo->mutex);while((iRet = rte_ring_mc_dequeue(pstHostInfo->rcvbuf, (void**)&pstOffLoad)) < 0){pthread_cond_wait(&pstHostInfo->cond, &pstHostInfo->mutex);}pthread_mutex_unlock(&pstHostInfo->mutex);pstAddr = (struct sockaddr_in *)src_addr;pstAddr->sin_port = pstOffLoad->sport;rte_memcpy(&pstAddr->sin_addr.s_addr, &pstOffLoad->sip, sizeof(uint32_t));if(len < pstOffLoad->length){rte_memcpy(buf, pstOffLoad->data, len);pucPtr = rte_malloc("unsigned char *", pstOffLoad->length - len, 0);rte_memcpy(pucPtr, pstOffLoad->data + len, pstOffLoad->length - len);pstOffLoad->length -= len;rte_free(pstOffLoad->data);pstOffLoad->data = pucPtr;rte_ring_mp_enqueue(pstHostInfo->rcvbuf, pstOffLoad);return len;}iLen = pstOffLoad->length;rte_memcpy(buf, pstOffLoad->data, pstOffLoad->length);rte_free(pstOffLoad->data);rte_free(pstOffLoad);return iLen;
} ssize_t nsendto(int sockfd, const void *buf, size_t len, __attribute__((unused)) int flags,const struct sockaddr *dest_addr, __attribute__((unused)) socklen_t addrlen)
{struct localhost *pstHostInfo = NULL;struct offload *pstOffLoad = NULL;const struct sockaddr_in *pstAddr = (const struct sockaddr_in *)dest_addr;pstHostInfo = (struct localhost *)get_hostinfo_fromfd(sockfd);if(pstHostInfo == NULL)return -1;pstOffLoad = rte_malloc("offload", sizeof(struct offload), 0);if (pstOffLoad == NULL)return -1;pstOffLoad->dip = pstAddr->sin_addr.s_addr;pstOffLoad->dport = pstAddr->sin_port;pstOffLoad->sip = pstHostInfo->localip;pstOffLoad->sport = pstHostInfo->localport;pstOffLoad->length = len;struct in_addr addr;addr.s_addr = pstOffLoad->dip;printf("nsendto ---> src: %s:%d \n", inet_ntoa(addr), ntohs(pstOffLoad->dport));pstOffLoad->data = rte_malloc("unsigned char *", len, 0);if (pstOffLoad->data == NULL) {rte_free(pstOffLoad);return -1;}rte_memcpy(pstOffLoad->data, buf, len);puts("rte_ring_mp_enqueue before !");rte_ring_mp_enqueue(pstHostInfo->sndbuf, pstOffLoad);puts("rte_ring_mp_enqueue after !");return len;
}int nclose(int fd)
{void *info = NULL;info = (struct localhost *)get_hostinfo_fromfd(fd);if(info == NULL)return -1;struct localhost *pstHostInfo = (struct localhost *)info;if(pstHostInfo->protocol == IPPROTO_UDP){LL_REMOVE(pstHostInfo, g_pstHost);if (pstHostInfo->rcvbuf)rte_ring_free(pstHostInfo->rcvbuf);if (pstHostInfo->sndbuf)rte_ring_free(pstHostInfo->sndbuf);rte_free(pstHostInfo);set_fd_frombitmap(fd);}else if(pstHostInfo->protocol == IPPROTO_TCP){struct tcp_stream *pstStream = (struct tcp_stream*)info;if (pstStream->status != TCP_STATUS_LISTEN){struct tcp_fragment *pstFragment = rte_malloc("tcp_fragment", sizeof(struct tcp_fragment), 0);if (pstFragment == NULL)return -1;memset(pstFragment, 0x00, sizeof(struct tcp_fragment));pstFragment->data = NULL;pstFragment->length = 0;pstFragment->sport = pstStream->dport;pstFragment->dport = pstStream->sport;pstFragment->seqnum = pstStream->snd_nxt;pstFragment->acknum = pstStream->rcv_nxt;pstFragment->tcp_flags = RTE_TCP_FIN_FLAG | RTE_TCP_ACK_FLAG; // 发送FINpstFragment->windows = D_TCP_INITIAL_WINDOW;pstFragment->hdrlen_off = 0x50;rte_ring_mp_enqueue(pstStream->sndbuf, pstFragment);pstStream->status = TCP_STATUS_LAST_ACK;set_fd_frombitmap(fd);}else{LL_REMOVE(pstStream, g_pstTcpTbl->tcb_set);rte_free(pstStream);}}return 0;
}
2、接口实现
#include "udp.h"
int udp_process(struct rte_mbuf *pstUdpMbuf)
{struct rte_ipv4_hdr *pstIpHdr;struct rte_udp_hdr *pstUdpHdr;struct localhost *pstHost;struct offload *pstOffLoad;pstIpHdr = rte_pktmbuf_mtod_offset(pstUdpMbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));pstUdpHdr = (struct rte_udp_hdr *)(pstIpHdr + 1);pstHost = get_hostinfo_fromip_port(pstIpHdr->dst_addr, pstUdpHdr->dst_port, pstIpHdr->next_proto_id);if (pstHost == NULL){rte_pktmbuf_free(pstUdpMbuf);return -3;}struct in_addr addr;addr.s_addr = pstIpHdr->src_addr;printf("udp_process ---> src: %s:%d \n", inet_ntoa(addr), ntohs(pstUdpHdr->src_port));pstOffLoad = rte_malloc("offload", sizeof(struct offload), 0);if (pstOffLoad == NULL){rte_pktmbuf_free(pstUdpMbuf);return -1;}pstOffLoad->dip = pstIpHdr->dst_addr;pstOffLoad->sip = pstIpHdr->src_addr;pstOffLoad->sport = pstUdpHdr->src_port;pstOffLoad->dport = pstUdpHdr->dst_port;pstOffLoad->protocol = IPPROTO_UDP;pstOffLoad->length = ntohs(pstUdpHdr->dgram_len);pstOffLoad->data = rte_malloc("unsigned char*", pstOffLoad->length - sizeof(struct rte_udp_hdr), 0);if (pstOffLoad->data == NULL){rte_pktmbuf_free(pstUdpMbuf);rte_free(pstOffLoad);return -2;}rte_memcpy(pstOffLoad->data, (unsigned char *)(pstUdpHdr+1), pstOffLoad->length - sizeof(struct rte_udp_hdr));rte_ring_mp_enqueue(pstHost->rcvbuf, pstOffLoad); // recv bufferpthread_mutex_lock(&pstHost->mutex);pthread_cond_signal(&pstHost->cond);pthread_mutex_unlock(&pstHost->mutex);rte_pktmbuf_free(pstUdpMbuf);return 0;
}static int ng_encode_udp_apppkt(uint8_t *msg, uint32_t sip, uint32_t dip,uint16_t sport, uint16_t dport, uint8_t *srcmac, uint8_t *dstmac,unsigned char *data, uint16_t total_len)
{struct rte_ether_hdr *pstEth;struct rte_ipv4_hdr *pstIp;struct rte_udp_hdr *pstUdp;// 1 ethhdrpstEth = (struct rte_ether_hdr *)msg;rte_memcpy(pstEth->s_addr.addr_bytes, srcmac, RTE_ETHER_ADDR_LEN);rte_memcpy(pstEth->d_addr.addr_bytes, dstmac, RTE_ETHER_ADDR_LEN);pstEth->ether_type = htons(RTE_ETHER_TYPE_IPV4);// 2 iphdrpstIp = (struct rte_ipv4_hdr *)(pstEth + 1);pstIp->version_ihl = 0x45;pstIp->type_of_service = 0;pstIp->total_length = htons(total_len - sizeof(struct rte_ether_hdr));pstIp->packet_id = 0;pstIp->fragment_offset = 0;pstIp->time_to_live = 64; // ttl = 64pstIp->next_proto_id = IPPROTO_UDP;pstIp->src_addr = sip;pstIp->dst_addr = dip;pstIp->hdr_checksum = 0;pstIp->hdr_checksum = rte_ipv4_cksum(pstIp);// 3 udphdrpstUdp = (struct rte_udp_hdr *)(pstIp + 1);pstUdp->src_port = sport;pstUdp->dst_port = dport;uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);pstUdp->dgram_len = htons(udplen);rte_memcpy((uint8_t*)(pstUdp + 1), data, udplen);pstUdp->dgram_cksum = 0;pstUdp->dgram_cksum = rte_ipv4_udptcp_cksum(pstIp, pstUdp);return 0;
}static struct rte_mbuf * ng_udp_pkt(struct rte_mempool *mbuf_pool, uint32_t sip, uint32_t dip,uint16_t sport, uint16_t dport, unsigned char *srcmac, unsigned char *dstmac,unsigned char *data, uint16_t length)
{unsigned int uiTotalLen;struct rte_mbuf *pstMbuf;unsigned char *pucPktData;uiTotalLen = length + 42; // 42 = eth + ippstMbuf = rte_pktmbuf_alloc(mbuf_pool);if (!pstMbuf)rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");pstMbuf->pkt_len = uiTotalLen;pstMbuf->data_len = uiTotalLen;pucPktData = rte_pktmbuf_mtod(pstMbuf, unsigned char*);ng_encode_udp_apppkt(pucPktData, sip, dip, sport, dport, srcmac, dstmac,data, uiTotalLen);return pstMbuf;
}int udp_out(struct rte_mempool *pstMbufPool)
{struct localhost *pstHost;for(pstHost = g_pstHost; pstHost != NULL; pstHost = pstHost->next){struct offload *pstOffLoad = NULL;int iSendCnt = rte_ring_mc_dequeue(pstHost->sndbuf, (void **)&pstOffLoad);if(iSendCnt < 0)continue;struct in_addr addr;addr.s_addr = pstOffLoad->dip;printf("udp_out ---> src: %s:%d \n", inet_ntoa(addr), ntohs(pstOffLoad->dport));unsigned char *dstmac = ng_get_dst_macaddr(pstOffLoad->dip); // 查询对端mac地址if (dstmac == NULL) // 先广播发个arp包确定对端mac地址{struct rte_mbuf *pstArpbuf = ng_send_arp(pstMbufPool, RTE_ARP_OP_REQUEST, g_aucDefaultArpMac,pstOffLoad->sip, pstOffLoad->dip);rte_ring_mp_enqueue_burst(g_pstRingIns->pstOutRing, (void **)&pstArpbuf, 1, NULL);rte_ring_mp_enqueue(pstHost->sndbuf, pstOffLoad); // 将取出的udp数据再次写入队列}else{struct rte_mbuf *pstUdpbuf = ng_udp_pkt(pstMbufPool, pstOffLoad->sip, pstOffLoad->dip,pstOffLoad->sport, pstOffLoad->dport, pstHost->localmac,dstmac, pstOffLoad->data, pstOffLoad->length);rte_ring_mp_enqueue_burst(g_pstRingIns->pstOutRing, (void **)&pstUdpbuf, 1, NULL);if (pstOffLoad->data != NULL)rte_free(pstOffLoad->data);rte_free(pstOffLoad);}}return 0;
}
机制和TCP类似。
3、上层应用
//netfamily.c
unsigned char g_aucDefaultArpMac[RTE_ETHER_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};unsigned char g_ucFdTable[D_MAX_FD_COUNT] = {0};static struct St_InOut_Ring *ringInstance(void)
{if (g_pstRingIns == NULL){g_pstRingIns = rte_malloc("in/out ring", sizeof(struct St_InOut_Ring), 0);memset(g_pstRingIns, 0, sizeof(struct St_InOut_Ring));}return g_pstRingIns;
}void ng_init_port(struct rte_mempool *pstMbufPoolPub)
{unsigned int uiPortsNum;const int iRxQueueNum = 1;const int iTxQueueNum = 1;int iRet;struct rte_eth_dev_info stDevInfo;struct rte_eth_txconf stTxConf;struct rte_eth_conf stPortConf = // 端口配置信息{.rxmode = {.max_rx_pkt_len = 1518 } // RTE_ETHER_MAX_LEN = 1518};uiPortsNum = rte_eth_dev_count_avail();if (uiPortsNum == 0)rte_exit(EXIT_FAILURE, "No Supported eth found\n");rte_eth_dev_info_get(D_PORT_ID, &stDevInfo);// 配置以太网设备rte_eth_dev_configure(D_PORT_ID, iRxQueueNum, iTxQueueNum, &stPortConf);iRet = rte_eth_rx_queue_setup(D_PORT_ID, 0 , 1024, rte_eth_dev_socket_id(D_PORT_ID), NULL, pstMbufPoolPub);if(iRet < 0)rte_exit(EXIT_FAILURE, "Could not setup RX queue!\n");stTxConf = stDevInfo.default_txconf;stTxConf.offloads = stPortConf.txmode.offloads;iRet = rte_eth_tx_queue_setup(D_PORT_ID, 0 , 1024, rte_eth_dev_socket_id(D_PORT_ID), &stTxConf);if (iRet < 0)rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");if (rte_eth_dev_start(D_PORT_ID) < 0 )rte_exit(EXIT_FAILURE, "Could not start\n");rte_eth_promiscuous_enable(D_PORT_ID);
}static int ng_config_network_if(uint16_t port_id, unsigned char if_up) {if (!rte_eth_dev_is_valid_port(port_id)) {return -EINVAL;}int ret = 0;if (if_up) {rte_eth_dev_stop(port_id);ret = rte_eth_dev_start(port_id);} else {rte_eth_dev_stop(port_id);}if (ret < 0) {printf("Failed to start port : %d\n", port_id);}return 0;
}static struct rte_kni *ng_alloc_kni(struct rte_mempool *mbuf_pool) {struct rte_kni *kni_hanlder = NULL;struct rte_kni_conf conf;memset(&conf, 0, sizeof(conf));snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth%u", D_PORT_ID);conf.group_id = D_PORT_ID;conf.mbuf_size = D_MAX_PACKET_SIZE;rte_eth_macaddr_get(D_PORT_ID, (struct rte_ether_addr *)conf.mac_addr);rte_eth_dev_get_mtu(D_PORT_ID, &conf.mtu);// print_ethaddr("ng_alloc_kni: ", (struct ether_addr *)conf.mac_addr);/*struct rte_eth_dev_info dev_info;memset(&dev_info, 0, sizeof(dev_info));rte_eth_dev_info_get(D_PORT_ID, &dev_info);*/struct rte_kni_ops ops;memset(&ops, 0, sizeof(ops));ops.port_id = D_PORT_ID;ops.config_network_if = ng_config_network_if;kni_hanlder = rte_kni_alloc(mbuf_pool, &conf, &ops);if (!kni_hanlder) {rte_exit(EXIT_FAILURE, "Failed to create kni for port : %d\n", D_PORT_ID);}return kni_hanlder;
}static int pkt_process(void *arg)
{struct rte_mempool *pstMbufPool;int iRxNum;int i;struct rte_ether_hdr *pstEthHdr;struct rte_ipv4_hdr *pstIpHdr;pstMbufPool = (struct rte_mempool *)arg;while(1){struct rte_mbuf *pstMbuf[32];iRxNum = rte_ring_mc_dequeue_burst(g_pstRingIns->pstInRing, (void**)pstMbuf, D_BURST_SIZE, NULL);if(iRxNum <= 0)continue;for(i = 0; i < iRxNum; ++i){pstEthHdr = rte_pktmbuf_mtod_offset(pstMbuf[i], struct rte_ether_hdr *, 0);if (pstEthHdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) //IPv4: 0800{pstIpHdr = rte_pktmbuf_mtod_offset(pstMbuf[i], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));// 维护一个arp表ng_arp_entry_insert(pstIpHdr->src_addr, pstEthHdr->s_addr.addr_bytes);if(pstIpHdr->next_proto_id == IPPROTO_UDP) // udp{// udp processudp_process(pstMbuf[i]);}else if(pstIpHdr->next_proto_id == IPPROTO_TCP) // tcp{// printf("tcp_process ---\n");tcp_process(pstMbuf[i]);}else{rte_kni_tx_burst(g_pstKni, pstMbuf, iRxNum);// printf("tcp/udp --> rte_kni_handle_request\n");}}else{// ifconfig vEth0 192.168.181.169 uprte_kni_tx_burst(g_pstKni, pstMbuf, iRxNum);// printf("ip --> rte_kni_handle_request\n");} }rte_kni_handle_request(g_pstKni);// to sendudp_out(pstMbufPool);tcp_out(pstMbufPool);}return 0;
}int udp_server_entry(__attribute__((unused)) void *arg)
{ int iConnfd;struct sockaddr_in stLocalAddr, stClientAddr;socklen_t uiAddrLen = sizeof(stClientAddr);;char acBuf[D_UDP_BUFFER_SIZE] = {0};iConnfd = nsocket(AF_INET, SOCK_DGRAM, 0);if (iConnfd == -1){printf("nsocket failed\n");return -1;}memset(&stLocalAddr, 0, sizeof(struct sockaddr_in));stLocalAddr.sin_port = htons(8889);stLocalAddr.sin_family = AF_INET;stLocalAddr.sin_addr.s_addr = inet_addr("192.168.181.169");nbind(iConnfd, (struct sockaddr*)&stLocalAddr, sizeof(stLocalAddr));while (1){if (nrecvfrom(iConnfd, acBuf, D_UDP_BUFFER_SIZE, 0,(struct sockaddr*)&stClientAddr, &uiAddrLen) < 0){continue;}else{printf("recv from %s:%d, data:%s\n", inet_ntoa(stClientAddr.sin_addr),ntohs(stClientAddr.sin_port), acBuf);nsendto(iConnfd, acBuf, strlen(acBuf), 0,(struct sockaddr*)&stClientAddr, sizeof(stClientAddr));}}nclose(iConnfd);return 0;
}int main(int argc, char *argv[])
{struct rte_mempool *pstMbufPoolPub;struct St_InOut_Ring *pstRing;struct rte_mbuf *pstRecvMbuf[32] = {NULL};struct rte_mbuf *pstSendMbuf[32] = {NULL};int iRxNum;int iTotalNum;int iOffset;int iTxNum;unsigned int uiCoreId;if(rte_eal_init(argc, argv) < 0)rte_exit(EXIT_FAILURE, "Error with EAL init\n");pstMbufPoolPub = rte_pktmbuf_pool_create("MBUF_POOL_PUB", D_NUM_MBUFS, 0, 0,RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());if(pstMbufPoolPub == NULL){printf("rte_errno = %x, errmsg = %s\n", rte_errno, rte_strerror(rte_errno));return -1;}if (-1 == rte_kni_init(D_PORT_ID))rte_exit(EXIT_FAILURE, "kni init failed\n");ng_init_port(pstMbufPoolPub);g_pstKni = ng_alloc_kni(pstMbufPoolPub);// ng_init_port(pstMbufPoolPub);rte_eth_macaddr_get(D_PORT_ID, &g_stCpuMac);pstRing = ringInstance();if(pstRing == NULL)rte_exit(EXIT_FAILURE, "ring buffer init failed\n");pstRing->pstInRing = rte_ring_create("in ring", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);pstRing->pstOutRing = rte_ring_create("out ring", D_RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);uiCoreId = rte_lcore_id();uiCoreId = rte_get_next_lcore(uiCoreId, 1, 0);rte_eal_remote_launch(pkt_process, pstMbufPoolPub, uiCoreId);uiCoreId = rte_get_next_lcore(uiCoreId, 1, 0);rte_eal_remote_launch(udp_server_entry, pstMbufPoolPub, uiCoreId);uiCoreId = rte_get_next_lcore(uiCoreId, 1, 0);rte_eal_remote_launch(tcp_server_entry, pstMbufPoolPub, uiCoreId);while (1){// rxiRxNum = rte_eth_rx_burst(D_PORT_ID, 0, pstRecvMbuf, D_BURST_SIZE);if(iRxNum > 0)rte_ring_sp_enqueue_burst(pstRing->pstInRing, (void**)pstRecvMbuf, iRxNum, NULL);// txiTotalNum = rte_ring_sc_dequeue_burst(pstRing->pstOutRing, (void**)pstSendMbuf, D_BURST_SIZE, NULL);if(iTotalNum > 0){iOffset = 0;while(iOffset < iTotalNum){iTxNum = rte_eth_tx_burst(D_PORT_ID, 0, &pstSendMbuf[iOffset], iTotalNum - iOffset);if(iTxNum > 0)iOffset += iTxNum;}}}}
在前面的应用中,其实可以发现处理的TCP和UDP的数据有的是写在一个函数里了,这其实是从设计上看不是很好,以后不容易扩展,可它也有好处啊,容易让人明白啊。更多的依赖代码可以参看GITHUB上的开源地址。
四、总结
UDP其实在普通的网络应用中,基本用来做一些辅助的工作,如果地址发现、广播简单消息等等。但由于它的占用资源少,在一些场景下就能发挥很大作用。包括在前文提到的QUIC其实都借鉴了UDP的一些特点。所以是不是觉得,很多技术其实并不是完全隔离的,它们会不断的整合、独立再如此循环。所以以后别的公司会不会也会也一个类似于DPDK的框架呢?拭目以待!
相关文章:

DPDK系列之四十二DPDK应用网络编程UDP编程
一、UDP编程 UDP编程的应用和TCP编程的应用同样非常广泛,如果说真得想使用UDP编程,一般情况下还真得不至于运用DPDK这种重量级的框架。但一个框架的优秀与否,不仅仅在于自身的整体设计优秀,更重要的在于其对应用的支持更完善。 正…...

金三银四面试题(十九):MySQL中的锁
在MySQL中,锁是非常重要的,特别是在多用户并发访问数据库的环境中,因此也是面试中常问的话题。 请说说数据库的锁? 关于MySQL 的锁机制,可能会问很多问题,不过这也得看面试官在这方面的知识储备。 MySQL …...

【JavaScript】原型链/作用域/this指针/闭包
1.原型链 参考资料:Annotated ES5 ECMAScript起初并不支持如C、Smalltalk 或 Java 中“类”的形式创建对象,而是通过字面量表示法或者构造函数创建对象。每个构造函数都是一个具有名为“prototype”的属性的函数,该属性用于实现基于原型的继…...

Python的MATLAB使用
Python和MATLAB是两种不同的编程语言,它们各自拥有不同的生态系统和库。然而,你可以在Python中使用一些方法来实现与MATLAB类似的功能。以下是一些方法和库,可以帮助你在Python中实现MATLAB风格的编程: 1. NumPy: NumPy是Python中…...

文件输入/输出流(I/O)
文章目录 前言一、文件输入\输出流是什么?二、使用方法 1.FileInputStream与FileOutputStream类2.FileReader与FileWriter类总结 前言 对于文章I/O(输入/输出流的概述),有了下文。这篇文章将具体详细展述如何向磁盘文件中输入数据,或者读取磁…...

docker,schedule job和environment variables三者的含义与区别
这三个概念在软件开发和部署中扮演着不同的角色: Docker一般长这样:superlifestyle/sscp-api Schedule Job一般长这样:recorrect_ocr_receipt_status 、Sync2D365 Environment Variables一般长这样:D365_BATCH_OPERATION_SIZE ima…...

90天玩转Python—16—基础知识篇:面向对象知识详解
90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

python 标准库之openpyxl的常规操作
目录 openpyxl(Excel文件处理模块) 读sheet 读sheet中单元格 合并单元格 openpyxl模块基本用法 安装方法 基本使用 读取Excel文档 (一)获取工作表 (二)获取单元格 (三)获取…...

90天玩转Python—12—基础知识篇:Python自动化操作Email:发送邮件、收邮件与邮箱客户端操作全解析
90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

利用lidar_align来进行lidar和imu标定
文章目录 下载并安装lidar_align安装nlopt迁移NLOPTConfig.cmake修改loader.cpp文件编译并运行 下载并安装lidar_align mkdir -p lidar_align/src cd lidar_align/src git clone https://github.com/ethz-asl/lidar_align.git安装nlopt git clone http://github.com/steven…...

牛客NC93 设计LRU缓存结构【hard 链表,Map Java】
题目 题目链接: https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84 思路 双向链表map最新的数据放头结点,尾节点放最老的数据,没次移除尾巴节点本地考察链表的新增,删除,移动节点参考答案Java im…...

机器学习和深度学习 -- 李宏毅(笔记与个人理解1-6)
机器学习和深度学习教程 – 李宏毅(笔记与个人理解) day1 课程内容 什么是机器学习 找函数关键技术(深度学习) 函数 – 类神经网络来表示 ;输入输出可以是 向量或者矩阵等如何找到函数: supervised Lear…...

低功耗全极霍尔开关芯片 D02,磁性开关点精确,对工艺和温度变化不敏感
1、概述 D02 是一款低功耗全极霍尔开关,用于检测施加的磁通量密度,并提供一个数字输出,该输出指示所感测磁通量幅度的当前状态。这些应用的一个例子是翻盖手机中的 ON/OFF 开关。微功耗设计特别适合电池供电系统,如手机或笔记本电…...

初识--数据结构
什么是数据结构?我们为什么要学习数据结构呢....一系列的问题就促使我们不得不了解数据结构。我们不禁要问了,学习C语言不就够了吗?为什么还要学习数据结构呢?这是因为:数据结构能够解决C语言解决不了的问题࿰…...

人工智能前沿成科技竞争新高地
以下文章来源:经济参考报 近日,首届中国具身智能大会(CEAI 2024)在上海举行。作为人工智能领域的前沿热点,具身智能正逐步走进现实,成为当前全球科技竞争的新高地、未来产业的新赛道、经济发展的新引擎。 “…...

【算法刷题day23】Leetcode:669. 修剪二叉搜索树、108. 将有序数组转换为二叉搜索树、538. 把二叉搜索树转换为累加树
文章目录 Leetcode 669. 修剪二叉搜索树解题思路代码总结 Leetcode 108. 将有序数组转换为二叉搜索树解题思路代码总结 Leetcode 538. 把二叉搜索树转换为累加树解题思路代码总结 草稿图网站 java的Deque Leetcode 669. 修剪二叉搜索树 题目:669. 修剪二叉搜索树 解…...

设计一个会议管理系统100问?
会议管理系统的基本功能有哪些?如何确保会议管理系统的安全性?会议管理系统可以支持多少种不同类型的会议?是否有权限管理功能?是否支持会议室预订功能?会议管理系统可以导入外部参与者信息吗?是否支持多种…...

一文搞懂BI、ERP、MES、SCM、PLM、CRM、WMS、APS、SCADA、QMS
在企业信息化数字化过程中我们经常遇到很多系统,比如:MES、ERP、SCM、WMS、APS、SCADA、PLM、QMS、CRM、EAM、BI,这些都是什么系统?有什么功能和作用?它们之间的关系是怎样的? 今天就一文简单分享。 术语 …...

全量知识系统 程序详细设计 之 先验逻辑-实现:从“平凡”回到“平凡” (QA 百度搜索)
Q1. 思考:数学中的平凡,和程序中的平凡(比如POJO)、语言中的平凡(比如纯文本),数据中的平凡(比如 Number)。因为我设计中的全知系统将设计的三个方面刻画为语言设计、程序…...

注解(Annotation) --java学习笔记
注解 就是Java代码里的特殊标记,比如:Override、Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处 自定义注解 就是自己定义注解 自定义注解到底该怎么写:…...

uniapp 小程序获取WiFi列表
<template><view ><button click"getWifiList">获取WiFi列表</button><scroll-view:scroll-top"scrollTop"scroll-yclass"content-pop"><viewclass"itemInfo"v-for"(item, index) in wifiList&…...

数据可视化-ECharts Html项目实战(11)
在之前的文章中,我们学习了如何在ECharts中特殊图表的双y图以及自定义形状词云图。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢。 数据可视化-ECh…...

【MySQL数据库 | 第二十四篇】Limit语句的性能问题和调优策略
前言: MySQL作为最流行的关系型数据库管理系统之一,被广泛应用于各种规模和类型的应用程序中。其强大的功能和灵活的查询语言使得开发人员能够高效地执行各种数据操作和分析。 然而,在处理大量数据或复杂查询时,一些开发人员可能…...

【数据结构】两两交换链表 复制带随机指针的链表
问题描述1 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 求解 使用一个栈S来存储相邻两个节点即可 /*** Definition for…...

网络安全流量平台_优缺点分析
FlowShadow(流影),Ntm(派网),Elastiflow。 Arkimesuricata,QNSMsuricata,Malcolm套件。 Malcolm套件优点:支持文件还原反病毒引擎(clamav/yara)…...

【c语言】自定义类型:结构体详解
目录 自定义类型:结构体 结构体类型的声明 结构体变量的创建和初始化 结构的特殊声明 结构的自引用 结构体内存对齐 对其规则 为什么存在内存对齐? 修改默认对⻬数 结构体传参 结构体实现位段 位段的内存分配 位段的跨平台问题 位段的应用…...

利用AbortController,取消正在发送的请求
参考文章:https://blog.csdn.net/qq_45560350/article/details/130588101 解决问题:再图层中点击仓库的时候,点击后又取消掉,我们希望这个请求可以被取消掉,我们口可以利用AbortController控制器对象 实操:…...

dockerhub右键快速搜索脚本
Chrome 浏览器扩展的后台脚本,用于创建右键菜单项,并根据用户的操作在新的标签页中打开 Docker Hub 网站或者进行搜索。 // 创建右键菜单项,用于打开 Docker Hub 网站 chrome.contextMenus.create({id: search-home, // 菜单项的唯一标识符t…...

类似微信的以文搜图功能实现
通过PaddleOCR识别图片中的文字,将识别结果报存到es中,利用es查询语句返回结果图片。 技术逻辑 PaddleOCR部署、es部署创建mapping将PaddleOCR识别结果保存至es通过查询,返回结果 前期准备 PaddleOCR、es部署请参考https://blog.csdn.net…...

Android 13.0 Launcher3定制化之最近任务的全部清除由左边移到下边显示
1.概述 在最近13.0的系统rom产品开发中,在Launcher3的定制化开发中,在最近任务列表中,发现点击recents最近任务键后 显示的全部清除按键在左边 由于是横屏的产品显示在左边不太合理 所以要求显示在下边比较合理,所以要从Launcher3的显示流程来解决这个问题 2. 最近任务全…...