/*++ Copyright (c) 1996-1999 Microsoft Corporation Module Name: pktsched.h Abstract: defines for packet scheduler component interface Author: Revision History: --*/ #ifndef _PKTSCHED_H_ #define _PKTSCHED_H_ // // forwards // /* typedef struct _PSI_INFO; typedef struct _PS_PROFILE; typedef struct _PS_PIPE_CONTEXT; typedef struct _PS_FLOW_CONTEXT; typedef struct _PS_DEBUG_INFO; */ // // Component registration function exported by PSched // // // Context info passed to each component during pipe initialization. The PS // allocates one PS_PIPE_CONTEXT struct for each component. The size of an // individual component's struct is indicated by the component during registration, // and must be at least as large as sizeof(PS_PIPE_CONTEXT). // Each component's context area begins with the struct defined below, and the // component-specific data follows. // // Note : This structure has to be word aligned. // typedef struct _PS_PIPE_CONTEXT { // NextComponentContext - Pointer to next component's pipe-specific data // PrevComponentContext - Pointer to previous component's pipe-specific data // NextComponent - Function info about next component in pipeline // PacketReservedOffset - Offset to packet reserved bytes for this component struct _PS_PIPE_CONTEXT *NextComponentContext; struct _PS_PIPE_CONTEXT *PrevComponentContext; struct _PSI_INFO *NextComponent; ULONG PacketReservedOffset; } PS_PIPE_CONTEXT, *PPS_PIPE_CONTEXT; // // Context info passed to each component during flow initialization. The PS // allocates one PS_FLOW_CONTEXT struct for each component. The size of an // individual component's struct is indicated by the component during registration, // and must be at least as large as sizeof(PS_FLOW_CONTEXT). // Each component's context area begins with the struct defined below, and the // component-specific data follows. // typedef struct _PS_FLOW_CONTEXT { // NextComponentContext - Pointer to next component's flow-specific data // PrevComponentContext - Pointer to previous component's flow-specific data struct _PS_FLOW_CONTEXT *NextComponentContext; struct _PS_FLOW_CONTEXT *PrevComponentContext; } PS_FLOW_CONTEXT, *PPS_FLOW_CONTEXT, PS_CLASS_MAP_CONTEXT, *PPS_CLASS_MAP_CONTEXT; // // Packet Information Block. This structure can be found // at offset zero from the packet's ProtocolReserved area. // typedef struct _PACKET_INFO_BLOCK { // SchedulerLinks - Linkage in scheduling component list // PacketLength - Length of packet, non including MAC header // ConformanceTime - Token Bucket Conformance Time // DelayTime - Time at which packet is eligible for sending // FlowContext - Flow context area for the convenience of the scheduling // components. May be used by the scheduling component // while the packet is being processed by that component. // ClassMapContext - Class Map context area for convenience of scheduling // components. May be used by the scheduling component // when the packet is being processed by that component. // IpHdr - points to the IP transport header. This is used by the // sequencer to stamp the IP packet with the non conforming // TOS byte. We store a pointer here because we have already // done the dirty work of getting to the buffer in MpSend. // This will be 0 for non IP packets, in which case the // sequencer need not do anything. // IPPrecedenceByteNonConforming - The TOS setting for non conforming packets. // UserPriorityNonConforming - 802.1p setting for non conforming packets. LIST_ENTRY SchedulerLinks; ULONG PacketLength; LARGE_INTEGER ConformanceTime; LARGE_INTEGER DelayTime; HANDLE FlowContext; HANDLE ClassMapContext; ULONG IPHeaderOffset; IPHeader *IPHdr; PNDIS_PACKET NdisPacket; UCHAR TOSNonConforming; UCHAR UserPriorityNonConforming; } PACKET_INFO_BLOCK, *PPACKET_INFO_BLOCK; // // Prototypes for PS routines made available to scheduling components. // typedef VOID (*PS_DROP_PACKET)( IN HANDLE PsPipeContext, IN HANDLE PsFlowContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ); typedef HANDLE (*PS_NDIS_PIPE_HANDLE)( IN HANDLE PsPipeContext ); typedef HANDLE (*PS_NDIS_FLOW_HANDLE)( IN HANDLE PsFlowContext ); typedef VOID (*PS_GET_TIMER_INFO)( OUT PULONG TimerResolution // Timer resolution in system time units ); typedef struct _PS_PROCS { PS_DROP_PACKET DropPacket; PS_NDIS_PIPE_HANDLE NdisPipeHandle; PS_GET_TIMER_INFO GetTimerInfo; } PS_PROCS, *PPS_PROCS; // // Upcall information passed to next component // typedef VOID (*PSU_SEND_COMPLETE)( IN PPS_PIPE_CONTEXT PipeContext, IN PNDIS_PACKET Packet ); typedef struct _PS_UPCALLS { PSU_SEND_COMPLETE SendComplete; PPS_PIPE_CONTEXT PipeContext; } PS_UPCALLS, *PPS_UPCALLS; // // Pipe parameters // typedef struct _PS_PIPE_PARAMETERS { // Bandwidth - In bytes/sec // MTUSize - Maximum frame size // HeaderSize - Number of bytes in header // Flags - See below // MaxOutstandingSends - Maximum sends that can be pending concurrently // SDModeControlledLoad - Default handling of non-conforming controlled load traffic // SDModeGuaranteed - Default handling of non-conforming guaranteed service traffic // SDModeNetworkControl - Default handling of non-conforming NetworkControl service traffic // SDModeQualitative - Default handling of non-conforming Qualitative service traffic // RegistryPath - Pointer to the registry path of that interface. Can be used to read reg params. ULONG Bandwidth; ULONG MTUSize; ULONG HeaderSize; ULONG Flags; ULONG MaxOutstandingSends; ULONG SDModeControlledLoad; ULONG SDModeGuaranteed; ULONG SDModeNetworkControl; ULONG SDModeQualitative; PNDIS_STRING RegistryPath; // Need this to let the scheduling components to know what kind of medium it is // NDIS_MEDIUM MediaType; // Wan Or anything else } PS_PIPE_PARAMETERS, *PPS_PIPE_PARAMETERS; // Pipe flags #define PS_DISABLE_DRR 2 #define PS_INTERMEDIATE_SYS 4 // // function typedefs for the scheduler entry points // typedef NDIS_STATUS (*PS_INITIALIZE_PIPE)( IN HANDLE PsPipeContext, IN PPS_PIPE_PARAMETERS PipeParameters, IN PPS_PIPE_CONTEXT ComponentPipeContext, IN PPS_PROCS PsProcs, IN PPS_UPCALLS Upcalls ); typedef NDIS_STATUS (*PS_MODIFY_PIPE)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_PIPE_PARAMETERS PipeParameters ); typedef VOID (*PS_DELETE_PIPE)( IN PPS_PIPE_CONTEXT PipeContext ); typedef NDIS_STATUS (*PS_CREATE_FLOW)( IN PPS_PIPE_CONTEXT PipeContext, IN HANDLE PsFlowContext, IN PCO_CALL_PARAMETERS CallParameters, IN PPS_FLOW_CONTEXT ComponentFlowContext ); typedef NDIS_STATUS (*PS_MODIFY_FLOW)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN PCO_CALL_PARAMETERS CallParameters ); typedef VOID (*PS_DELETE_FLOW)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext ); typedef VOID (*PS_EMPTY_FLOW)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext ); typedef BOOLEAN (*PS_SUBMIT_PACKET)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN PPS_CLASS_MAP_CONTEXT ClassMapContext, IN PPACKET_INFO_BLOCK PktInfo); typedef BOOLEAN (*PS_RECEIVE_PACKET)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN PPS_CLASS_MAP_CONTEXT ClassMapContext, IN PNDIS_PACKET Packet, IN NDIS_MEDIUM Medium ); typedef BOOLEAN (*PS_RECEIVE_INDICATION)( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN PPS_CLASS_MAP_CONTEXT ClassMapContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize, IN UINT TransportHeaderOffset ); typedef VOID (*PS_SET_INFORMATION) ( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN NDIS_OID Oid, IN ULONG BufferSize, IN PVOID Buffer ); typedef VOID (*PS_QUERY_INFORMATION) ( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_FLOW_CONTEXT FlowContext, IN NDIS_OID Oid, IN ULONG BufferSize, IN PVOID Buffer, IN OUT PULONG BytesWritten, IN OUT PULONG BytesNeeded, IN OUT PNDIS_STATUS Status); typedef NDIS_STATUS (*PS_CREATE_CLASS_MAP) ( IN PPS_PIPE_CONTEXT PipeContext, IN HANDLE PsClassMapContext, IN PTC_CLASS_MAP_FLOW ClassMap, IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext ); typedef NDIS_STATUS (*PS_DELETE_CLASS_MAP) ( IN PPS_PIPE_CONTEXT PipeContext, IN PPS_CLASS_MAP_CONTEXT ); /* End Prototypes */ // // Scheduling component registration structure. // #define PS_COMPONENT_CURRENT_VERSION 1 typedef struct _PSI_INFO { LIST_ENTRY Links; BOOLEAN Registered; BOOLEAN AddIn; USHORT Version; NDIS_STRING ComponentName; ULONG PacketReservedLength; ULONG PipeContextLength; ULONG FlowContextLength; ULONG ClassMapContextLength; ULONG SupportedOidsLength; NDIS_OID *SupportedOidList; ULONG SupportedGuidsLength; NDIS_GUID *SupportedGuidList; PS_INITIALIZE_PIPE InitializePipe; PS_MODIFY_PIPE ModifyPipe; PS_DELETE_PIPE DeletePipe; PS_CREATE_FLOW CreateFlow; PS_MODIFY_FLOW ModifyFlow; PS_DELETE_FLOW DeleteFlow; PS_EMPTY_FLOW EmptyFlow; PS_SUBMIT_PACKET SubmitPacket; PS_RECEIVE_PACKET ReceivePacket; PS_RECEIVE_INDICATION ReceiveIndication; PS_SET_INFORMATION SetInformation; PS_QUERY_INFORMATION QueryInformation; PS_CREATE_CLASS_MAP CreateClassMap; PS_DELETE_CLASS_MAP DeleteClassMap; } PSI_INFO, *PPSI_INFO; // // Profile registration structure // #define MAX_COMPONENT_PER_PROFILE 10 typedef struct _PS_PROFILE { LIST_ENTRY Links; USHORT UnregisteredAddInCnt; NDIS_STRING ProfileName; UINT ComponentCnt; // Allocate an extra slot for the StubComponent PPSI_INFO ComponentList[MAX_COMPONENT_PER_PROFILE + 1]; } PS_PROFILE, *PPS_PROFILE; // // Debugging support for add-in components // typedef VOID (*PS_GET_CURRENT_TIME) (PLARGE_INTEGER SysTime); typedef VOID (*PS_LOGSTRING_PROC) ( IN char *format, ... ); typedef VOID (*PS_LOGSCHED_PROC) ( IN ULONG SchedulerComponent, IN ULONG Action, IN PVOID VC, IN PNDIS_PACKET Packet, IN ULONG PacketLength, IN ULONG Priority, IN LONGLONG ArrivalTime, IN LONGLONG ConformanceTime, IN ULONG PacketsInComponent, IN ULONG BytesInComponent ); typedef VOID (*PS_LOGREC_PROC) ( IN ULONG ComponentId, IN PVOID RecordData, IN ULONG RecordLength ); typedef ULONG (*PS_GETID_PROC) ( VOID); typedef struct _PS_DEBUG_INFO { PULONG DebugLevel; PULONG DebugMask; PULONG LogTraceLevel; PULONG LogTraceMask; ULONG LogId; PS_GET_CURRENT_TIME GetCurrentTime; PS_LOGSTRING_PROC LogString; PS_LOGSCHED_PROC LogSched; PS_LOGREC_PROC LogRec; } PS_DEBUG_INFO, *PPS_DEBUG_INFO; NDIS_STATUS RegisterPsComponent( PPSI_INFO PsiComponentInfo, ULONG Size , PPS_DEBUG_INFO Dbg); // // VOID // InsertEntryList( // PLIST_ENTRY Entry, // PLIST_ENTRY EntryToInsert // ); // // insert EntryToInsert just after Entry // #define InsertEntryList( Entry, EntryToInsert ) { \ (EntryToInsert)->Flink = (Entry)->Flink; \ (Entry)->Flink = (EntryToInsert); \ (EntryToInsert)->Blink = (EntryToInsert)->Flink->Blink; \ (EntryToInsert)->Flink->Blink = (EntryToInsert); \ } #define ARP_802_ADDR_LENGTH 6 // Length of an 802 address. #define ARP_ETYPE_IP 0x800 typedef struct _ETH_HEADER { UCHAR DestAddr[ARP_802_ADDR_LENGTH]; UCHAR SrcAddr[ARP_802_ADDR_LENGTH]; USHORT Type; } ETH_HEADER, *PETH_HEADER; _inline IPHeader * GetIpHeader(ULONG TransportHeaderOffset, PNDIS_PACKET pNdisPacket) { PVOID pAddr; PNDIS_BUFFER pNdisBuf1, pNdisBuf2; UINT Len; pNdisBuf1 = pNdisPacket->Private.Head; NdisQueryBuffer(pNdisBuf1, &pAddr, &Len); while(Len <= TransportHeaderOffset) { // // Transport header is not in this buffer, // try the next buffer // TransportHeaderOffset -= Len; NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2); ASSERT(pNdisBuf2); NdisQueryBuffer(pNdisBuf2, &pAddr, &Len); pNdisBuf1 = pNdisBuf2; } return (IPHeader *)(((PUCHAR)pAddr) + TransportHeaderOffset); } // // Set TOS byte and recalculate checksum // Use incremental checksum update // RFCs 1071, 1141, 1624 // // // RFC : 1624 // HC' = ~(~HC + ~m + m'); // HC - old checksum, m - old value, m' - new value // #define SET_TOS_XSUM(Packet, pIpHdr, tos) { \ PNDIS_PACKET_EXTENSION _PktExt; \ NDIS_TCP_IP_CHECKSUM_PACKET_INFO _ChkPI; \ _PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET((Packet)); \ _ChkPI.Value = PtrToUlong(_PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo]); \ if(_ChkPI.Transmit.NdisPacketIpChecksum) { \ (pIpHdr)->iph_tos = ((pIpHdr)->iph_tos & PS_IP_DS_CODEPOINT_MASK) | (tos); \ } \ else { \ USHORT _old, _new; \ ULONG _sum; \ _old = *(USHORT *)(pIpHdr); \ (pIpHdr)->iph_tos = ((pIpHdr)->iph_tos & PS_IP_DS_CODEPOINT_MASK) | (tos); \ _new = *(USHORT *)(pIpHdr); \ _sum = ((~(pIpHdr)->iph_xsum) & 0xffff) + ((~_old) & 0xffff) + _new; \ _sum = (_sum & 0xffff) + (_sum >> 16); \ _sum += (_sum >> 16); \ (pIpHdr)->iph_xsum = (ushort) ((~_sum) & 0xffff); \ } \ } // // Number of OS time units per second // #define OS_TIME_SCALE 10000000 // // convert from OS's 100 ns to millisecs // #define OS_TIME_TO_MILLISECS(_time) ((_time)/10000) _inline VOID PsGetCurrentTime( PLARGE_INTEGER SysTime ) /*++ Routine Description: Get the current system time Arguments: Comments: 1. We need something that always increases - Hence we cannot use NdisGetCurrentSystemTime or KeQueryCurrentSystem time. Those APIs can return decreasing times (daylight savings, date/time, etc). Return Value: System time (in base OS time units) --*/ { #if defined(PERF_COUNTER) LARGE_INTEGER Now; LARGE_INTEGER Frequency; Now = KeQueryPerformanceCounter(&Frequency); SysTime->QuadPart = (Now.QuadPart * OS_TIME_SCALE) / Frequency.QuadPart; #else // // We used to use KeQueryTickCount() with KeQueryTimeIncrement(). But, if we are driving the clock at a lower // resolution, then we cannot use KeQueryTickCount, because this will always return the time based on the // maximum resolution. Therefore, we use KeQueryInterruptTime(). // SysTime->QuadPart = KeQueryInterruptTime(); #endif } #endif /* _PKTSCHED_H_ */ /* end pktsched.h */