Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,35 @@

## Performance

- **Test Overview**
One large packet with 100 Million bytes of data

- **Hardware & Conditions**
Tested on a MacBook Air M3 (my daily driver machine, running multiple background applications)

- **Interface**
Real Wi-Fi interface: en0

- **Throughput**
9.4 MB/s
20.9 MB/s

- **Memory Usage**
Peak memory footprint: 14 million bytes
**Peak memory footprint: 203 million bytes**
- 100M bytes are used for buffers on receiver and sender
- 3M bytes are used on internal data


- **CPU Usage**
Average utilization: ~7.7%
Average utilization: ~9%

- **Detailed Timing (from /usr/bin/time -l)**
- Real (wall-clock) time: 5.32 seconds
- User CPU time: 0.24 seconds
- System CPU time: 0.17 seconds
- Total CPU time: 0.41 seconds
- Real (wall-clock) time: 4.78 seconds
- User CPU time: 0.07 seconds
- System CPU time: 0.31 seconds
- Total CPU time: 0.38 seconds

- **CPU Cycles**
1 005 063 001 cycles
1 513 423 854 cycles

## Installation
Follow these steps to install SwiftNet:
Expand Down
63 changes: 31 additions & 32 deletions src/execute_packet_callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,52 +59,51 @@ void execute_packet_callback(
pthread_mutex_t* const execute_callback_mtx,
pthread_cond_t* const execute_callback_cond
) {
while (1) {
if (atomic_load_explicit(closing, memory_order_acquire) == true) {
break;
}
check_packet:
if (unlikely(atomic_load_explicit(closing, memory_order_acquire) == true)) {
return;
}

pthread_mutex_lock(execute_callback_mtx);
pthread_mutex_lock(execute_callback_mtx);

const struct PacketCallbackQueueNode* const node = wait_for_next_packet_callback(queue);
if(node == NULL) {
pthread_cond_wait(execute_callback_cond, execute_callback_mtx);
const struct PacketCallbackQueueNode* const node = wait_for_next_packet_callback(queue);
if(node == NULL) {
pthread_cond_wait(execute_callback_cond, execute_callback_mtx);

pthread_mutex_unlock(execute_callback_mtx);
pthread_mutex_unlock(execute_callback_mtx);

continue;
}
goto check_packet;
}

pthread_mutex_unlock(execute_callback_mtx);
pthread_mutex_unlock(execute_callback_mtx);

atomic_thread_fence(memory_order_acquire);
if(node->packet_data == NULL) {
allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);
goto check_packet;
}

if(node->packet_data == NULL) {
allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);
continue;
}
if(node->pending_message != NULL) {
remove_pending_message_from_hashmap(pending_messages, node->pending_message);
}

if(node->pending_message != NULL) {
remove_pending_message_from_hashmap(pending_messages, node->pending_message);
void (*const packet_handler_loaded)(void* const, void* const) = atomic_load(packet_handler);
if (unlikely(packet_handler_loaded == NULL)) {
if (connection_type == CONNECTION_TYPE_CLIENT) {
swiftnet_client_destroy_packet_data(node->packet_data, connection);
} else {
swiftnet_client_destroy_packet_data(node->packet_data, connection);
}

void (*const packet_handler_loaded)(void* const, void* const) = atomic_load(packet_handler);
if (unlikely(packet_handler_loaded == NULL)) {
if (connection_type == CONNECTION_TYPE_CLIENT) {
swiftnet_client_destroy_packet_data(node->packet_data, connection);
} else {
swiftnet_client_destroy_packet_data(node->packet_data, connection);
}
allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);

allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);
goto check_packet;
}

continue;
}
(*packet_handler_loaded)(node->packet_data, atomic_load_explicit(user_data, memory_order_acquire));

(*packet_handler_loaded)(node->packet_data, atomic_load_explicit(user_data, memory_order_acquire));
allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);

allocator_free(&packet_callback_queue_node_memory_allocator, (void*)node);
}
goto check_packet;
}

void* execute_packet_callback_client(void* const void_client) {
Expand Down
20 changes: 10 additions & 10 deletions src/handle_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ static inline void swiftnet_handle_packets(
const struct pcap_pkthdr* hdr,
const uint8_t* packet,
pthread_mutex_t* const process_packets_mtx,
pthread_cond_t* const process_packets_cond

pthread_cond_t* const process_packets_cond,
_Atomic bool *const processing_packets
) {
uint8_t* const packet_buffer = allocator_allocate(&packet_buffer_memory_allocator);
if (unlikely(packet_buffer == NULL)) {
Expand Down Expand Up @@ -100,15 +100,15 @@ static inline void swiftnet_handle_packets(

struct PacketQueueNode* const node = construct_node(len, packet_buffer, sender_address);

atomic_thread_fence(memory_order_release);

pthread_mutex_lock(process_packets_mtx);

insert_queue_node(node, packet_queue, connection_type);

pthread_cond_signal(process_packets_cond);
if (atomic_load_explicit(processing_packets, memory_order_acquire) != true) {
pthread_mutex_lock(process_packets_mtx);

pthread_mutex_unlock(process_packets_mtx);
pthread_cond_signal(process_packets_cond);

pthread_mutex_unlock(process_packets_mtx);
}
}

static void handle_client_init(struct SwiftNetClientConnection* user, const struct pcap_pkthdr* hdr, const uint8_t* buffer) {
Expand Down Expand Up @@ -177,7 +177,7 @@ static inline void handle_correct_receiver(const enum ConnectionType connection_
if (client_connection->initialized == false) {
handle_client_init(client_connection, hdr, packet);
} else {
swiftnet_handle_packets(client_connection->port_info.source_port, &client_connection->process_packets_thread, client_connection, CONNECTION_TYPE_CLIENT, &client_connection->packet_queue, &client_connection->closing, client_connection->loopback, client_connection->addr_type, hdr, packet, &client_connection->process_packets_mtx, &client_connection->process_packets_cond);
swiftnet_handle_packets(client_connection->port_info.source_port, &client_connection->process_packets_thread, client_connection, CONNECTION_TYPE_CLIENT, &client_connection->packet_queue, &client_connection->closing, client_connection->loopback, client_connection->addr_type, hdr, packet, &client_connection->process_packets_mtx, &client_connection->process_packets_cond, &client_connection->processing_packets);
}
} else {
LOCK_ATOMIC_DATA_TYPE(&listener->servers.atomic_lock);
Expand All @@ -189,7 +189,7 @@ static inline void handle_correct_receiver(const enum ConnectionType connection_
return;
}

swiftnet_handle_packets(server->server_port, &server->process_packets_thread, server, CONNECTION_TYPE_SERVER, &server->packet_queue, &server->closing, server->loopback, server->addr_type, hdr, packet, &server->process_packets_mtx, &server->process_packets_cond);
swiftnet_handle_packets(server->server_port, &server->process_packets_thread, server, CONNECTION_TYPE_SERVER, &server->packet_queue, &server->closing, server->loopback, server->addr_type, hdr, packet, &server->process_packets_mtx, &server->process_packets_cond, &server->processing_packets);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/initialize_client_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void* request_server_information(void* const request_server_information_args_voi
}
#endif

swiftnet_pcap_send(request_server_information_args->pcap, request_server_information_args->data, request_server_information_args->size);
SWIFTNET_PCAP_SEND_SAFE(request_server_information_args->pcap, request_server_information_args->data, request_server_information_args->size);

usleep(250000);
}
Expand Down Expand Up @@ -98,6 +98,7 @@ static inline struct SwiftNetClientConnection* const construct_client_connection
UNLOCK_ATOMIC_DATA_TYPE(&new_connection->packet_queue.locked);
UNLOCK_ATOMIC_DATA_TYPE(&new_connection->packet_callback_queue.locked);

atomic_store_explicit(&new_connection->processing_packets, true, memory_order_release);
atomic_store_explicit(&new_connection->closing, false, memory_order_release);
atomic_store_explicit(&new_connection->initialized, false, memory_order_release);
atomic_store_explicit(&new_connection->packet_handler_user_arg, NULL, memory_order_release);
Expand Down
1 change: 1 addition & 0 deletions src/initialize_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static inline struct SwiftNetServer* const construct_server(const bool loopback,
UNLOCK_ATOMIC_DATA_TYPE(&new_server->packet_queue.locked);
UNLOCK_ATOMIC_DATA_TYPE(&new_server->packet_callback_queue.locked);

atomic_store_explicit(&new_server->processing_packets, true, memory_order_release);
atomic_store_explicit(&new_server->packet_handler, NULL, memory_order_release);
atomic_store_explicit(&new_server->packet_handler_user_arg, NULL, memory_order_release);
atomic_store_explicit(&new_server->closing, false, memory_order_release);
Expand Down
4 changes: 1 addition & 3 deletions src/internal/datatype_allocator.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ static inline void set_memory_status(struct SwiftNetMemoryAllocator* const memor
return;
}
}

printf("doesnt fall\n");
}

static inline bool is_already_free(struct SwiftNetMemoryAllocator* const memory_allocator, void* const memory_location) {
Expand Down Expand Up @@ -129,7 +127,7 @@ struct SwiftNetMemoryAllocatorStack* const find_free_pointer_stack(struct SwiftN
if((bitmap | invalid_bitmap) == UINT64_MAX) {
return NULL;
} else {
first_free = __builtin_ctz(~(bitmap | invalid_bitmap));
first_free = __builtin_ctzll(~(bitmap | invalid_bitmap));
}

if (first_free >= stacks_allocated) {
Expand Down
69 changes: 24 additions & 45 deletions src/internal/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <arpa/inet.h>
#include <pcap/pcap.h>
#include <stdint.h>
#include <arm_acle.h>
#include <string.h>
#include <netinet/in.h>
#include <stdatomic.h>
Expand All @@ -27,6 +28,11 @@
#define DISABLE_INTERNAL_CHECK
#endif

#define SWIFTNET_PCAP_SEND_SAFE(pcap, buffer, len) \
while(swiftnet_pcap_send(pcap, buffer, len) == -2) { \
usleep(2000); \
} \

enum RequestLostPacketsReturnType {
REQUEST_LOST_PACKETS_RETURN_UPDATED_BIT_ARRAY = 0x00,
REQUEST_LOST_PACKETS_RETURN_COMPLETED_PACKET = 0x01
Expand Down Expand Up @@ -82,8 +88,8 @@ enum RequestLostPacketsReturnType {

// Simple crc16 call with proper memory order
#define HANDLE_CHECKSUM(buffer, size, prepend_size) \
uint16_t checksum = htons(crc16(buffer, size)); \
memcpy(buffer + prepend_size + offsetof(struct ip, ip_sum), &checksum, sizeof(checksum));
const uint32_t checksum = crc32(buffer, size); \
memcpy(buffer + prepend_size + sizeof(struct ip) + offsetof(struct SwiftNetPacketInfo, checksum), &checksum, sizeof(checksum));

// Number used in ip.proto
#define PROT_NUMBER 253
Expand All @@ -99,50 +105,22 @@ enum RequestLostPacketsReturnType {

#define MIN(one, two) (one > two ? two : one)

static const uint16_t crc16_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

static inline uint16_t crc16(const uint8_t *data, size_t length) {
uint16_t crc = 0xFFFF;
static inline uint32_t crc32(uint8_t* data, uint32_t length) {
uint32_t crc = 0xFFFFFFFF;

for (size_t i = 0; i < length; i++) {
uint8_t byte = data[i];
crc = (crc >> 8) ^ crc16_table[(crc ^ byte) & 0xFF];
while (length >= 8) {
crc = __crc32d(crc, *(const uint64_t*)data);
data += 8;
length -= 8;
}

while (length > 0) {
crc = __crc32b(crc, *data);
data++;
length--;
}

return crc ^ 0xFFFF;
return ~crc;
}

enum StackCreatingState {
Expand Down Expand Up @@ -325,7 +303,8 @@ static inline struct SwiftNetPacketInfo construct_packet_info(const uint32_t pac
.chunk_amount = chunk_amount,
.chunk_index = chunk_index,
.maximum_transmission_unit = maximum_transmission_unit,
.port_info = port_info
.port_info = port_info,
.checksum = 0x00
};
}

Expand All @@ -339,7 +318,7 @@ static struct ip construct_ip_header(struct in_addr destination_addr, const uint
.ip_id = htons(packet_id), // Packet id
.ip_off = htons(0), // Not used
.ip_ttl = 64,// Time to live
.ip_sum = htons(0), // Checksum
.ip_sum = htons(0), // not used!!
.ip_src = private_ip_address, // Source ip
.ip_dst = destination_addr // Destination ip
};
Expand Down
1 change: 1 addition & 0 deletions src/internal/pcap_open.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "internal.h"
#include <pcap/pcap.h>

pcap_t* swiftnet_pcap_open(const char* interface) {
char errbuf[PCAP_ERRBUF_SIZE];
Expand Down
10 changes: 9 additions & 1 deletion src/internal/pcap_send.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#include "internal.h"
#include <errno.h>
#include <pcap/pcap.h>

int swiftnet_pcap_send(pcap_t *pcap, const u_char *data, int len) {
if (pcap_inject(pcap, data, len) == -1) {
int ret = pcap_inject(pcap, data, len);

if (ret == -1) {
if (errno == ENOBUFS) {
return -2;
}

PRINT_ERROR("inject error: %s", pcap_geterr(pcap));
return -1;
}
Expand Down
12 changes: 7 additions & 5 deletions src/memory_cleanup_background_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@ void* memory_cleanup_background_service() {

gettimeofday(&end, NULL);

uint32_t diff_us = (uint32_t)((end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec));
int64_t elapsed_us = (int64_t)(end.tv_sec - start.tv_sec) * 1000000LL + (end.tv_usec - start.tv_usec);

if (diff_us > PACKET_HISTORY_STORE_TIME * 1000000) {
continue;
}
if (elapsed_us < 0) elapsed_us = 0;

uint64_t target_us = (uint64_t)PACKET_HISTORY_STORE_TIME * 1000000ULL;

usleep((PACKET_HISTORY_STORE_TIME * 1000000) - diff_us);
if ((uint64_t)elapsed_us < target_us) {
usleep(target_us - (uint64_t)elapsed_us);
}
}

return NULL;
Expand Down
Loading
Loading