/* ********************************************************************************************** * File: packet_io_util.cpp * Description: * Authors: Liu WenTan * Date: 2022-07-15 * Copyright: (c) 2018-2022 Geedge Networks, Inc. All rights reserved. *********************************************************************************************** */ #include #include #include #include #include "utils.h" #include "packet_io_util.h" static ssize_t packet_copy_data_offset(uint8_t *ptr, uint32_t offset, const uint8_t *data, uint32_t data_len) { memcpy(ptr + offset, data, data_len); return 0; } ssize_t packet_copy_data(uint8_t *ptr, const uint8_t *pkt_data, uint32_t pkt_len) { return packet_copy_data_offset(ptr, 0, pkt_data, pkt_len); } void pio_packet_queue_init(struct pio_packet_queue *q) { if (nullptr == q) { return; } q->bot = nullptr; q->top = nullptr; q->len = 0; pthread_mutex_init(&q->mutex_q, nullptr); } void pio_packet_enqueue(struct pio_packet_queue *q, struct pio_packet *p) { if (nullptr == p) return; /* more packets in queue */ if (q->top != nullptr) { p->prev = nullptr; p->next = q->top; q->top->prev = p; q->top = p; /* only packet */ } else { p->prev = nullptr; p->next = nullptr; q->top = p; q->bot = p; } q->len++; } struct pio_packet *pio_packet_dequeue(struct pio_packet_queue *q) { struct pio_packet *p = nullptr; /* if the queue is empty there are no packets left. */ if (q->len == 0) { return nullptr; } q->len--; /* pull the bottom packet from the queue */ p = q->bot; /* more packets in queue */ if (q->bot->prev != nullptr) { q->bot = q->bot->prev; q->bot->next = nullptr; /* just the one we remove, so now empty */ } else { q->top = nullptr; q->bot = nullptr; } p->next = nullptr; p->prev = nullptr; return p; } void release_pio_packet_queue(struct pio_packet_queue *q) { if (nullptr == q) { return; } while (q->len != 0) { struct pio_packet *p = pio_packet_dequeue(q); FREE(p); } } ssize_t strncpy_safe(char *dst, const char *src, size_t dst_size) { if (nullptr == dst || nullptr == src || dst_size == 0) { return -1; } size_t slen = strlen(src); if (slen >= dst_size) { strncpy(dst, src, dst_size); dst[dst_size - 1] = '\0'; } else { strcpy(dst, src); } return 0; } static uint32_t simple_murmur_hash(const void *key, int len) { const uint32_t m = 0x5bd1e995; const int r = 24; /* Initialize the hash to a 'random' value */ uint32_t h = len; const unsigned char *data = (const unsigned char *)key; while (len >= 4) { uint32_t k = *(uint32_t *)data; k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } /* Handle the last few bytes of the input array */ switch (len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; /* Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. */ h ^= h >> 13; h *= m; h ^= h >> 15; return h; } static uint64_t generic_2tuple_hash(uint8_t *src, uint8_t *dst, size_t n) { if (nullptr == src || nullptr == dst || n == 0) { return 0; } uint64_t key1 = simple_murmur_hash(src, n); uint64_t key2 = simple_murmur_hash(dst, n); return (key1 ^ key2); } uint64_t pio_packet_hash(struct pio_packet *p) { struct ethhdr *eth_hdr = (struct ethhdr *)p->pkt_payload; uint8_t *disp_arg1 = nullptr; uint8_t *disp_arg2 = nullptr; size_t disp_len = 0; if (p->data_link != LINKTYPE_ETHERNET) { return 0; } uint16_t eth_type = ntohs(eth_hdr->h_proto); if (eth_type == ETHERNET_TYPE_IP) { struct iphdr *ipv4_hdr = (struct iphdr *)(eth_hdr + 1); disp_arg1 = (uint8_t *)&ipv4_hdr->saddr; disp_arg2= (uint8_t *)&ipv4_hdr->daddr; disp_len = sizeof(uint32_t); } else if (eth_type == ETHERNET_TYPE_IPV6) { struct ip6_hdr *ipv6_hdr = (struct ip6_hdr *)(eth_hdr + 1); disp_arg1 = (uint8_t *)&ipv6_hdr->ip6_src; disp_arg2 = (uint8_t *)&ipv6_hdr->ip6_dst; disp_len = sizeof(struct in6_addr); } uint64_t hash = generic_2tuple_hash(disp_arg1, disp_arg2, disp_len); return hash; }