Source code of Windows XP (NT5)
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.

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