Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2238 lines
71 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. Conformr.c
  5. Abstract:
  6. Token Bucket Conformer. This module is a scheduling component that
  7. assigns conformance times to packets, based on the token bucket
  8. algorithm.
  9. Author:
  10. Intel->YoramB->RajeshSu->SanjayKa.
  11. Environment:
  12. Kernel Mode
  13. Revision History:
  14. --*/
  15. #include "psched.h"
  16. #pragma hdrstop
  17. #ifdef QUEUE_LIMIT
  18. ULONG gPhysMemSize; // size of physical memory (in MB), used for shaper queue limit default
  19. #endif // QUEUE_LIMIT
  20. //
  21. // For maintaining shaper Pipe & Flow Stats.
  22. //
  23. #define SHAPER_AVERAGING_ARRAY_SIZE 256
  24. #define SHAPER_FLOW_AVERAGING_ARRAY_SIZE 256
  25. // The conformer's pipe information
  26. typedef struct _TBC_PIPE {
  27. // ContextInfo - Generic context info
  28. // MaxPacket - Maximum packet size for pipe
  29. // PsPipeContext - PS's pipe context value
  30. // DropPacket - PS's drop packet routine
  31. // HeaderLength - Length of MAC header for this pipe
  32. // ControlledLoadMode - Default mode for non-conforming traffic from
  33. // controlled load flows
  34. // GuaranteedMode - Default mode for non-conforming traffic from
  35. // guaranteed service flows
  36. // IntermediateSystem - TRUE if "IS" mode should be used for implementing discard semantics
  37. // Stats - Per Pipe stats.
  38. PS_PIPE_CONTEXT ContextInfo;
  39. PS_CONFORMER_STATS cStats;
  40. PS_SHAPER_STATS sStats;
  41. PRUNNING_AVERAGE PacketsInShaperAveragingArray;
  42. ULONG PacketsInShaper;
  43. ULONG MaxPacket;
  44. LIST_ENTRY ActiveFlows;
  45. ULONG TimerStatus;
  46. ULONG TimerResolution;
  47. HANDLE PsPipeContext;
  48. PPS_PROCS PsProcs;
  49. ULONG HeaderLength;
  50. ULONG ControlledLoadMode;
  51. ULONG GuaranteedMode;
  52. ULONG NetworkControlMode;
  53. ULONG Qualitative;
  54. ULONG IntermediateSystem;
  55. ULONG TimerUnloadFlag;
  56. NDIS_EVENT TimerUnloadEvent;
  57. // Need this to figure out the timer-wheel size //
  58. NDIS_MEDIUM MediaType;
  59. // Timer wheel parameters //
  60. PVOID pTimerWheel;
  61. ULONG TimerWheelShift;
  62. NDIS_MINIPORT_TIMER Timer;
  63. NDIS_SPIN_LOCK Lock;
  64. ULONG SetSlotValue;
  65. LARGE_INTEGER SetTimerValue;
  66. LARGE_INTEGER ExecTimerValue;
  67. ULONG ExecSlot;
  68. } TBC_PIPE, *PTBC_PIPE;
  69. #define TIMER_UNINITIALIZED 0
  70. #define TIMER_INACTIVE 1
  71. #define TIMER_SET 2
  72. #define TIMER_PROC_EXECUTING 3
  73. typedef enum _FLOW_STATE {
  74. TS_FLOW_CREATED = 1,
  75. TS_FLOW_DELETED
  76. } FLOW_STATE;
  77. // The conformer's flow information
  78. typedef struct _TBC_FLOW {
  79. // ContextInfo - Generic context info
  80. // Lock - Protects flow data
  81. // TokenRate - TokenRate from generic QoS
  82. // Capacity - TokenBucketSize from generic QoS
  83. // PeakRate - PeakBandwidth from generic QoS
  84. // MinPolicedUnit - MinimumPolicedUnit from generic QoS
  85. // Mode - Flow S/D mode
  86. // NoConformance - Indicates whether flow is exempt from conformance algorithm
  87. // LastConformanceTime - Absolute tb conformance time of last non-discarded packet
  88. // PeakConformanceTime - Earliest time next packet can be sent, based on peak rate
  89. // LastConformanceCredits - Number of credits at LastConformanceTime
  90. // PsFlowContext - PS's flow context value
  91. // Stats - Per flow stats.
  92. PS_FLOW_CONTEXT ContextInfo;
  93. NDIS_SPIN_LOCK Lock;
  94. ULONG Flags;
  95. LIST_ENTRY Links;
  96. ULONG Mode;
  97. ULONG Shape;
  98. LIST_ENTRY PacketQueue;
  99. LARGE_INTEGER FlowEligibilityTime;
  100. ULONG LoopCount;
  101. ULONG TokenRate;
  102. ULONG Capacity;
  103. ULONG PeakRate;
  104. ULONG MinPolicedUnit;
  105. ULONG NoConformance;
  106. LARGE_INTEGER LastConformanceTime;
  107. LARGE_INTEGER PeakConformanceTime;
  108. ULONG LastConformanceCredits;
  109. HANDLE PsFlowContext;
  110. #ifdef QUEUE_LIMIT
  111. ULONG QueueSize;
  112. ULONG QueueSizeLimit;
  113. ULONG DropOverLimitPacketsFromHead;
  114. ULONG UseDefaultQueueLimit;
  115. #endif // QUEUE_LIMIT
  116. PS_CONFORMER_STATS cStats;
  117. PS_SHAPER_STATS sStats;
  118. ULONG PacketsInShaper;
  119. PRUNNING_AVERAGE PacketsInShaperAveragingArray;
  120. FLOW_STATE State;
  121. } TBC_FLOW, *PTBC_FLOW;
  122. // Macros used during token bucket conformance calculation
  123. #define EARNED_CREDITS(_t,_r) ((ULONG)(( (_t) * (_r) ) / OS_TIME_SCALE))
  124. #define TIME_TO_EARN_CREDITS(_c,_r) (((LONGLONG)(_c) * OS_TIME_SCALE) / (_r) )
  125. #define TIME_TO_SEND(_c,_r) (((LONGLONG)(_c) * OS_TIME_SCALE) / (_r) )
  126. #define PACKET_IS_CONFORMING(_ttime, _curtime, _r) \
  127. ( ((_ttime).QuadPart - (_curtime).QuadPart) <= (_r) )
  128. #define LOCK_FLOW(_f) NdisAcquireSpinLock(&(_f)->Lock)
  129. #define UNLOCK_FLOW(_f) NdisReleaseSpinLock(&(_f)->Lock)
  130. #define PacketIsEligible(_pktinfo, _flow, _curtime, _r) \
  131. ( (_pktinfo)->DelayTime.QuadPart <= ((_curtime).QuadPart + (_r)) )
  132. #define FlowIsEligible(_flow, _curtime, _r) \
  133. ( (_flow)->FlowEligibilityTime.QuadPart <= ((_curtime).QuadPart + (_r)) )
  134. #define LOCK_PIPE(_p) NdisAcquireSpinLock(&(_p)->Lock)
  135. #define UNLOCK_PIPE(_p) NdisReleaseSpinLock(&(_p)->Lock)
  136. //
  137. // Define the maximum number of time for which a packet can live in the shaper. If a packet becomes conformant at
  138. // a time that is > this value, it gets discarded. This is to prevent apps from queueing up packets in the shaper
  139. // for a very long time (and exiting immediately causing a bugcheck when the app terminates after 5 min.). Note that
  140. // this applies only to shape mode flows.
  141. //
  142. #define MAX_TIME_FOR_PACKETS_IN_SHAPER 250000
  143. #define TIMER_WHEEL_QTY 8 // in ms //
  144. #define TIMER_WHEEL_SHIFT 3
  145. #define MSIN100NS 10000 // these many ticks are there in 1 ms //
  146. #define WAN_TIMER_WHEEL_SHIFT 8 // how many TIMER_WHEEL_QTY will it have? //
  147. #define LAN_TIMER_WHEEL_SHIFT 11 // how many TIMER_WHEEL_QTY will it have? //
  148. #define DUMMY_SLOT (0xffffffff)
  149. #define DUMMY_TIME (0)
  150. /* External */
  151. /* Static */
  152. /* Forward */
  153. NDIS_STATUS
  154. TbcInitializePipe (
  155. IN HANDLE PsPipeContext,
  156. IN PPS_PIPE_PARAMETERS PipeParameters,
  157. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  158. IN PPS_PROCS PsProcs,
  159. IN PPS_UPCALLS Upcalls
  160. );
  161. NDIS_STATUS
  162. TbcModifyPipe (
  163. IN PPS_PIPE_CONTEXT PipeContext,
  164. IN PPS_PIPE_PARAMETERS PipeParameters
  165. );
  166. VOID
  167. TbcDeletePipe (
  168. IN PPS_PIPE_CONTEXT PipeContext
  169. );
  170. NDIS_STATUS
  171. TbcCreateFlow (
  172. IN PPS_PIPE_CONTEXT PipeContext,
  173. IN HANDLE PsFlowContext,
  174. IN PCO_CALL_PARAMETERS CallParameters,
  175. IN PPS_FLOW_CONTEXT ComponentFlowContext
  176. );
  177. NDIS_STATUS
  178. TbcModifyFlow (
  179. IN PPS_PIPE_CONTEXT PipeContext,
  180. IN PPS_FLOW_CONTEXT FlowContext,
  181. IN PCO_CALL_PARAMETERS CallParameters
  182. );
  183. VOID
  184. TbcDeleteFlow (
  185. IN PPS_PIPE_CONTEXT PipeContext,
  186. IN PPS_FLOW_CONTEXT FlowContext
  187. );
  188. VOID
  189. TbcEmptyFlow (
  190. IN PPS_PIPE_CONTEXT PipeContext,
  191. IN PPS_FLOW_CONTEXT FlowContext
  192. );
  193. NDIS_STATUS
  194. TbcCreateClassMap (
  195. IN PPS_PIPE_CONTEXT PipeContext,
  196. IN HANDLE PsClassMapContext,
  197. IN PTC_CLASS_MAP_FLOW ClassMap,
  198. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext);
  199. NDIS_STATUS
  200. TbcDeleteClassMap (
  201. IN PPS_PIPE_CONTEXT PipeContext,
  202. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext);
  203. BOOLEAN
  204. TbcSubmitPacket (
  205. IN PPS_PIPE_CONTEXT PipeContext,
  206. IN PPS_FLOW_CONTEXT FlowContext,
  207. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  208. IN PPACKET_INFO_BLOCK PacketInfo
  209. );
  210. VOID
  211. TbcSetInformation (
  212. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  213. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  214. IN NDIS_OID Oid,
  215. IN ULONG Len,
  216. IN PVOID Data);
  217. VOID
  218. TbcQueryInformation (
  219. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  220. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  221. IN NDIS_OID Oid,
  222. IN ULONG Len,
  223. IN PVOID Data,
  224. IN OUT PULONG BytesWritten,
  225. IN OUT PULONG BytesNeeded,
  226. IN OUT PNDIS_STATUS Status);
  227. /* End Forward */
  228. extern VOID
  229. ServiceActiveFlows(
  230. PVOID SysArg1,
  231. PVOID Context,
  232. PVOID SysArg2,
  233. PVOID SysArg3);
  234. VOID
  235. InitializeTbConformer(
  236. PPSI_INFO Info)
  237. /*++
  238. Routine Description:
  239. Initialization routine for token bucket conformer. This routine just
  240. fills in the PSI_INFO struct and returns.
  241. Arguments:
  242. Info - Pointer to component interface info struct
  243. Return Values:
  244. NDIS_STATUS_SUCCESS
  245. --*/
  246. {
  247. #ifdef QUEUE_LIMIT
  248. ULONG bytesWritten;
  249. SYSTEM_BASIC_INFORMATION sbi;
  250. #endif // QUEUE_LIMIT
  251. Info->PipeContextLength = ((sizeof(TBC_PIPE)+7) & ~7);
  252. Info->FlowContextLength = ((sizeof(TBC_FLOW)+7) & ~7);
  253. Info->ClassMapContextLength = sizeof(PS_CLASS_MAP_CONTEXT);
  254. Info->InitializePipe = TbcInitializePipe;
  255. Info->ModifyPipe = TbcModifyPipe;
  256. Info->DeletePipe = TbcDeletePipe;
  257. Info->CreateFlow = TbcCreateFlow;
  258. Info->ModifyFlow = TbcModifyFlow;
  259. Info->DeleteFlow = TbcDeleteFlow;
  260. Info->EmptyFlow = TbcEmptyFlow;
  261. Info->CreateClassMap = TbcCreateClassMap;
  262. Info->DeleteClassMap = TbcDeleteClassMap;
  263. Info->SubmitPacket = TbcSubmitPacket;
  264. Info->ReceivePacket = NULL;
  265. Info->ReceiveIndication = NULL;
  266. Info->SetInformation = TbcSetInformation;
  267. Info->QueryInformation = TbcQueryInformation;
  268. #ifdef QUEUE_LIMIT
  269. NtQuerySystemInformation(SystemBasicInformation,
  270. &sbi,
  271. sizeof(SYSTEM_BASIC_INFORMATION),
  272. &bytesWritten);
  273. gPhysMemSize = sbi.NumberOfPhysicalPages * sbi.PageSize;
  274. // convert to MB
  275. gPhysMemSize >>= 20;
  276. #endif // QUEUE_LIMIT
  277. } // InitializeTbConformer
  278. //
  279. // Unload routine: currently does nothing
  280. //
  281. void
  282. UnloadConformr()
  283. {
  284. }
  285. NDIS_STATUS
  286. TbcInitializePipe (
  287. IN HANDLE PsPipeContext,
  288. IN PPS_PIPE_PARAMETERS PipeParameters,
  289. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  290. IN PPS_PROCS PsProcs,
  291. IN PPS_UPCALLS Upcalls
  292. )
  293. /*++
  294. Routine Description:
  295. Pipe initialization routine for token bucket conformer.
  296. Arguments:
  297. PsPipeContext - PS pipe context value
  298. PipeParameters - Pointer to pipe parameters
  299. ComponentPipeContext - Pointer to this component's context area
  300. PsProcs - PS's support routines
  301. Upcalls - Previous component's upcall table
  302. Return Values:
  303. Status value from next component
  304. --*/
  305. {
  306. PTBC_PIPE Pipe = (PTBC_PIPE)ComponentPipeContext;
  307. NDIS_STATUS Status;
  308. HANDLE NdisHandle;
  309. int i = 0;
  310. PLIST_ENTRY pList = NULL;
  311. PsDbgOut(DBG_INFO, DBG_SCHED_TBC,
  312. ("PSCHED: Conformer pipe initialized. Bandwidth = %u\n", PipeParameters->Bandwidth));
  313. Pipe->MaxPacket = PipeParameters->MTUSize - PipeParameters->HeaderSize;
  314. Pipe->PsPipeContext = PsPipeContext;
  315. (*PsProcs->GetTimerInfo)(&Pipe->TimerResolution);
  316. Pipe->TimerResolution /= 2;
  317. Pipe->PsProcs = PsProcs;
  318. Pipe->HeaderLength = PipeParameters->HeaderSize;
  319. Pipe->ControlledLoadMode = PipeParameters->SDModeControlledLoad;
  320. Pipe->GuaranteedMode = PipeParameters->SDModeGuaranteed;
  321. Pipe->NetworkControlMode = PipeParameters->SDModeNetworkControl;
  322. Pipe->Qualitative = PipeParameters->SDModeQualitative;
  323. Pipe->IntermediateSystem = (PipeParameters->Flags & PS_INTERMEDIATE_SYS) ? TRUE : FALSE;
  324. Pipe->MediaType = PipeParameters->MediaType;
  325. InitializeListHead(&Pipe->ActiveFlows);
  326. NdisHandle = (*PsProcs->NdisPipeHandle)(PsPipeContext);
  327. // 1. Initialize the spin lock that protects the timer wheel //
  328. NdisAllocateSpinLock(&Pipe->Lock);
  329. // 2. Initialize the timer for the timer wheel //
  330. if (NdisHandle != NULL)
  331. {
  332. NdisMInitializeTimer(
  333. &Pipe->Timer,
  334. NdisHandle,
  335. ServiceActiveFlows,
  336. Pipe);
  337. Pipe->TimerStatus = TIMER_INACTIVE;
  338. }
  339. else
  340. {
  341. // Why would it come here.... ? //
  342. Pipe->TimerStatus = TIMER_UNINITIALIZED;
  343. }
  344. // Remember what kind of pipe are we installing now.. //
  345. if( Pipe->MediaType == NdisMediumWan )
  346. Pipe->TimerWheelShift = WAN_TIMER_WHEEL_SHIFT;
  347. else
  348. Pipe->TimerWheelShift = LAN_TIMER_WHEEL_SHIFT;
  349. // These values should always be initialized //
  350. Pipe->pTimerWheel = NULL;
  351. Pipe->SetSlotValue = DUMMY_SLOT;
  352. Pipe->SetTimerValue.QuadPart = DUMMY_TIME;
  353. Pipe->cStats.NonconformingPacketsScheduled = 0;
  354. Pipe->PacketsInShaper = 0;
  355. Pipe->PacketsInShaperAveragingArray = NULL;
  356. NdisZeroMemory(&Pipe->sStats, sizeof(PS_SHAPER_STATS));
  357. Status = CreateAveragingArray(&Pipe->PacketsInShaperAveragingArray,
  358. SHAPER_AVERAGING_ARRAY_SIZE);
  359. if(Status != NDIS_STATUS_SUCCESS)
  360. {
  361. NdisFreeSpinLock( &Pipe->Lock );
  362. return(Status);
  363. }
  364. NdisInitializeEvent(&Pipe->TimerUnloadEvent);
  365. Pipe->TimerUnloadFlag = 0;
  366. Status = (*Pipe->ContextInfo.NextComponent->InitializePipe)(
  367. PsPipeContext,
  368. PipeParameters,
  369. Pipe->ContextInfo.NextComponentContext,
  370. PsProcs,
  371. Upcalls);
  372. if (Status != NDIS_STATUS_SUCCESS)
  373. {
  374. DeleteAveragingArray(Pipe->PacketsInShaperAveragingArray);
  375. NdisFreeSpinLock( &Pipe->Lock );
  376. }
  377. return Status;
  378. } // TbcInitializePipe
  379. NDIS_STATUS
  380. TbcModifyPipe (
  381. IN PPS_PIPE_CONTEXT PipeContext,
  382. IN PPS_PIPE_PARAMETERS PipeParameters
  383. )
  384. /*++
  385. Routine Description:
  386. Pipe parameter modification routine for token bucket conformer.
  387. Arguments:
  388. PipeContext - Pointer to this component's pipe context area
  389. PipeParameters - Pointer to pipe parameters
  390. Return Values:
  391. Status value from next component
  392. --*/
  393. {
  394. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  395. PTBC_FLOW Flow;
  396. PLIST_ENTRY Entry;
  397. PsDbgOut(DBG_INFO, DBG_SCHED_TBC,
  398. ("PSCHED: Conformer pipe modified. Bandwidth = %u\n", PipeParameters->Bandwidth));
  399. LOCK_PIPE(Pipe);
  400. (*Pipe->PsProcs->GetTimerInfo)(&Pipe->TimerResolution);
  401. Pipe->TimerResolution /= 2;
  402. UNLOCK_PIPE(Pipe);
  403. return (*Pipe->ContextInfo.NextComponent->ModifyPipe)(
  404. Pipe->ContextInfo.NextComponentContext,
  405. PipeParameters);
  406. } // TbcModifyPipe
  407. VOID
  408. TbcDeletePipe (
  409. IN PPS_PIPE_CONTEXT PipeContext
  410. )
  411. /*++
  412. Routine Description:
  413. Pipe removal routine for token bucket conformer.
  414. Arguments:
  415. PipeContext - Pointer to this component's pipe context area
  416. Return Values:
  417. --*/
  418. {
  419. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  420. BOOLEAN Cancelled;
  421. if (Pipe->TimerStatus == TIMER_SET)
  422. {
  423. BOOLEAN TimerCancelled;
  424. NdisMCancelTimer(&Pipe->Timer, &TimerCancelled );
  425. if( !TimerCancelled )
  426. {
  427. // Need to handle the case where the Timer could not be cancelled. In this case, the DPC could be running,
  428. // and we will have to wait here before going further
  429. }
  430. else
  431. {
  432. Pipe->TimerStatus = TIMER_INACTIVE;
  433. }
  434. }
  435. DeleteAveragingArray(Pipe->PacketsInShaperAveragingArray);
  436. // Every pipe does not necessarily have a Timer-wheel now //
  437. if( Pipe->pTimerWheel )
  438. PsFreePool( Pipe->pTimerWheel);
  439. NdisFreeSpinLock(&Pipe->Lock);
  440. PsDbgOut(DBG_INFO, DBG_SCHED_TBC, ("PSCHED: Conformer pipe deleted\n"));
  441. (*Pipe->ContextInfo.NextComponent->DeletePipe)(Pipe->ContextInfo.NextComponentContext);
  442. } // TbcDeletePipe
  443. #ifdef QUEUE_LIMIT
  444. /*
  445. SetDefaultFlowQueueLimit() - Sets the queue size limit on a flow using a formula based on
  446. the amount of physical memory in the system and the overall
  447. bandwidth of the flow.
  448. OUT PTS_FLOW Flow - Pointer to the flow to set the limit on
  449. IN PCO_CALL_PARAMETERS CallParameters - Call parameters containing the flow's
  450. bandwidth requirements
  451. */
  452. static void
  453. SetDefaultFlowQueueLimit (
  454. OUT PTS_FLOW Flow,
  455. IN PCO_CALL_PARAMETERS CallParameters
  456. )
  457. {
  458. ULONG FlowBandwidth; // = either PeakRate or TokenRate+BucketSize
  459. // determine the "flow bandwidth"
  460. // if the peak rate is specified, use it as flow b/w
  461. if (CallParameters->CallMgrParameters->Transmit.PeakBandwidth != QOS_NOT_SPECIFIED)
  462. FlowBandwidth = CallParameters->CallMgrParameters->Transmit.PeakBandwidth;
  463. // otherwise use tokenrate + bucket size
  464. else if (QOS_NOT_SPECIFIED == CallParameters->CallMgrParameters->Transmit.TokenBucketSize)
  465. FlowBandwidth = CallParameters->CallMgrParameters->Transmit.TokenRate;
  466. else FlowBandwidth = CallParameters->CallMgrParameters->Transmit.TokenRate +
  467. CallParameters->CallMgrParameters->Transmit.TokenBucketSize;
  468. // then use it to compute the queue limit (first in time units)
  469. Flow->QueueSizeLimit = (ULONG)(40.0 * log10(0.2 * gPhysMemSize) / log10(FlowBandwidth));
  470. // convert time limit to size limit
  471. Flow->QueueSizeLimit *= FlowBandwidth;
  472. }
  473. #endif // QUEUE_LIMIT
  474. NDIS_STATUS
  475. TbcCreateFlow (
  476. IN PPS_PIPE_CONTEXT PipeContext,
  477. IN HANDLE PsFlowContext,
  478. IN PCO_CALL_PARAMETERS CallParameters,
  479. IN PPS_FLOW_CONTEXT ComponentFlowContext
  480. )
  481. /*++
  482. Routine Description:
  483. Flow creation routine for token bucket conformer.
  484. Arguments:
  485. PipeContext - Pointer to this component's pipe context area
  486. PsFlowContext - PS flow context value
  487. CallParameters - Pointer to call parameters for flow
  488. ComponentFlowContext - Pointer to this component's flow context area
  489. Return Values:
  490. Status value from next component
  491. --*/
  492. {
  493. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  494. PTBC_FLOW Flow = (PTBC_FLOW)ComponentFlowContext;
  495. HANDLE NdisHandle;
  496. NDIS_STATUS Status;
  497. ULONG ParamsLength;
  498. LPQOS_OBJECT_HDR QoSObject;
  499. LPQOS_SD_MODE ShapeDiscardObject = NULL;
  500. ULONG Mode;
  501. ULONG PeakRate;
  502. ULONG Slot= 0;
  503. LARGE_INTEGER Ms;
  504. LARGE_INTEGER TenMs;
  505. LARGE_INTEGER CurrentTimeInMs;
  506. LONGLONG DeltaTimeInMs;
  507. PLIST_ENTRY pList = NULL;
  508. LARGE_INTEGER CurrentTime;
  509. #ifdef QUEUE_LIMIT
  510. LPQOS_SHAPER_QUEUE_LIMIT_DROP_MODE ShaperOverLimitDropModeObject = NULL;
  511. LPQOS_SHAPER_QUEUE_LIMIT ShaperQueueLimitObject = NULL;
  512. #endif // QUEUELIMIT
  513. if (Pipe->TimerStatus == TIMER_UNINITIALIZED) {
  514. NdisHandle = (*Pipe->PsProcs->NdisPipeHandle)(Pipe->PsPipeContext);
  515. if (NdisHandle != NULL) {
  516. NdisMInitializeTimer(
  517. &Pipe->Timer,
  518. NdisHandle,
  519. ServiceActiveFlows,
  520. Pipe);
  521. Pipe->TimerStatus = TIMER_INACTIVE;
  522. }
  523. else {
  524. return NDIS_STATUS_FAILURE;
  525. }
  526. }
  527. NdisAllocateSpinLock(&Flow->Lock);
  528. // Get the required values from the flowspec. We assume here that the PS wrapper
  529. // has performed the required validity checks:
  530. // TokenRate <= PeakRate
  531. // TokenRate > 0
  532. Flow->State = TS_FLOW_CREATED;
  533. Flow->TokenRate = CallParameters->CallMgrParameters->Transmit.TokenRate;
  534. Flow->Capacity = CallParameters->CallMgrParameters->Transmit.TokenBucketSize;
  535. Flow->PeakRate = CallParameters->CallMgrParameters->Transmit.PeakBandwidth;
  536. Flow->MinPolicedUnit =
  537. (CallParameters->CallMgrParameters->Transmit.MinimumPolicedSize == QOS_NOT_SPECIFIED) ?
  538. 0 : CallParameters->CallMgrParameters->Transmit.MinimumPolicedSize;
  539. if (Flow->Capacity == QOS_NOT_SPECIFIED)
  540. {
  541. if( Pipe->MaxPacket > (CallParameters->CallMgrParameters->Transmit.TokenRate / 100) )
  542. Flow->Capacity = Pipe->MaxPacket;
  543. else
  544. Flow->Capacity = CallParameters->CallMgrParameters->Transmit.TokenRate / 100;
  545. }
  546. // Look for the Shape/Discard object in the call manager specific parameters.
  547. // If it is found, save the pointer.
  548. ParamsLength = CallParameters->CallMgrParameters->CallMgrSpecific.Length;
  549. if (CallParameters->CallMgrParameters->CallMgrSpecific.ParamType == PARAM_TYPE_GQOS_INFO) {
  550. QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
  551. while ((ParamsLength > 0) && (QoSObject->ObjectType != QOS_OBJECT_END_OF_LIST)) {
  552. if (QoSObject->ObjectType == QOS_OBJECT_SD_MODE) {
  553. ShapeDiscardObject = (LPQOS_SD_MODE)QoSObject;
  554. #ifdef QUEUE_LIMIT
  555. else if (QoSObject->ObjectType == QOS_OBJECT_SHAPER_QUEUE_DROP_MODE) {
  556. ShaperOverLimitDropModeObject = (LPQOS_SHAPER_QUEUE_LIMIT_DROP_MODE)QoSObject;
  557. }
  558. else if (QoSObject->ObjectType == QOS_OBJECT_SHAPER_QUEUE_LIMIT) {
  559. ShaperQueueLimitObject = (LPQOS_SHAPER_QUEUE_LIMIT)QoSObject;
  560. }
  561. #endif // QUEUE_LIMIT
  562. }
  563. ParamsLength -= QoSObject->ObjectLength;
  564. QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject + QoSObject->ObjectLength);
  565. }
  566. }
  567. // If no Shape/Discard object was found, set the default value for the
  568. // "Discard" parameter. Otherwise set it to the value specified by the
  569. // object.
  570. if (ShapeDiscardObject == NULL) {
  571. switch (CallParameters->CallMgrParameters->Transmit.ServiceType) {
  572. case SERVICETYPE_CONTROLLEDLOAD:
  573. Mode = Pipe->ControlledLoadMode;
  574. break;
  575. case SERVICETYPE_GUARANTEED:
  576. Mode = Pipe->GuaranteedMode;
  577. break;
  578. case SERVICETYPE_NETWORK_CONTROL:
  579. Mode = Pipe->NetworkControlMode;
  580. break;
  581. case SERVICETYPE_QUALITATIVE:
  582. Mode = Pipe->Qualitative;
  583. break;
  584. default:
  585. Mode = TC_NONCONF_BORROW;
  586. }
  587. }
  588. else {
  589. Mode = ShapeDiscardObject->ShapeDiscardMode;
  590. }
  591. Flow->Mode = Mode;
  592. Flow->NoConformance = ((Mode == TC_NONCONF_BORROW_PLUS) ||
  593. (Flow->TokenRate == QOS_NOT_SPECIFIED));
  594. PsGetCurrentTime(&Flow->LastConformanceTime);
  595. Flow->PeakConformanceTime = Flow->LastConformanceTime;
  596. Flow->LastConformanceCredits = Flow->Capacity;
  597. Flow->PsFlowContext = PsFlowContext;
  598. PeakRate = CallParameters->CallMgrParameters->Transmit.PeakBandwidth;
  599. if (Flow->Mode == TC_NONCONF_SHAPE) {
  600. Flow->Shape = TRUE;
  601. } else if ((PeakRate != QOS_NOT_SPECIFIED) &&
  602. (Flow->Mode != TC_NONCONF_BORROW_PLUS) &&
  603. !Pipe->IntermediateSystem) {
  604. Flow->Shape = TRUE;
  605. } else {
  606. Flow->Shape = FALSE;
  607. }
  608. #ifdef QUEUE_LIMIT
  609. Flow->QueueSize = 0;
  610. // If the flow is shaped, set the queue limiting params. If not specified, use defaults
  611. if (Flow->Shape) {
  612. // set the drop mode
  613. if (NULL != ShaperOverLimitDropModeObject) {
  614. Flow->DropOverLimitPacketsFromHead = (BOOLEAN) ShaperOverLimitDropModeObject->DropMode;
  615. }
  616. else {
  617. // default to this behavior
  618. Flow->DropOverLimitPacketsFromHead = TRUE;
  619. }
  620. // set the queue limit
  621. if (NULL != ShaperQueueLimitObject) {
  622. Flow->UseDefaultQueueLimit = FALSE;
  623. Flow->QueueSizeLimit = ShaperQueueLimitObject->QueueSizeLimit;
  624. }
  625. else {
  626. Flow->UseDefaultQueueLimit = TRUE;
  627. // default to a size based on the flow's bandwidth and physical memory
  628. SetDefaultFlowQueueLimit(Flow, CallParameters);
  629. }
  630. }
  631. #endif // QUEUE_LIMIT
  632. InitializeListHead(&Flow->PacketQueue);
  633. PsGetCurrentTime(&Flow->FlowEligibilityTime);
  634. Flow->cStats.NonconformingPacketsScheduled = 0;
  635. Flow->PacketsInShaper = 0;
  636. Flow->PacketsInShaperAveragingArray = NULL;
  637. NdisZeroMemory(&Flow->sStats, sizeof(PS_SHAPER_STATS));
  638. Status = CreateAveragingArray(&Flow->PacketsInShaperAveragingArray,
  639. SHAPER_FLOW_AVERAGING_ARRAY_SIZE);
  640. if(Status != NDIS_STATUS_SUCCESS){
  641. return(Status);
  642. }
  643. PsDbgOut(DBG_INFO, DBG_SCHED_TBC, ("PSCHED: Conformer flow %08X (PsFlowContext = %08X) created. Rate = %u\n",
  644. Flow,
  645. Flow->PsFlowContext,
  646. Flow->TokenRate));
  647. Status = (*Pipe->ContextInfo.NextComponent->CreateFlow)(
  648. Pipe->ContextInfo.NextComponentContext,
  649. PsFlowContext,
  650. CallParameters,
  651. Flow->ContextInfo.NextComponentContext);
  652. LOCK_PIPE( Pipe );
  653. if (Status != NDIS_STATUS_SUCCESS)
  654. {
  655. NdisFreeSpinLock(&Flow->Lock);
  656. DeleteAveragingArray(Flow->PacketsInShaperAveragingArray);
  657. }
  658. UNLOCK_PIPE( Pipe );
  659. return Status;
  660. } // TbcCreateFlow
  661. NDIS_STATUS
  662. TbcModifyFlow (
  663. IN PPS_PIPE_CONTEXT PipeContext,
  664. IN PPS_FLOW_CONTEXT FlowContext,
  665. IN PCO_CALL_PARAMETERS CallParameters
  666. )
  667. /*++
  668. Routine Description:
  669. Flow modification routine for token bucket conformer.
  670. Arguments:
  671. PipeContext - Pointer to this component's pipe context area
  672. FlowContext - Pointer to this component's flow context area
  673. CallParameters - Pointer to call parameters for flow
  674. Return Values:
  675. Status value from next component
  676. --*/
  677. {
  678. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  679. PTBC_FLOW Flow = (PTBC_FLOW)FlowContext;
  680. ULONG ParamsLength;
  681. LPQOS_OBJECT_HDR QoSObject;
  682. LPQOS_SD_MODE ShapeDiscardObject = NULL;
  683. ULONG Mode;
  684. ULONG PeakRate;
  685. LARGE_INTEGER CurrentTime;
  686. #ifdef QUEUE_LIMIT
  687. LPQOS_SHAPER_QUEUE_LIMIT_DROP_MODE ShaperOverLimitDropModeObject = NULL;
  688. LPQOS_SHAPER_QUEUE_LIMIT ShaperQueueLimitObject = NULL;
  689. #endif // QUEUE_LIMIT
  690. // Look for the Shape/Discard object in the call manager specific parameters.
  691. // If it is found, save the pointer.
  692. ParamsLength = CallParameters->CallMgrParameters->CallMgrSpecific.Length;
  693. if (CallParameters->CallMgrParameters->CallMgrSpecific.ParamType == PARAM_TYPE_GQOS_INFO) {
  694. QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
  695. while ((ParamsLength > 0) && (QoSObject->ObjectType != QOS_OBJECT_END_OF_LIST)) {
  696. if (QoSObject->ObjectType == QOS_OBJECT_SD_MODE) {
  697. ShapeDiscardObject = (LPQOS_SD_MODE)QoSObject;
  698. #ifdef QUEUE_LIMIT
  699. else if (QoSObject->ObjectType == QOS_OBJECT_SHAPER_QUEUE_DROP_MODE) {
  700. ShaperOverLimitDropModeObject = (LPQOS_SHAPER_QUEUE_LIMIT_DROP_MODE)QoSObject;
  701. }
  702. else if (QoSObject->ObjectType == QOS_OBJECT_SHAPER_QUEUE_LIMIT) {
  703. ShaperQueueLimitObject = (LPQOS_SHAPER_QUEUE_LIMIT)QoSObject;
  704. }
  705. #endif // QUEUE_LIMIT
  706. }
  707. ParamsLength -= QoSObject->ObjectLength;
  708. QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject + QoSObject->ObjectLength);
  709. }
  710. }
  711. PeakRate = CallParameters->CallMgrParameters->Transmit.PeakBandwidth;
  712. LOCK_FLOW(Flow);
  713. //
  714. // There are basically 2 parameters that have to be corrected in this function:
  715. // They are (a) LastConformanceTime (b) LastConformanceCredits.
  716. // (1) If LastConformanceTime is in the future: Goto step(4).
  717. // (2) (a) Figure out how many bytes were accumulated between LastConformanceTime and CurrentTime.
  718. // (b) If Accumulated Credits is greater than Bucket size, Accumulated Credits = Bucket size.
  719. // (c) Set LastConformanceTime to CurrentTime.
  720. // (3) PeakConformanceTime will not be changed.
  721. // (4) Change the Flow parameters, as specified in the Modify-call.
  722. PsGetCurrentTime(&CurrentTime);
  723. if( Flow->LastConformanceTime.QuadPart < CurrentTime.QuadPart)
  724. {
  725. ULONG Credits;
  726. Credits = Flow->LastConformanceCredits +
  727. EARNED_CREDITS( CurrentTime.QuadPart - Flow->LastConformanceTime.QuadPart, Flow->TokenRate);
  728. if( Credits > Flow->Capacity)
  729. Flow->LastConformanceCredits = Flow->Capacity;
  730. else
  731. Flow->LastConformanceCredits = Credits;
  732. Flow->LastConformanceTime.QuadPart = CurrentTime.QuadPart;
  733. }
  734. if (CallParameters->CallMgrParameters->Transmit.ServiceType != SERVICETYPE_NOCHANGE) {
  735. // Get the new flowspec values. Again we assume the PS wrapper has done
  736. // the required validity checks.
  737. Flow->TokenRate = CallParameters->CallMgrParameters->Transmit.TokenRate;
  738. Flow->Capacity = CallParameters->CallMgrParameters->Transmit.TokenBucketSize;
  739. Flow->PeakRate = CallParameters->CallMgrParameters->Transmit.PeakBandwidth;
  740. Flow->MinPolicedUnit =
  741. (CallParameters->CallMgrParameters->Transmit.MinimumPolicedSize == QOS_NOT_SPECIFIED) ?
  742. 0 : CallParameters->CallMgrParameters->Transmit.MinimumPolicedSize;
  743. if (Flow->Capacity == QOS_NOT_SPECIFIED)
  744. {
  745. if( Pipe->MaxPacket > (CallParameters->CallMgrParameters->Transmit.TokenRate / 100) )
  746. Flow->Capacity = Pipe->MaxPacket;
  747. else
  748. Flow->Capacity = CallParameters->CallMgrParameters->Transmit.TokenRate / 100;
  749. }
  750. if (ShapeDiscardObject == NULL) {
  751. // Re-calculate the Shape parameter if the user has never specified
  752. // a Shape/Discard object.
  753. switch (CallParameters->CallMgrParameters->Transmit.ServiceType) {
  754. case SERVICETYPE_CONTROLLEDLOAD:
  755. Mode = Pipe->ControlledLoadMode;
  756. break;
  757. case SERVICETYPE_GUARANTEED:
  758. Mode = Pipe->GuaranteedMode;
  759. break;
  760. case SERVICETYPE_NETWORK_CONTROL:
  761. Mode = Pipe->NetworkControlMode;
  762. break;
  763. case SERVICETYPE_QUALITATIVE:
  764. Mode = Pipe->Qualitative;
  765. break;
  766. default:
  767. Mode = TC_NONCONF_BORROW;
  768. }
  769. }
  770. }
  771. else
  772. {
  773. // The ServiceType has not changed. We can use the existing mode.
  774. Mode = Flow->Mode;
  775. }
  776. if (ShapeDiscardObject != NULL) {
  777. Mode = ShapeDiscardObject->ShapeDiscardMode;
  778. }
  779. Flow->Mode = Mode;
  780. Flow->NoConformance = ((Mode == TC_NONCONF_BORROW_PLUS) ||
  781. (Flow->TokenRate == QOS_NOT_SPECIFIED));
  782. if (Flow->Mode == TC_NONCONF_SHAPE) {
  783. Flow->Shape = TRUE;
  784. } else if ((PeakRate != QOS_NOT_SPECIFIED) &&
  785. (Flow->Mode != TC_NONCONF_BORROW_PLUS) &&
  786. !Pipe->IntermediateSystem) {
  787. Flow->Shape = TRUE;
  788. } else {
  789. Flow->Shape = FALSE;
  790. }
  791. #ifdef QUEUE_LIMIT
  792. // If the flow is shaped, check the queue limiting params. If specified, use
  793. if (Flow->Shape) {
  794. // modify drop mode
  795. if (NULL != ShaperOverLimitDropModeObject) {
  796. Flow->DropOverLimitPacketsFromHead = (BOOLEAN) ShaperOverLimitDropModeObject->DropMode;
  797. }
  798. // modify queue limit
  799. if (NULL != ShaperQueueLimitObject) {
  800. Flow->UseDefaultQueueLimit = FALSE;
  801. Flow->QueueSizeLimit = ShaperQueueLimitObject->QueueSizeLimit;
  802. }
  803. // if they haven't overridden the limit, recompute it in case bandwidth req's changed
  804. else if (Flow->UseDefaultQueueLimit) {
  805. SetDefaultFlowQueueLimit(Flow, CallParameters);
  806. }
  807. }
  808. #endif // QUEUE_LIMIT
  809. UNLOCK_FLOW(Flow);
  810. PsDbgOut(DBG_INFO, DBG_SCHED_TBC, ("PSCHED: Conformer flow %08x (PsFlowContext %08X) modified. Rate = %u\n",
  811. Flow, Flow->PsFlowContext, Flow->TokenRate));
  812. return (*Pipe->ContextInfo.NextComponent->ModifyFlow)(
  813. Pipe->ContextInfo.NextComponentContext,
  814. Flow->ContextInfo.NextComponentContext,
  815. CallParameters);
  816. } // TbcModifyFlow
  817. VOID
  818. TbcDeleteFlow (
  819. IN PPS_PIPE_CONTEXT PipeContext,
  820. IN PPS_FLOW_CONTEXT FlowContext
  821. )
  822. /*++
  823. Routine Description:
  824. Flow removal routine for token bucket conformer.
  825. Arguments:
  826. PipeContext - Pointer to this component's pipe context area
  827. FlowContext - Pointer to this component's flow context area
  828. Return Values:
  829. --*/
  830. {
  831. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  832. PTBC_FLOW Flow = (PTBC_FLOW)FlowContext;
  833. PPACKET_INFO_BLOCK PacketInfo;
  834. PNDIS_PACKET Packet;
  835. LIST_ENTRY DropList;
  836. PsDbgOut(DBG_INFO, DBG_SCHED_TBC, ("PSCHED: Conformer flow %08X (PS context %08X) deleted\n",
  837. Flow, Flow->PsFlowContext));
  838. NdisFreeSpinLock(&Flow->Lock);
  839. InitializeListHead(&DropList);
  840. LOCK_PIPE(Pipe);
  841. if (!IsListEmpty(&Flow->PacketQueue)) {
  842. // Remove flow from active list
  843. RemoveEntryList(&Flow->Links);
  844. while (!IsListEmpty(&Flow->PacketQueue)) {
  845. // Drop any packets that remain queued for this flow.
  846. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&Flow->PacketQueue);
  847. InsertTailList(&DropList, &PacketInfo->SchedulerLinks);
  848. }
  849. }
  850. DeleteAveragingArray(Flow->PacketsInShaperAveragingArray);
  851. UNLOCK_PIPE(Pipe);
  852. while (!IsListEmpty(&DropList))
  853. {
  854. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&DropList);
  855. Packet = PacketInfo->NdisPacket;
  856. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  857. }
  858. (*Pipe->ContextInfo.NextComponent->DeleteFlow)(
  859. Pipe->ContextInfo.NextComponentContext,
  860. Flow->ContextInfo.NextComponentContext);
  861. } // TbcDeleteFlow
  862. VOID
  863. TbcEmptyFlow (
  864. IN PPS_PIPE_CONTEXT PipeContext,
  865. IN PPS_FLOW_CONTEXT FlowContext
  866. )
  867. /*++
  868. Routine Description:
  869. Flow removal routine for token bucket conformer.
  870. Arguments:
  871. PipeContext - Pointer to this component's pipe context area
  872. FlowContext - Pointer to this component's flow context area
  873. Return Values:
  874. --*/
  875. {
  876. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  877. PTBC_FLOW Flow = (PTBC_FLOW)FlowContext;
  878. PPACKET_INFO_BLOCK PacketInfo;
  879. PNDIS_PACKET Packet;
  880. LIST_ENTRY DropList;
  881. PsDbgOut(DBG_INFO, DBG_SCHED_TBC, ("PSCHED: Conformer flow %08X (PS context %08X) emptied\n",
  882. Flow, Flow->PsFlowContext));
  883. InitializeListHead(&DropList);
  884. LOCK_PIPE(Pipe);
  885. if (!IsListEmpty(&Flow->PacketQueue))
  886. {
  887. // Remove flow from active list
  888. RemoveEntryList(&Flow->Links);
  889. while (!IsListEmpty(&Flow->PacketQueue))
  890. {
  891. // Drop any packets that remain queued for this flow.
  892. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&Flow->PacketQueue);
  893. InsertTailList(&DropList, &PacketInfo->SchedulerLinks);
  894. }
  895. }
  896. Flow->State = TS_FLOW_DELETED;
  897. UNLOCK_PIPE(Pipe);
  898. while (!IsListEmpty(&DropList))
  899. {
  900. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&DropList);
  901. Packet = PacketInfo->NdisPacket;
  902. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  903. }
  904. (*Pipe->ContextInfo.NextComponent->EmptyFlow)(
  905. Pipe->ContextInfo.NextComponentContext,
  906. Flow->ContextInfo.NextComponentContext);
  907. } // TbcModifyFlow
  908. static NDIS_STATUS
  909. TbcCreateClassMap (
  910. IN PPS_PIPE_CONTEXT PipeContext,
  911. IN HANDLE PsClassMapContext,
  912. IN PTC_CLASS_MAP_FLOW ClassMap,
  913. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext)
  914. {
  915. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  916. return (*Pipe->ContextInfo.NextComponent->CreateClassMap)(
  917. Pipe->ContextInfo.NextComponentContext,
  918. PsClassMapContext,
  919. ClassMap,
  920. ComponentClassMapContext->NextComponentContext);
  921. }
  922. static NDIS_STATUS
  923. TbcDeleteClassMap (
  924. IN PPS_PIPE_CONTEXT PipeContext,
  925. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext)
  926. {
  927. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  928. return (*Pipe->ContextInfo.NextComponent->DeleteClassMap)(
  929. Pipe->ContextInfo.NextComponentContext,
  930. ComponentClassMapContext->NextComponentContext);
  931. }
  932. void
  933. InsertFlow( PTBC_PIPE Pipe,
  934. PTBC_FLOW Flow,
  935. LARGE_INTEGER CurrentTime,
  936. PPACKET_INFO_BLOCK PacketInfo,
  937. PNDIS_PACKET Packet,
  938. ULONG ExecSlot,
  939. LARGE_INTEGER ExecTimeInTenMs)
  940. {
  941. /* So, the packet is not eligible to be sent out right now, and the pkt-queue is empty.. */
  942. ULONG Slot= 0;
  943. LARGE_INTEGER Ms;
  944. LARGE_INTEGER TenMs;
  945. LARGE_INTEGER CurrentTimeInMs;
  946. LARGE_INTEGER DeltaTimeInTenMs, CurrentTimeInTenMs;
  947. PLIST_ENTRY pList = NULL;
  948. BOOLEAN TimerCancelled;
  949. PsDbgSched(DBG_INFO,
  950. DBG_SCHED_SHAPER,
  951. SHAPER, PKT_ENQUEUE, Flow->PsFlowContext,
  952. Packet, PacketInfo->PacketLength, 0,
  953. CurrentTime.QuadPart,
  954. PacketInfo->DelayTime.QuadPart,
  955. Pipe->PacketsInShaper,
  956. 0);
  957. /* Conf time in ms and 10ms */
  958. Ms.QuadPart = OS_TIME_TO_MILLISECS( Flow->FlowEligibilityTime.QuadPart );
  959. TenMs.QuadPart = Ms.QuadPart >> TIMER_WHEEL_SHIFT;
  960. /* Diff in 10 MS */
  961. DeltaTimeInTenMs.QuadPart = TenMs.QuadPart - ExecTimeInTenMs.QuadPart;
  962. /* Figure out the Slot for this time.. */
  963. Slot = (ULONG)( (TenMs.QuadPart) & (( 1 << Pipe->TimerWheelShift) - 1) );
  964. /* Update the loop count too */
  965. Flow->LoopCount = (ULONG)( DeltaTimeInTenMs.QuadPart >> Pipe->TimerWheelShift );
  966. if( Slot == ExecSlot)
  967. Slot = ( (Slot + 1) & ((1 << Pipe->TimerWheelShift) - 1) );
  968. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  969. /* Need to insert the flow to the timer-wheel in slot's position*/
  970. InsertTailList(pList, &Flow->Links);
  971. }
  972. VOID
  973. ServiceActiveFlows(
  974. PVOID SysArg1,
  975. PVOID Context,
  976. PVOID SysArg2,
  977. PVOID SysArg3)
  978. /*++
  979. Routine Description:
  980. Service the active flow list after a timer expiration.
  981. Arguments:
  982. Context - Pointer to pipe context information
  983. Return Values:
  984. --*/
  985. {
  986. PTBC_PIPE Pipe = (PTBC_PIPE)Context;
  987. PTBC_FLOW Flow;
  988. LARGE_INTEGER CurrentTime;
  989. LONGLONG RelTimeInMillisecs;
  990. PPACKET_INFO_BLOCK PacketInfo;
  991. PNDIS_PACKET Packet;
  992. BOOLEAN DoneWithFlow;
  993. PLIST_ENTRY CurrentLink;
  994. PLIST_ENTRY ListHead;
  995. PLIST_ENTRY ListEnd;
  996. ULONG i = 0;
  997. ULONG SetSlot= 0;
  998. ULONG CurrentSlot = 0;
  999. LARGE_INTEGER Ms;
  1000. LARGE_INTEGER TenMs;
  1001. LARGE_INTEGER CurrentTimeInMs;
  1002. LONGLONG DeltaTimeInMs;
  1003. LIST_ENTRY SendList;
  1004. LIST_ENTRY FlowList;
  1005. InitializeListHead(&SendList);
  1006. InitializeListHead(&FlowList);
  1007. LOCK_PIPE(Pipe);
  1008. PsGetCurrentTime(&CurrentTime);
  1009. /* start from here.. */
  1010. i = SetSlot = Pipe->SetSlotValue;
  1011. Ms.QuadPart = OS_TIME_TO_MILLISECS( CurrentTime.QuadPart);
  1012. TenMs.QuadPart = Ms.QuadPart >> TIMER_WHEEL_SHIFT;
  1013. // Need to make sure that SetTimerValue is lesser than TenMs //
  1014. if( Pipe->SetTimerValue.QuadPart > TenMs.QuadPart)
  1015. {
  1016. // Why is the timer firing earlier than when it is slated to?
  1017. TenMs.QuadPart = 1;
  1018. NdisMSetTimer(&Pipe->Timer, (UINT)(TenMs.QuadPart << TIMER_WHEEL_SHIFT));
  1019. UNLOCK_PIPE(Pipe);
  1020. return;
  1021. }
  1022. /* run till here.. */
  1023. CurrentSlot = (ULONG)( (TenMs.QuadPart) & ((1 << Pipe->TimerWheelShift) - 1) );
  1024. /* Indicate that the timer is running */
  1025. Pipe->TimerStatus = TIMER_PROC_EXECUTING;
  1026. Pipe->ExecTimerValue.QuadPart = Pipe->SetTimerValue.QuadPart;
  1027. Pipe->ExecSlot = Pipe->SetSlotValue;
  1028. ListHead = (PLIST_ENTRY)((char*)Pipe->pTimerWheel + (sizeof(LIST_ENTRY)* SetSlot ));
  1029. ListEnd = (PLIST_ENTRY)((char*)Pipe->pTimerWheel + (sizeof(LIST_ENTRY)* CurrentSlot ));
  1030. while(1)
  1031. {
  1032. while( !IsListEmpty( ListHead) )
  1033. {
  1034. CurrentLink = ListHead->Flink;
  1035. Flow = CONTAINING_RECORD(CurrentLink, TBC_FLOW, Links);
  1036. RemoveEntryList(&Flow->Links);
  1037. PsAssert(!IsListEmpty(&Flow->PacketQueue));
  1038. DoneWithFlow = FALSE;
  1039. InitializeListHead( &SendList );
  1040. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  1041. if( Flow->LoopCount > 0 )
  1042. {
  1043. Flow->LoopCount--;
  1044. InsertTailList( &FlowList, &Flow->Links );
  1045. continue;
  1046. }
  1047. while( FlowIsEligible(Flow, CurrentTime, ((TIMER_WHEEL_QTY/2) * MSIN100NS)))
  1048. {
  1049. RemoveEntryList(&PacketInfo->SchedulerLinks);
  1050. Packet = PacketInfo->NdisPacket;
  1051. DoneWithFlow = IsListEmpty(&Flow->PacketQueue);
  1052. Pipe->PacketsInShaper--;
  1053. Flow->PacketsInShaper--;
  1054. if(gEnableAvgStats)
  1055. {
  1056. Pipe->sStats.AveragePacketsInShaper =
  1057. RunningAverage(Pipe->PacketsInShaperAveragingArray,
  1058. Pipe->PacketsInShaper);
  1059. Flow->sStats.AveragePacketsInShaper =
  1060. RunningAverage(Flow->PacketsInShaperAveragingArray,
  1061. Flow->PacketsInShaper);
  1062. }
  1063. PsDbgSched(DBG_INFO,
  1064. DBG_SCHED_SHAPER,
  1065. SHAPER, PKT_DEQUEUE, Flow->PsFlowContext,
  1066. Packet, PacketInfo->PacketLength, 0,
  1067. CurrentTime.QuadPart,
  1068. PacketInfo->DelayTime.QuadPart,
  1069. Pipe->PacketsInShaper,
  1070. 0);
  1071. InsertTailList( &SendList, &PacketInfo->SchedulerLinks);
  1072. if( !DoneWithFlow)
  1073. {
  1074. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  1075. Flow->FlowEligibilityTime.QuadPart = PacketInfo->DelayTime.QuadPart;
  1076. }
  1077. else
  1078. {
  1079. break;
  1080. }
  1081. }
  1082. if( !DoneWithFlow)
  1083. {
  1084. /* Need to insert in the right place.. */
  1085. InsertFlow( Pipe, Flow, CurrentTime, PacketInfo, Packet, i, Pipe->ExecTimerValue);
  1086. }
  1087. /* send the packet corresponding to this flow here */
  1088. UNLOCK_PIPE(Pipe);
  1089. while( !IsListEmpty( &SendList ))
  1090. {
  1091. PPACKET_INFO_BLOCK PacketInfo;
  1092. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&SendList);
  1093. if (!(*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  1094. Pipe->ContextInfo.NextComponentContext,
  1095. Flow->ContextInfo.NextComponentContext,
  1096. (PacketInfo->ClassMapContext != NULL) ?
  1097. ((PPS_CLASS_MAP_CONTEXT)PacketInfo->ClassMapContext)->NextComponentContext: NULL,
  1098. PacketInfo))
  1099. {
  1100. (*Pipe->PsProcs->DropPacket)( Pipe->PsPipeContext,
  1101. Flow->PsFlowContext,
  1102. PacketInfo->NdisPacket,
  1103. NDIS_STATUS_FAILURE);
  1104. }
  1105. }
  1106. LOCK_PIPE(Pipe);
  1107. }
  1108. /* Now, we need to re-insert back all the non-zero loop counts into the same buckets (before we move on ) */
  1109. while( !IsListEmpty( &FlowList) )
  1110. {
  1111. CurrentLink = RemoveHeadList( &FlowList );
  1112. InsertTailList(ListHead, CurrentLink);
  1113. }
  1114. /* We have traversed the whole length.. */
  1115. if(ListHead == ListEnd)
  1116. break;
  1117. /* Need to move ListHead to next slot.. */
  1118. i = ( (i+1) & ((1 << Pipe->TimerWheelShift) - 1) );
  1119. ListHead = (PLIST_ENTRY)((char*)Pipe->pTimerWheel + (sizeof(LIST_ENTRY)* i));
  1120. Pipe->ExecSlot = i;
  1121. Pipe->ExecTimerValue.QuadPart ++;
  1122. }
  1123. //
  1124. // Need to find the "next non-empty slot" and set the timer.
  1125. // If no such slot is found, do not set the timer.
  1126. //
  1127. i = ( CurrentSlot + 1) & ((1 << Pipe->TimerWheelShift) - 1) ;
  1128. TenMs.QuadPart = 1;
  1129. while(1)
  1130. {
  1131. ListHead = (PLIST_ENTRY)((char*)Pipe->pTimerWheel + (sizeof(LIST_ENTRY)* i));
  1132. if( !IsListEmpty( ListHead) )
  1133. {
  1134. // found a non-empty slot //
  1135. Pipe->SetSlotValue = i;
  1136. Pipe->SetTimerValue.QuadPart = (Ms.QuadPart >> TIMER_WHEEL_SHIFT) + TenMs.QuadPart;
  1137. Pipe->TimerStatus = TIMER_SET;
  1138. NdisMSetTimer(&Pipe->Timer, (UINT)(TenMs.QuadPart << TIMER_WHEEL_SHIFT));
  1139. UNLOCK_PIPE(Pipe);
  1140. return;
  1141. }
  1142. if( i == CurrentSlot)
  1143. break;
  1144. i = ((i +1) & ((1 << Pipe->TimerWheelShift) - 1) );
  1145. TenMs.QuadPart = TenMs.QuadPart + 1;
  1146. }
  1147. Pipe->TimerStatus = TIMER_INACTIVE;
  1148. UNLOCK_PIPE(Pipe);
  1149. return;
  1150. } // ServiceActiveFlows
  1151. BOOLEAN
  1152. TbcSubmitPacket (
  1153. IN PPS_PIPE_CONTEXT PipeContext,
  1154. IN PPS_FLOW_CONTEXT FlowContext,
  1155. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  1156. IN PPACKET_INFO_BLOCK PacketInfo
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Packet submission routine for token bucket conformer.
  1161. Arguments:
  1162. PipeContext - Pointer to this component's pipe context area
  1163. FlowContext - Pointer to this component's flow context area
  1164. Packet - Pointer to packet
  1165. Return Values:
  1166. Status value from next component
  1167. --*/
  1168. {
  1169. PTBC_PIPE Pipe = (PTBC_PIPE)PipeContext;
  1170. PTBC_FLOW Flow = (PTBC_FLOW)FlowContext;
  1171. PNDIS_PACKET Packet = PacketInfo->NdisPacket;
  1172. LARGE_INTEGER CurrentTime;
  1173. LARGE_INTEGER ConformanceTime;
  1174. LARGE_INTEGER TransmitTime;
  1175. LARGE_INTEGER PeakConformanceTime;
  1176. ULONG Credits;
  1177. ULONG PacketLength;
  1178. BOOLEAN TimerCancelled;
  1179. LONGLONG RelTimeInMillisecs;
  1180. BOOLEAN Status;
  1181. #ifdef QUEUE_LIMIT
  1182. PPACKET_INFO_BLOCK PacketToBeDroppedInfo;
  1183. #endif // QUEUE_LIMIT
  1184. PsGetCurrentTime(&CurrentTime);
  1185. if (Flow->NoConformance) {
  1186. // The conformance time calculation is not performed for certain types of
  1187. // flows. If the flow does not have a specified rate, we cannot really do
  1188. // token bucket. Flows that use the "borrow+" shape/discard mode only use
  1189. // their rate as a relative weight. For either of these types of flows
  1190. // there is no distinction between conforming and non-conforming traffic.
  1191. // So, we just set the "conformance" time to the current time to insure
  1192. // that all packets will be handled as conforming in subsequent components.
  1193. PacketInfo->ConformanceTime.QuadPart = CurrentTime.QuadPart;
  1194. }
  1195. else {
  1196. // We decided to not use the MinPolicedSize as per WMT request. This makes the overhead
  1197. // calculation complicated and incorrect.
  1198. PacketLength = //(PacketInfo->PacketLength < Flow->MinPolicedUnit) ? Flow->MinPolicedUnit :
  1199. PacketInfo->PacketLength;
  1200. LOCK_FLOW(Flow);
  1201. // Set ConformanceTime to the earliest time at which the packet may
  1202. // possibly go out, based on the token bucket parameters, and Credits
  1203. // to the number of credits available at that time.
  1204. if (CurrentTime.QuadPart > Flow->LastConformanceTime.QuadPart) {
  1205. ConformanceTime = CurrentTime;
  1206. Credits = Flow->LastConformanceCredits +
  1207. EARNED_CREDITS(
  1208. CurrentTime.QuadPart - Flow->LastConformanceTime.QuadPart,
  1209. Flow->TokenRate);
  1210. }
  1211. else {
  1212. ConformanceTime = Flow->LastConformanceTime;
  1213. Credits = Flow->LastConformanceCredits;
  1214. }
  1215. if (Credits > Flow->Capacity) {
  1216. Credits = Flow->Capacity;
  1217. }
  1218. // Now check whether there are enough credits to send the packet at ConformanceTime
  1219. if (Credits < PacketLength) {
  1220. // If there aren't enough credits, update ConformanceTime to the time at which
  1221. // there will be enough credits
  1222. ConformanceTime.QuadPart +=
  1223. (LONGLONG)TIME_TO_EARN_CREDITS(PacketLength - Credits, Flow->TokenRate);
  1224. // Now update Credits to be the number of credits available at ConformanceTime,
  1225. // taking this packet into account. In this case, the number of credits
  1226. // at ConformanceTime will be zero.
  1227. Credits = 0;
  1228. // If it has to wait to earn credits, it's non-conforming
  1229. Flow->cStats.NonconformingPacketsScheduled ++;
  1230. Pipe->cStats.NonconformingPacketsScheduled ++;
  1231. }
  1232. else {
  1233. // There are enough credits, so the packet can be sent at ConformanceTime. Update
  1234. // Credits to be the number of credits available at ConformanceTime, taking this
  1235. // packet into account.
  1236. Credits -= PacketLength;
  1237. }
  1238. // Calculate the adjusted conformance time, which is the maximum of the
  1239. // token bucket conformance time and the peak conformance time.
  1240. if (Flow->PeakRate != QOS_NOT_SPECIFIED)
  1241. {
  1242. PeakConformanceTime = (Flow->PeakConformanceTime.QuadPart < CurrentTime.QuadPart) ?
  1243. CurrentTime : Flow->PeakConformanceTime;
  1244. TransmitTime = (PeakConformanceTime.QuadPart < ConformanceTime.QuadPart) ?
  1245. ConformanceTime : PeakConformanceTime;
  1246. } else {
  1247. PeakConformanceTime = Flow->LastConformanceTime;
  1248. TransmitTime = ConformanceTime;
  1249. }
  1250. // Perform mode-specific operations. For discard mode flows, check whether
  1251. // the packet should be dropped. For all flows, set the packet conformance
  1252. // times based on the pipe/flow mode. The packet's conformance time is the
  1253. // time at which the packet should be considered conforming. The delay time
  1254. // is the earliest time at which a packet is eligible for sending.
  1255. // When deciding whether to drop a packet, we consider a packet conforming if
  1256. // its conformance time is within half a clock tick of the current time.
  1257. if (Flow->Mode == TC_NONCONF_DISCARD) {
  1258. if (Pipe->IntermediateSystem) {
  1259. if (!PACKET_IS_CONFORMING(TransmitTime, CurrentTime, Pipe->TimerResolution)) {
  1260. UNLOCK_FLOW(Flow);
  1261. PsDbgSched(DBG_TRACE, DBG_SCHED_TBC,
  1262. TBC_CONFORMER, PKT_DISCARD, Flow->PsFlowContext,
  1263. Packet, PacketInfo->PacketLength, 0,
  1264. CurrentTime.QuadPart,
  1265. TransmitTime.QuadPart, 0, 0);
  1266. return FALSE;
  1267. }
  1268. } else {
  1269. if (!PACKET_IS_CONFORMING(ConformanceTime, CurrentTime, Pipe->TimerResolution)) {
  1270. UNLOCK_FLOW(Flow);
  1271. PsDbgSched(DBG_TRACE, DBG_SCHED_TBC,
  1272. TBC_CONFORMER, PKT_DISCARD, Flow->PsFlowContext,
  1273. Packet, PacketInfo->PacketLength, 0,
  1274. CurrentTime.QuadPart,
  1275. ConformanceTime.QuadPart, 0, 0);
  1276. return FALSE;
  1277. }
  1278. }
  1279. }
  1280. // Set the packet conformance times
  1281. if (Pipe->IntermediateSystem) {
  1282. if (Flow->Mode == TC_NONCONF_SHAPE) {
  1283. // Both conformance times are the adjusted conformance time.
  1284. PacketInfo->ConformanceTime.QuadPart =
  1285. PacketInfo->DelayTime.QuadPart = TransmitTime.QuadPart;
  1286. //
  1287. // If the packet is going to remain for > 5 min, discard it.
  1288. //
  1289. if(TransmitTime.QuadPart > CurrentTime.QuadPart &&
  1290. OS_TIME_TO_MILLISECS((TransmitTime.QuadPart - CurrentTime.QuadPart))
  1291. > MAX_TIME_FOR_PACKETS_IN_SHAPER)
  1292. {
  1293. UNLOCK_FLOW(Flow);
  1294. return FALSE;
  1295. }
  1296. } else {
  1297. // Packet's conformance time is the adjusted conformance time,
  1298. // and the delay time is the current time.
  1299. PacketInfo->ConformanceTime.QuadPart = TransmitTime.QuadPart;
  1300. PacketInfo->DelayTime.QuadPart = CurrentTime.QuadPart;
  1301. }
  1302. } else {
  1303. if (Flow->Mode == TC_NONCONF_SHAPE) {
  1304. // Packet's conformance time is the token bucket conformance time,
  1305. // and the delay time is the adjusted conformance time.
  1306. PacketInfo->ConformanceTime.QuadPart = ConformanceTime.QuadPart;
  1307. PacketInfo->DelayTime.QuadPart = TransmitTime.QuadPart;
  1308. //
  1309. // If the packet is going to remain for > 5 min, discard it.
  1310. //
  1311. if(TransmitTime.QuadPart > CurrentTime.QuadPart &&
  1312. OS_TIME_TO_MILLISECS((TransmitTime.QuadPart - CurrentTime.QuadPart))
  1313. > MAX_TIME_FOR_PACKETS_IN_SHAPER)
  1314. {
  1315. UNLOCK_FLOW(Flow);
  1316. return FALSE;
  1317. }
  1318. } else {
  1319. // Packet's conformance time is the token bucket conformance time, and
  1320. // the delay time is the peak conformance time.
  1321. PacketInfo->ConformanceTime.QuadPart = ConformanceTime.QuadPart;
  1322. PacketInfo->DelayTime.QuadPart = PeakConformanceTime.QuadPart;
  1323. }
  1324. }
  1325. // Update the flow's variables
  1326. if (Flow->PeakRate != QOS_NOT_SPECIFIED) {
  1327. Flow->PeakConformanceTime.QuadPart =
  1328. PeakConformanceTime.QuadPart + (LONGLONG)TIME_TO_SEND(PacketLength, Flow->PeakRate);
  1329. }
  1330. Flow->LastConformanceTime = ConformanceTime;
  1331. Flow->LastConformanceCredits = Credits;
  1332. UNLOCK_FLOW(Flow);
  1333. }
  1334. // Pass the packet on
  1335. PsDbgSched(DBG_INFO, DBG_SCHED_TBC,
  1336. TBC_CONFORMER, PKT_CONFORMANCE, Flow->PsFlowContext,
  1337. Packet, PacketInfo->PacketLength, 0,
  1338. CurrentTime.QuadPart,
  1339. (Pipe->IntermediateSystem) ?
  1340. TransmitTime.QuadPart : ConformanceTime.QuadPart, 0, 0);
  1341. if (!Flow->Shape)
  1342. {
  1343. // No shaping in effect. Pass the packet on.
  1344. /* Since the packet is not being shaped, it could be non-conformant. So, need to reset it's 802.1p and
  1345. IP-Precedence values. */
  1346. if( (!Flow->NoConformance) &&
  1347. !PACKET_IS_CONFORMING(PacketInfo->ConformanceTime, CurrentTime, Pipe->TimerResolution))
  1348. {
  1349. NDIS_PACKET_8021Q_INFO VlanPriInfo;
  1350. VlanPriInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo);
  1351. VlanPriInfo.TagHeader.UserPriority = PacketInfo->UserPriorityNonConforming;
  1352. NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo) = VlanPriInfo.Value;
  1353. // Reset the TOS byte for IP Packets.
  1354. if(NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) == NDIS_PROTOCOL_ID_TCP_IP) {
  1355. if(!PacketInfo->IPHdr) {
  1356. PacketInfo->IPHdr = GetIpHeader(PacketInfo->IPHeaderOffset, Packet);
  1357. }
  1358. SET_TOS_XSUM(Packet,
  1359. PacketInfo->IPHdr,
  1360. PacketInfo->TOSNonConforming);
  1361. }
  1362. }
  1363. return (*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  1364. Pipe->ContextInfo.NextComponentContext,
  1365. Flow->ContextInfo.NextComponentContext,
  1366. (ClassMapContext != NULL) ? ClassMapContext->NextComponentContext : NULL,
  1367. PacketInfo);
  1368. }
  1369. LOCK_PIPE(Pipe);
  1370. if(Flow->State == TS_FLOW_DELETED)
  1371. {
  1372. UNLOCK_PIPE(Pipe);
  1373. return FALSE;
  1374. }
  1375. /* At this point, the conf-time of the packet is in TransmitTime
  1376. and the packetino->DelayTime has this info.
  1377. */
  1378. PacketInfo->FlowContext = FlowContext;
  1379. // If packet queue is not empty just queue the packet regardless of
  1380. // whether it is eligible. If it is eligible, the timer proc will
  1381. // detect this and send the packet. If not, it will insert the flow
  1382. // into the correct location in the flow list if necessary.
  1383. if (!IsListEmpty(&Flow->PacketQueue))
  1384. {
  1385. PsDbgSched(DBG_INFO,
  1386. DBG_SCHED_SHAPER,
  1387. SHAPER, PKT_ENQUEUE, Flow->PsFlowContext,
  1388. Packet, PacketInfo->PacketLength, 0,
  1389. 0,
  1390. PacketInfo->DelayTime.QuadPart,
  1391. Pipe->PacketsInShaper,
  1392. 0);
  1393. PacketInfo->ClassMapContext = ClassMapContext;
  1394. InsertTailList(&Flow->PacketQueue, &PacketInfo->SchedulerLinks);
  1395. }
  1396. else if(PacketIsEligible(PacketInfo, Flow, CurrentTime, ((TIMER_WHEEL_QTY/2) * MSIN100NS) ))
  1397. {
  1398. // Packet is eligible, so pass the packet on.
  1399. UNLOCK_PIPE(Pipe);
  1400. PsDbgSched(DBG_INFO,
  1401. DBG_SCHED_SHAPER,
  1402. SHAPER, PKT_DEQUEUE, Flow->PsFlowContext,
  1403. Packet, PacketInfo->PacketLength, 0,
  1404. CurrentTime.QuadPart,
  1405. PacketInfo->DelayTime.QuadPart,
  1406. Pipe->PacketsInShaper,
  1407. 0);
  1408. return (*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  1409. Pipe->ContextInfo.NextComponentContext,
  1410. Flow->ContextInfo.NextComponentContext,
  1411. (ClassMapContext != NULL) ? ClassMapContext->NextComponentContext : NULL,
  1412. PacketInfo);
  1413. }
  1414. else
  1415. {
  1416. // So, the packet is not eligible to be sent out right now, and the pkt-queue is empty
  1417. ULONG Slot= 0;
  1418. LARGE_INTEGER Ms;
  1419. LARGE_INTEGER TenMs;
  1420. LARGE_INTEGER CurrentTimeInMs, CurrentTimeInTenMs;
  1421. LONGLONG DeltaTimeInMs;
  1422. PLIST_ENTRY pList = NULL;
  1423. BOOL Success = FALSE;
  1424. //
  1425. // The first thing we do here is: If there is no timer allocated for this pipe, allocate one
  1426. // The FIRST packet to be shaped on the pipe will take a hit due to this..
  1427. //
  1428. if( !Pipe->pTimerWheel )
  1429. {
  1430. ULONG i =0;
  1431. PsAllocatePool( Pipe->pTimerWheel,
  1432. (sizeof(LIST_ENTRY) << Pipe->TimerWheelShift ),
  1433. TimerTag);
  1434. if( !Pipe->pTimerWheel)
  1435. {
  1436. UNLOCK_PIPE(Pipe);
  1437. // If we could not allocate memory for the timer, we are not going to shape the packet //
  1438. return (*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  1439. Pipe->ContextInfo.NextComponentContext,
  1440. Flow->ContextInfo.NextComponentContext,
  1441. (ClassMapContext != NULL) ? ClassMapContext->NextComponentContext : NULL,
  1442. PacketInfo);
  1443. }
  1444. // Initialize the Timer wheel //
  1445. pList = (PLIST_ENTRY)(Pipe->pTimerWheel);
  1446. for( i = 0; i < (ULONG) (1 << Pipe->TimerWheelShift); i++)
  1447. {
  1448. InitializeListHead( pList );
  1449. pList = (PLIST_ENTRY)((PCHAR)pList + sizeof(LIST_ENTRY));
  1450. }
  1451. }
  1452. Ms.QuadPart= 0;
  1453. PsDbgSched(DBG_INFO,
  1454. DBG_SCHED_SHAPER,
  1455. SHAPER, PKT_ENQUEUE, Flow->PsFlowContext,
  1456. Packet, PacketInfo->PacketLength, 0,
  1457. CurrentTime.QuadPart,
  1458. PacketInfo->DelayTime.QuadPart,
  1459. Pipe->PacketsInShaper,
  1460. 0);
  1461. PacketInfo->ClassMapContext = ClassMapContext;
  1462. InsertTailList(&Flow->PacketQueue, &PacketInfo->SchedulerLinks);
  1463. /* update the eligibility timer of the flow.. */
  1464. Flow->FlowEligibilityTime.QuadPart = PacketInfo->DelayTime.QuadPart;
  1465. /* Conf time in ms and 10ms */
  1466. Ms.QuadPart = OS_TIME_TO_MILLISECS( Flow->FlowEligibilityTime.QuadPart );
  1467. TenMs.QuadPart = Ms.QuadPart >> TIMER_WHEEL_SHIFT;
  1468. CurrentTimeInMs.QuadPart = OS_TIME_TO_MILLISECS( CurrentTime.QuadPart);
  1469. CurrentTimeInTenMs.QuadPart = CurrentTimeInMs.QuadPart >> TIMER_WHEEL_SHIFT;
  1470. /* Update the loop count too */
  1471. Flow->LoopCount = (ULONG)( (TenMs.QuadPart - CurrentTimeInTenMs.QuadPart) >> Pipe->TimerWheelShift );
  1472. if( Pipe->TimerStatus == TIMER_INACTIVE)
  1473. {
  1474. /* Figure out the Slot for this time.. */
  1475. Slot = (ULONG)( (TenMs.QuadPart) & ((1 << Pipe->TimerWheelShift) - 1 ) );
  1476. Pipe->SetTimerValue.QuadPart = TenMs.QuadPart - (Flow->LoopCount << Pipe->TimerWheelShift);
  1477. Pipe->SetSlotValue = Slot;
  1478. /* Need to insert the flow to the timer-wheel in slot's position*/
  1479. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  1480. InsertTailList(pList, &Flow->Links);
  1481. Pipe->TimerStatus = TIMER_SET;
  1482. NdisMSetTimer(&Pipe->Timer, (UINT)((Pipe->SetTimerValue.QuadPart - CurrentTimeInTenMs.QuadPart) << TIMER_WHEEL_SHIFT) );
  1483. }
  1484. else if( Pipe->TimerStatus == TIMER_SET)
  1485. {
  1486. if( TenMs.QuadPart <= Pipe->SetTimerValue.QuadPart)
  1487. {
  1488. Flow->LoopCount = 0;
  1489. /* Try to cancel the timer and re-set it */
  1490. NdisMCancelTimer( &Pipe->Timer, (PBOOLEAN)&Success );
  1491. if( Success)
  1492. {
  1493. /* Figure out the Slot for this time.. */
  1494. Slot = (ULONG)( (TenMs.QuadPart) & ((1 << Pipe->TimerWheelShift) - 1) );
  1495. // Pipe->SetTimerValue.QuadPart = TenMs.QuadPart - Flow->LoopCount * Pipe->TimerWheelSize ;
  1496. Pipe->SetTimerValue.QuadPart = TenMs.QuadPart - (Flow->LoopCount << Pipe->TimerWheelShift) ;
  1497. Pipe->SetSlotValue = Slot;
  1498. /* Need to insert the flow to the timer-wheel in slot's position*/
  1499. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  1500. InsertTailList(pList, &Flow->Links);
  1501. NdisMSetTimer(&Pipe->Timer, (UINT)((Pipe->SetTimerValue.QuadPart - CurrentTimeInTenMs.QuadPart) << TIMER_WHEEL_SHIFT));
  1502. }
  1503. else
  1504. {
  1505. /* Need to insert the flow to the timer-wheel in slot's position*/
  1506. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Pipe->SetSlotValue) );
  1507. InsertTailList(pList, &Flow->Links);
  1508. }
  1509. }
  1510. else
  1511. {
  1512. Flow->LoopCount = (ULONG)( (TenMs.QuadPart - Pipe->SetTimerValue.QuadPart) >> Pipe->TimerWheelShift );
  1513. /* Figure out the Slot for this time.. */
  1514. Slot = (ULONG)( (TenMs.QuadPart) & ((1 << Pipe->TimerWheelShift) - 1) );
  1515. /* Need to insert the flow to the timer-wheel in slot's position*/
  1516. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  1517. InsertTailList(pList, &Flow->Links);
  1518. }
  1519. }
  1520. else
  1521. {
  1522. PsAssert( Pipe->TimerStatus == TIMER_PROC_EXECUTING);
  1523. if( TenMs.QuadPart <= Pipe->ExecTimerValue.QuadPart)
  1524. {
  1525. PsAssert( Flow->LoopCount == 0);
  1526. Slot = (ULONG)((Pipe->ExecSlot + 1) & ((1 << Pipe->TimerWheelShift) - 1) );
  1527. /* Need to insert the flow to the timer-wheel in slot's position*/
  1528. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  1529. InsertTailList(pList, &Flow->Links);
  1530. }
  1531. else
  1532. {
  1533. Flow->LoopCount = (ULONG)( (TenMs.QuadPart - Pipe->ExecTimerValue.QuadPart) >> Pipe->TimerWheelShift );
  1534. /* Figure out the Slot for this time.. */
  1535. Slot = (ULONG)( (TenMs.QuadPart) & ((1 << Pipe->TimerWheelShift) - 1) );
  1536. if( Slot == Pipe->ExecSlot)
  1537. Slot = ( (Slot + 1) & ((1 << Pipe->TimerWheelShift) - 1) );
  1538. /* Need to insert the flow to the timer-wheel in slot's position*/
  1539. pList = (PLIST_ENTRY)( (char*)Pipe->pTimerWheel + ( sizeof(LIST_ENTRY) * Slot) );
  1540. InsertTailList(pList, &Flow->Links);
  1541. }
  1542. }
  1543. }
  1544. Pipe->PacketsInShaper++;
  1545. if(Pipe->PacketsInShaper > Pipe->sStats.MaxPacketsInShaper){
  1546. Pipe->sStats.MaxPacketsInShaper = Pipe->PacketsInShaper;
  1547. }
  1548. Flow->PacketsInShaper++;
  1549. if (Flow->PacketsInShaper > Flow->sStats.MaxPacketsInShaper) {
  1550. Flow->sStats.MaxPacketsInShaper = Flow->PacketsInShaper;
  1551. }
  1552. if(gEnableAvgStats)
  1553. {
  1554. Pipe->sStats.AveragePacketsInShaper =
  1555. RunningAverage(Pipe->PacketsInShaperAveragingArray, Pipe->PacketsInShaper);
  1556. Flow->sStats.AveragePacketsInShaper =
  1557. RunningAverage(Flow->PacketsInShaperAveragingArray, Flow->PacketsInShaper);
  1558. }
  1559. UNLOCK_PIPE(Pipe);
  1560. return TRUE;
  1561. } // TbcSubmitPacket
  1562. VOID
  1563. TbcSetInformation (
  1564. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  1565. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  1566. IN NDIS_OID Oid,
  1567. IN ULONG Len,
  1568. IN PVOID Data)
  1569. {
  1570. PTBC_PIPE Pipe = (PTBC_PIPE)ComponentPipeContext;
  1571. PTBC_FLOW Flow = (PTBC_FLOW)ComponentFlowContext;
  1572. switch(Oid)
  1573. {
  1574. case OID_QOS_STATISTICS_BUFFER:
  1575. if(Flow)
  1576. {
  1577. NdisZeroMemory(&Flow->cStats, sizeof(PS_CONFORMER_STATS));
  1578. NdisZeroMemory(&Flow->sStats, sizeof(PS_SHAPER_STATS));
  1579. }
  1580. else
  1581. {
  1582. NdisZeroMemory(&Pipe->cStats, sizeof(PS_CONFORMER_STATS));
  1583. NdisZeroMemory(&Pipe->sStats, sizeof(PS_SHAPER_STATS));
  1584. }
  1585. break;
  1586. default:
  1587. break;
  1588. }
  1589. (*Pipe->ContextInfo.NextComponent->SetInformation)(
  1590. Pipe->ContextInfo.NextComponentContext,
  1591. (Flow)?Flow->ContextInfo.NextComponentContext:0,
  1592. Oid,
  1593. Len,
  1594. Data);
  1595. }
  1596. VOID
  1597. TbcQueryInformation (
  1598. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  1599. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  1600. IN NDIS_OID Oid,
  1601. IN ULONG Len,
  1602. IN PVOID Data,
  1603. IN OUT PULONG BytesWritten,
  1604. IN OUT PULONG BytesNeeded,
  1605. IN OUT PNDIS_STATUS Status)
  1606. {
  1607. PTBC_PIPE Pipe = (PTBC_PIPE)ComponentPipeContext;
  1608. PTBC_FLOW Flow = (PTBC_FLOW)ComponentFlowContext;
  1609. ULONG Size;
  1610. ULONG cSize, sSize;
  1611. ULONG RemainingLength;
  1612. switch(Oid)
  1613. {
  1614. case OID_QOS_STATISTICS_BUFFER:
  1615. cSize = sizeof(PS_CONFORMER_STATS) + FIELD_OFFSET(PS_COMPONENT_STATS, Stats);
  1616. sSize = sizeof(PS_SHAPER_STATS) + FIELD_OFFSET(PS_COMPONENT_STATS, Stats);
  1617. Size = cSize + sSize;
  1618. if(*Status == NDIS_STATUS_SUCCESS)
  1619. {
  1620. //
  1621. // The previous component has succeeded - Let us
  1622. // see if we can write the data
  1623. //
  1624. RemainingLength = Len - *BytesWritten;
  1625. if(RemainingLength < Size) {
  1626. *Status = NDIS_STATUS_BUFFER_TOO_SHORT;
  1627. *BytesNeeded = Size + *BytesWritten;
  1628. *BytesWritten = 0;
  1629. }
  1630. else {
  1631. PPS_COMPONENT_STATS Cstats = (PPS_COMPONENT_STATS) Data;
  1632. *BytesWritten += Size;
  1633. *BytesNeeded = 0;
  1634. if(Flow)
  1635. {
  1636. // Per flow stats
  1637. Cstats->Type = PS_COMPONENT_CONFORMER;
  1638. Cstats->Length = sizeof(PS_CONFORMER_STATS);
  1639. NdisMoveMemory(&Cstats->Stats, &Flow->cStats, sizeof(PS_CONFORMER_STATS));
  1640. // Move the pointer to point after the conf. stats.. //
  1641. Cstats = (PPS_COMPONENT_STATS)((PUCHAR)Cstats + cSize);
  1642. Cstats->Type = PS_COMPONENT_SHAPER;
  1643. Cstats->Length = sizeof(PS_SHAPER_STATS);
  1644. NdisMoveMemory(&Cstats->Stats, &Flow->sStats, sizeof(PS_SHAPER_STATS));
  1645. }
  1646. else
  1647. {
  1648. // Per adapter stats
  1649. Cstats->Type = PS_COMPONENT_CONFORMER;
  1650. Cstats->Length = sizeof(PS_CONFORMER_STATS);
  1651. NdisMoveMemory(&Cstats->Stats, &Pipe->cStats, sizeof(PS_CONFORMER_STATS));
  1652. // Move the pointer to point after the shaper. stats.. //
  1653. Cstats = (PPS_COMPONENT_STATS)((PUCHAR)Cstats + cSize);
  1654. Cstats->Type = PS_COMPONENT_SHAPER;
  1655. Cstats->Length = sizeof(PS_SHAPER_STATS);
  1656. NdisMoveMemory(&Cstats->Stats, &Pipe->sStats, sizeof(PS_SHAPER_STATS));
  1657. }
  1658. //
  1659. // Advance Data so that the next component can update its stats
  1660. //
  1661. Data = (PVOID) ((PUCHAR)Data + Size);
  1662. }
  1663. }
  1664. else {
  1665. *BytesNeeded += Size;
  1666. *BytesWritten = 0;
  1667. }
  1668. break;
  1669. default:
  1670. break;
  1671. }
  1672. (*Pipe->ContextInfo.NextComponent->QueryInformation)(
  1673. Pipe->ContextInfo.NextComponentContext,
  1674. (Flow)?Flow->ContextInfo.NextComponentContext : 0,
  1675. Oid,
  1676. Len,
  1677. Data,
  1678. BytesWritten,
  1679. BytesNeeded,
  1680. Status);
  1681. }