Driver: Shaper: Rework packets processing

This commit is contained in:
Nodir Temirkhodjaev 2024-02-16 19:46:41 +03:00
parent 6cec5d5029
commit e880ea9ae5
10 changed files with 169 additions and 44 deletions

View File

@ -19,6 +19,7 @@ SOURCES += \
fortscb.c \ fortscb.c \
fortstat.c \ fortstat.c \
forttds.c \ forttds.c \
fortthr.c \
forttlsf.c \ forttlsf.c \
forttmr.c \ forttmr.c \
forttrace.c \ forttrace.c \
@ -57,6 +58,7 @@ HEADERS += \
fortscb.h \ fortscb.h \
fortstat.h \ fortstat.h \
forttds.h \ forttds.h \
fortthr.h \
forttlsf.h \ forttlsf.h \
forttmr.h \ forttmr.h \
forttrace.h \ forttrace.h \

View File

@ -26,7 +26,6 @@ typedef enum FORT_FUNC_ID {
FORT_DEVICE_LOAD, FORT_DEVICE_LOAD,
FORT_DEVICE_UNLOAD, FORT_DEVICE_UNLOAD,
FORT_PACKET_INJECT_COMPLETE, FORT_PACKET_INJECT_COMPLETE,
FORT_SHAPER_TIMER_PROCESS,
FORT_SYSCB_POWER, FORT_SYSCB_POWER,
FORT_SYSCB_TIME, FORT_SYSCB_TIME,
FORT_TIMER_CALLBACK, FORT_TIMER_CALLBACK,

View File

@ -29,6 +29,7 @@
#include "fortps.c" #include "fortps.c"
#include "fortstat.c" #include "fortstat.c"
#include "fortscb.c" #include "fortscb.c"
#include "fortthr.c"
#include "forttmr.c" #include "forttmr.c"
#include "forttrace.c" #include "forttrace.c"
#include "fortutl.c" #include "fortutl.c"

View File

@ -17,6 +17,16 @@
typedef void FORT_SHAPER_PACKET_FOREACH_FUNC(PFORT_SHAPER, PFORT_FLOW_PACKET); typedef void FORT_SHAPER_PACKET_FOREACH_FUNC(PFORT_SHAPER, PFORT_FLOW_PACKET);
static UCHAR fort_shaper_flags_set(PFORT_SHAPER shaper, UCHAR flags, BOOL on)
{
return on ? InterlockedOr8(&shaper->flags, flags) : InterlockedAnd8(&shaper->flags, ~flags);
}
static UCHAR fort_shaper_flags(PFORT_SHAPER shaper)
{
return fort_shaper_flags_set(shaper, 0, TRUE);
}
static LONG fort_shaper_io_bits_exchange(volatile LONG *io_bits, LONG v) static LONG fort_shaper_io_bits_exchange(volatile LONG *io_bits, LONG v)
{ {
return InterlockedExchange(io_bits, v); return InterlockedExchange(io_bits, v);
@ -83,15 +93,10 @@ inline static BOOL fort_packet_is_ipsec_tunneled(PCFORT_CALLOUT_ARG ca)
return info.isTunnelMode && !info.isDeTunneled; return info.isTunnelMode && !info.isDeTunneled;
} }
static ULONG fort_packet_data_length(const PNET_BUFFER_LIST netBufList) inline static ULONG fort_packet_data_length(PCFORT_CALLOUT_ARG ca)
{ {
ULONG data_length = 0; PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(ca->netBufList);
const ULONG data_length = NET_BUFFER_DATA_LENGTH(netBuf);
PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList);
while (netBuf != NULL) {
data_length += NET_BUFFER_DATA_LENGTH(netBuf);
netBuf = NET_BUFFER_NEXT_NB(netBuf);
}
return data_length; return data_length;
} }
@ -578,14 +583,15 @@ static void fort_shaper_queue_process_bandwidth(
{ {
const UINT64 bps = queue->limit.bps; const UINT64 bps = queue->limit.bps;
/* Advance the available bytes */
const UINT64 accumulated =
((now.QuadPart - queue->last_tick.QuadPart) * bps) / shaper->qpcFrequency.QuadPart;
queue->available_bytes += accumulated;
if (fort_shaper_packet_list_is_empty(&queue->bandwidth_list) if (fort_shaper_packet_list_is_empty(&queue->bandwidth_list)
&& queue->available_bytes > FORT_QUEUE_INITIAL_TOKEN_COUNT) { && queue->available_bytes > FORT_QUEUE_INITIAL_TOKEN_COUNT) {
queue->available_bytes = FORT_QUEUE_INITIAL_TOKEN_COUNT; queue->available_bytes = FORT_QUEUE_INITIAL_TOKEN_COUNT;
} else {
/* Advance the available bytes */
const UINT64 accumulated =
((now.QuadPart - queue->last_tick.QuadPart) * bps) / shaper->qpcFrequency.QuadPart;
queue->available_bytes += accumulated;
} }
queue->last_tick = now; queue->last_tick = now;
@ -598,11 +604,13 @@ static void fort_shaper_queue_process_bandwidth(
PFORT_FLOW_PACKET pkt_tail = NULL; PFORT_FLOW_PACKET pkt_tail = NULL;
PFORT_FLOW_PACKET pkt = pkt_chain; PFORT_FLOW_PACKET pkt = pkt_chain;
do { do {
if (bps != 0LL && queue->available_bytes < pkt->data_length) const UINT64 pkt_length = pkt->data_length;
if (bps != 0LL && queue->available_bytes < pkt_length)
break; break;
queue->available_bytes -= pkt->data_length; queue->available_bytes -= pkt_length;
queue->queued_bytes -= pkt->data_length; queue->queued_bytes -= pkt_length;
pkt->latency_start = now; pkt->latency_start = now;
@ -626,6 +634,12 @@ static PFORT_FLOW_PACKET fort_shaper_queue_process_latency(
const UINT32 latency_ms = queue->limit.latency_ms; const UINT32 latency_ms = queue->limit.latency_ms;
if (latency_ms == 0) {
fort_shaper_packet_list_cut_chain(&queue->latency_list, queue->latency_list.packet_tail);
return pkt_chain;
}
const UINT64 qpcFrequency = shaper->qpcFrequency.QuadPart; const UINT64 qpcFrequency = shaper->qpcFrequency.QuadPart;
const UINT64 qpcFrequencyHalfMs = qpcFrequency / 2000LL; const UINT64 qpcFrequencyHalfMs = qpcFrequency / 2000LL;
@ -786,17 +800,12 @@ static void fort_shaper_free_queues(PFORT_SHAPER shaper)
} }
} }
static void fort_shaper_timer_start(PFORT_SHAPER shaper) inline static void fort_shaper_thread_set_event(PFORT_SHAPER shaper)
{ {
const ULONG active_io_bits = fort_shaper_io_bits(&shaper->active_io_bits); KeSetEvent(&shaper->thread_event, IO_NO_INCREMENT, FALSE);
if (active_io_bits == 0)
return;
fort_timer_set_running(&shaper->timer, /*run=*/TRUE);
} }
inline static ULONG fort_shaper_timer_process_queues(PFORT_SHAPER shaper, ULONG active_io_bits) inline static ULONG fort_shaper_thread_process_queues(PFORT_SHAPER shaper, ULONG active_io_bits)
{ {
ULONG new_active_io_bits = 0; ULONG new_active_io_bits = 0;
@ -821,25 +830,50 @@ inline static ULONG fort_shaper_timer_process_queues(PFORT_SHAPER shaper, ULONG
return new_active_io_bits; return new_active_io_bits;
} }
static void fort_shaper_timer_process(void) inline static BOOL fort_shaper_thread_process(PFORT_SHAPER shaper)
{ {
FORT_CHECK_STACK(FORT_SHAPER_TIMER_PROCESS);
PFORT_SHAPER shaper = &fort_device()->shaper;
ULONG active_io_bits = ULONG active_io_bits =
fort_shaper_io_bits_set(&shaper->active_io_bits, FORT_PACKET_FLUSH_ALL, FALSE); fort_shaper_io_bits_set(&shaper->active_io_bits, FORT_PACKET_FLUSH_ALL, FALSE);
if (active_io_bits == 0) if (active_io_bits == 0)
return; return FALSE;
active_io_bits = fort_shaper_timer_process_queues(shaper, active_io_bits); active_io_bits = fort_shaper_thread_process_queues(shaper, active_io_bits);
if (active_io_bits != 0) { if (active_io_bits != 0) {
fort_shaper_io_bits_set(&shaper->active_io_bits, active_io_bits, TRUE); fort_shaper_io_bits_set(&shaper->active_io_bits, active_io_bits, TRUE);
fort_shaper_timer_start(shaper); return TRUE;
} }
return FALSE;
}
static void fort_shaper_thread_loop(PVOID context)
{
PFORT_SHAPER shaper = context;
PKEVENT thread_event = &shaper->thread_event;
LARGE_INTEGER due;
due.QuadPart = 1LL * -10000LL /* ms -> us */;
PLARGE_INTEGER timeout = NULL;
do {
KeWaitForSingleObject(thread_event, Executive, KernelMode, FALSE, timeout);
const BOOL is_active = fort_shaper_thread_process(shaper);
timeout = is_active ? &due : NULL;
} while ((fort_shaper_flags(shaper) & FORT_SHAPER_CLOSED) == 0);
}
static void fort_shaper_thread_close(PFORT_SHAPER shaper)
{
fort_shaper_thread_set_event(shaper);
fort_thread_wait(&shaper->thread);
} }
inline static PFORT_FLOW_PACKET fort_shaper_flush_queues(PFORT_SHAPER shaper, UINT32 group_io_bits) inline static PFORT_FLOW_PACKET fort_shaper_flush_queues(PFORT_SHAPER shaper, UINT32 group_io_bits)
@ -889,13 +923,16 @@ FORT_API void fort_shaper_open(PFORT_SHAPER shaper)
KeInitializeSpinLock(&shaper->lock); KeInitializeSpinLock(&shaper->lock);
fort_timer_open( KeInitializeEvent(&shaper->thread_event, SynchronizationEvent, FALSE);
&shaper->timer, /*period(ms)=*/1, FORT_TIMER_ONESHOT, &fort_shaper_timer_process);
fort_thread_run(&shaper->thread, &fort_shaper_thread_loop, shaper);
} }
FORT_API void fort_shaper_close(PFORT_SHAPER shaper) FORT_API void fort_shaper_close(PFORT_SHAPER shaper)
{ {
fort_timer_close(&shaper->timer); fort_shaper_flags_set(shaper, FORT_SHAPER_CLOSED, TRUE);
fort_shaper_thread_close(shaper);
fort_shaper_drop_packets(shaper); fort_shaper_drop_packets(shaper);
fort_shaper_free_queues(shaper); fort_shaper_free_queues(shaper);
@ -1020,11 +1057,12 @@ inline static NTSTATUS fort_shaper_packet_queue(
return STATUS_NO_SUCH_GROUP; return STATUS_NO_SUCH_GROUP;
/* Calculate the Packets' Data Length */ /* Calculate the Packets' Data Length */
const ULONG data_length = fort_packet_data_length(ca->netBufList); const ULONG data_length = fort_packet_data_length(ca);
/* Check the Queue for new Packet */ /* Check the Queue for new Packet */
if (!fort_shaper_packet_queue_check_packet(queue, data_length)) if (!fort_shaper_packet_queue_check_packet(queue, data_length)) {
return STATUS_SUCCESS; /* drop the packet */ return STATUS_SUCCESS; /* drop the packet */
}
/* Create the Packet */ /* Create the Packet */
PFORT_FLOW_PACKET pkt = fort_shaper_packet_get(shaper); PFORT_FLOW_PACKET pkt = fort_shaper_packet_get(shaper);
@ -1048,8 +1086,8 @@ inline static NTSTATUS fort_shaper_packet_queue(
/* Packets in transport layer must be re-injected in DCP due to locking */ /* Packets in transport layer must be re-injected in DCP due to locking */
fort_shaper_io_bits_set(&shaper->active_io_bits, queue_bit, TRUE); fort_shaper_io_bits_set(&shaper->active_io_bits, queue_bit, TRUE);
/* Start the Timer */ /* Process the queued packets in thread */
fort_shaper_timer_start(shaper); fort_shaper_thread_set_event(shaper);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View File

@ -6,7 +6,7 @@
#include "common/fortconf.h" #include "common/fortconf.h"
#include "fortcoutarg.h" #include "fortcoutarg.h"
#include "forttds.h" #include "forttds.h"
#include "forttmr.h" #include "fortthr.h"
#define FORT_PACKET_QUEUE_BAD_INDEX ((UINT16) -1) #define FORT_PACKET_QUEUE_BAD_INDEX ((UINT16) -1)
@ -129,8 +129,12 @@ typedef struct fort_pending
KSPIN_LOCK lock; KSPIN_LOCK lock;
} FORT_PENDING, *PFORT_PENDING; } FORT_PENDING, *PFORT_PENDING;
#define FORT_SHAPER_CLOSED 0x01
typedef struct fort_shaper typedef struct fort_shaper
{ {
UCHAR volatile flags;
UINT32 limit_io_bits; UINT32 limit_io_bits;
LONG volatile group_io_bits; LONG volatile group_io_bits;
@ -139,7 +143,8 @@ typedef struct fort_shaper
ULONG randomSeed; ULONG randomSeed;
LARGE_INTEGER qpcFrequency; LARGE_INTEGER qpcFrequency;
FORT_TIMER timer; KEVENT thread_event;
FORT_THREAD thread;
PFORT_FLOW_PACKET packet_free; PFORT_FLOW_PACKET packet_free;
tommy_arrayof packets; tommy_arrayof packets;

36
src/driver/fortthr.c Normal file
View File

@ -0,0 +1,36 @@
/* Fort Firewall Thread */
#include "fortthr.h"
#include "fortcb.h"
#include "fortdbg.h"
FORT_API NTSTATUS fort_thread_run(PFORT_THREAD thread, PKSTART_ROUTINE routine, PVOID context)
{
NTSTATUS status;
thread->thread_obj = NULL;
HANDLE hThread;
status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, routine, context);
if (!NT_SUCCESS(status))
return status;
status = ObReferenceObjectByHandle(
hThread, THREAD_ALL_ACCESS, NULL, KernelMode, &thread->thread_obj, NULL);
ZwClose(hThread);
return status;
}
FORT_API void fort_thread_wait(PFORT_THREAD thread)
{
if (thread->thread_obj == NULL)
return;
KeWaitForSingleObject(thread->thread_obj, Executive, KernelMode, FALSE, NULL);
ObDereferenceObject(thread->thread_obj);
thread->thread_obj = NULL;
}

23
src/driver/fortthr.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef FORTTHR_H
#define FORTTHR_H
#include "fortdrv.h"
typedef struct fort_thread
{
PVOID thread_obj;
} FORT_THREAD, *PFORT_THREAD;
#if defined(__cplusplus)
extern "C" {
#endif
FORT_API NTSTATUS fort_thread_run(PFORT_THREAD thread, PKSTART_ROUTINE routine, PVOID context);
FORT_API void fort_thread_wait(PFORT_THREAD thread);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // FORTTHR_H

View File

@ -315,6 +315,20 @@ void IoQueueWorkItemEx(
UNUSED(context); UNUSED(context);
} }
NTSTATUS PsCreateSystemThread(PHANDLE threadHandle, ULONG desiredAccess,
POBJECT_ATTRIBUTES objectAttributes, HANDLE processHandle, PVOID clientId,
PKSTART_ROUTINE startRoutine, PVOID startContext)
{
UNUSED(threadHandle);
UNUSED(desiredAccess);
UNUSED(objectAttributes);
UNUSED(processHandle);
UNUSED(clientId);
UNUSED(startRoutine);
UNUSED(startContext);
return STATUS_SUCCESS;
}
LARGE_INTEGER KeQueryPerformanceCounter(PLARGE_INTEGER performanceFrequency) LARGE_INTEGER KeQueryPerformanceCounter(PLARGE_INTEGER performanceFrequency)
{ {
UNUSED(performanceFrequency); UNUSED(performanceFrequency);

View File

@ -246,6 +246,9 @@ typedef IO_WORKITEM_ROUTINE *PIO_WORKITEM_ROUTINE;
typedef VOID IO_WORKITEM_ROUTINE_EX(PVOID IoObject, PVOID Context, PIO_WORKITEM IoWorkItem); typedef VOID IO_WORKITEM_ROUTINE_EX(PVOID IoObject, PVOID Context, PIO_WORKITEM IoWorkItem);
typedef IO_WORKITEM_ROUTINE_EX *PIO_WORKITEM_ROUTINE_EX; typedef IO_WORKITEM_ROUTINE_EX *PIO_WORKITEM_ROUTINE_EX;
typedef VOID KSTART_ROUTINE(PVOID startContext);
typedef KSTART_ROUTINE *PKSTART_ROUTINE;
typedef struct typedef struct
{ {
short Year; // range [1601...] short Year; // range [1601...]
@ -393,6 +396,10 @@ FORT_API void IoQueueWorkItem(
FORT_API void IoQueueWorkItemEx( FORT_API void IoQueueWorkItemEx(
PIO_WORKITEM workItem, PIO_WORKITEM_ROUTINE_EX routine, int queueType, PVOID context); PIO_WORKITEM workItem, PIO_WORKITEM_ROUTINE_EX routine, int queueType, PVOID context);
FORT_API NTSTATUS PsCreateSystemThread(PHANDLE threadHandle, ULONG desiredAccess,
POBJECT_ATTRIBUTES objectAttributes, HANDLE processHandle, PVOID clientId,
PKSTART_ROUTINE startRoutine, PVOID startContext);
FORT_API LARGE_INTEGER KeQueryPerformanceCounter(PLARGE_INTEGER performanceFrequency); FORT_API LARGE_INTEGER KeQueryPerformanceCounter(PLARGE_INTEGER performanceFrequency);
FORT_API void KeQuerySystemTime(PLARGE_INTEGER time); FORT_API void KeQuerySystemTime(PLARGE_INTEGER time);

View File

@ -664,7 +664,7 @@ void ConfUtil::writeLimit(fort_speed_limit *limit, quint32 kBits, quint32 buffer
limit->plr = packetLoss; limit->plr = packetLoss;
limit->latency_ms = latencyMsec; limit->latency_ms = latencyMsec;
limit->buffer_bytes = bufferSize; limit->buffer_bytes = bufferSize;
limit->bps = quint64(kBits) * (1024 / 8); limit->bps = quint64(kBits) * (1024LL / 8); /* to bytes per second */
} }
void ConfUtil::writeAddressRanges(char **data, const addrranges_arr_t &addressRanges) void ConfUtil::writeAddressRanges(char **data, const addrranges_arr_t &addressRanges)