Driver: Improve speed limiting by deferring ACK packets.

This commit is contained in:
Nodir Temirkhodjaev 2018-02-18 08:17:47 +05:00
parent 3478c67964
commit 1a5c45472c
3 changed files with 56 additions and 41 deletions

View File

@ -436,35 +436,36 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
FWPS_CLASSIFY_OUT0 *classifyOut, FWPS_CLASSIFY_OUT0 *classifyOut,
int ipProtoField, BOOL inbound) int ipProtoField, BOOL inbound)
{ {
PNET_BUFFER netBuf;
const IPPROTO ip_proto = (IPPROTO) inFixedValues->incomingValue[ const IPPROTO ip_proto = (IPPROTO) inFixedValues->incomingValue[
ipProtoField].value.uint8; ipProtoField].value.uint8;
const BOOL is_udp = (ip_proto == IPPROTO_UDP); const BOOL is_udp = (ip_proto == IPPROTO_UDP);
if (!(is_udp || FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, if (!(is_udp || FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)) FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
&& netBufList != NULL) { && netBufList != NULL
&& (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) {
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext; PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
const BOOL ignore_tcp_rst = inbound && g_device->conf_flags.ignore_tcp_rst; const BOOL ignore_tcp_rst = inbound && g_device->conf_flags.ignore_tcp_rst;
const BOOL defer_flow = flow->opt.speed_limit && !g_device->power_off
&& (inbound ? flow->opt.defer_in : flow->opt.defer_out);
if (ignore_tcp_rst || defer_flow) { const UINT32 defer_flag = inbound
const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList); ? FORT_STAT_FLOW_DEFER_IN : FORT_STAT_FLOW_DEFER_OUT;
const UINT32 flow_flags = FORT_STAT_FLOW_SPEED_LIMIT | defer_flag;
const BOOL defer_flow = (flow->opt.flags & flow_flags) == flow_flags
&& !g_device->power_off;
/* Position in the packet data:
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
*/
const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER);
if (ignore_tcp_rst) {
TCP_HEADER buf; TCP_HEADER buf;
PTCP_HEADER tcpHeader; PTCP_HEADER tcpHeader;
UINT32 tcpFlags; UINT32 tcpFlags;
if (netBuf == NULL)
goto permit;
/* Position in the packet data:
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
*/
const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER);
if (headerOffset != 0) { if (headerOffset != 0) {
NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL); NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL);
} }
@ -479,22 +480,20 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
if (tcpHeader == NULL) if (tcpHeader == NULL)
goto permit; goto permit;
if (ignore_tcp_rst && (tcpFlags & TCP_FLAG_RST)) if (tcpFlags & TCP_FLAG_RST)
goto block;
}
if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) {
const NTSTATUS status = fort_defer_add(&g_device->defer,
inFixedValues, inMetaValues, netBufList, inbound);
if (NT_SUCCESS(status))
goto block; goto block;
if (defer_flow //&& (tcpFlags & TCP_FLAG_ACK) if (status == STATUS_CANT_TERMINATE_SELF) {
&& NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) { /* Clear ACK deferring */
NTSTATUS status; flow->opt.flags &= ~defer_flag;
status = fort_defer_add(&g_device->defer, inFixedValues, inMetaValues,
netBufList, inbound);
if (!NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: Transport Classify: Defer error: %x\n", status);
}
goto block;
} }
} }
} }

View File

@ -120,6 +120,16 @@ fort_defer_add (PFORT_DEFER defer,
if (defer->injection4_id == INVALID_HANDLE_VALUE) if (defer->injection4_id == INVALID_HANDLE_VALUE)
return STATUS_FWP_TCPIP_NOT_READY; return STATUS_FWP_TCPIP_NOT_READY;
/* Skip self injected packet */
{
const FWPS_PACKET_INJECTION_STATE state = FwpsQueryPacketInjectionState0(
defer->injection4_id, netBufList, NULL);
if (state == FWPS_PACKET_INJECTED_BY_SELF
|| state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
return STATUS_CANT_TERMINATE_SELF;
}
/* Skip IpSec protected packet */ /* Skip IpSec protected packet */
if (inbound) { if (inbound) {
FWPS_PACKET_LIST_INFORMATION info; FWPS_PACKET_LIST_INFORMATION info;
@ -156,6 +166,7 @@ fort_defer_add (PFORT_DEFER defer,
defer->packet_head = defer->packet_tail = pkt; defer->packet_head = defer->packet_tail = pkt;
} else { } else {
defer->packet_tail->next = pkt; defer->packet_tail->next = pkt;
defer->packet_tail = pkt;
} }
pkt->inbound = inbound; pkt->inbound = inbound;

View File

@ -28,10 +28,12 @@ typedef struct fort_stat_proc {
}; };
} FORT_STAT_PROC, *PFORT_STAT_PROC; } FORT_STAT_PROC, *PFORT_STAT_PROC;
#define FORT_STAT_FLOW_SPEED_LIMIT 0x01
#define FORT_STAT_FLOW_DEFER_IN 0x02
#define FORT_STAT_FLOW_DEFER_OUT 0x04
typedef struct fort_stat_flow_opt { typedef struct fort_stat_flow_opt {
UCHAR speed_limit : 1; UCHAR volatile flags;
UCHAR defer_in : 1;
UCHAR defer_out : 1;
UCHAR group_index; UCHAR group_index;
UINT16 proc_index; UINT16 proc_index;
} FORT_STAT_FLOW_OPT, *PFORT_STAT_FLOW_OPT; } FORT_STAT_FLOW_OPT, *PFORT_STAT_FLOW_OPT;
@ -45,7 +47,7 @@ typedef struct fort_stat_flow {
#if defined(_WIN64) #if defined(_WIN64)
UINT64 flow_id; UINT64 flow_id;
#else #else
FORT_STAT_FLOW_OPT volatile opt; FORT_STAT_FLOW_OPT opt;
#endif #endif
void *data; void *data;
}; };
@ -346,8 +348,7 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
fort_stat_proc_inc(stat, proc_index); fort_stat_proc_inc(stat, proc_index);
} }
flow->opt.speed_limit = (UCHAR) speed_limit; flow->opt.flags = (speed_limit ? FORT_STAT_FLOW_SPEED_LIMIT : 0);
flow->opt.defer_in = flow->opt.defer_out = FALSE;
flow->opt.group_index = group_index; flow->opt.group_index = group_index;
flow->opt.proc_index = proc_index; flow->opt.proc_index = proc_index;
@ -518,7 +519,7 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
/* Add traffic to process */ /* Add traffic to process */
*proc_bytes += data_len; *proc_bytes += data_len;
if (flow->opt.speed_limit) { if (flow->opt.flags & FORT_STAT_FLOW_SPEED_LIMIT) {
const UCHAR group_index = flow->opt.group_index; const UCHAR group_index = flow->opt.group_index;
const PFORT_CONF_LIMIT group_limit = &stat->limits[group_index]; const PFORT_CONF_LIMIT group_limit = &stat->limits[group_index];
const UINT32 limit_bytes = inbound ? group_limit->in_bytes const UINT32 limit_bytes = inbound ? group_limit->in_bytes
@ -528,7 +529,7 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
PFORT_STAT_GROUP group = &stat->groups[group_index]; PFORT_STAT_GROUP group = &stat->groups[group_index];
UINT32 *group_bytes = inbound ? &group->traf.in_bytes UINT32 *group_bytes = inbound ? &group->traf.in_bytes
: &group->traf.out_bytes; : &group->traf.out_bytes;
UCHAR defer_flow = TRUE; BOOL defer_flow = TRUE;
if (*group_bytes < limit_bytes) { if (*group_bytes < limit_bytes) {
/* Add traffic to app. group */ /* Add traffic to app. group */
@ -540,10 +541,14 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
} }
/* Defer ACK */ /* Defer ACK */
if (inbound) { {
flow->opt.defer_out = defer_flow; const UINT32 defer_flag = inbound
} else { ? FORT_STAT_FLOW_DEFER_OUT : FORT_STAT_FLOW_DEFER_IN;
flow->opt.defer_in = defer_flow;
if (defer_flow)
flow->opt.flags |= defer_flag;
else
flow->opt.flags &= ~defer_flag;
} }
} }
} }