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.

1980 lines
58 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. DRRSeq.c
  5. Abstract:
  6. Priority/DRR Sequencer. This module is a scheduling component that
  7. determines the order in which submitted packets should be sent.
  8. Author:
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "psched.h"
  14. #pragma hdrstop
  15. // The sequencer classifies each flow into an internal "priority group" based
  16. // on the flow's service type and conformance status. Within each priority
  17. // group, there may be one or more priority levels or offsets. The total
  18. // number of internal priority levels is the sum of the priority levels for
  19. // each priority group. The internal priority assigned to each flow is
  20. // calculated from the priority group and the relative priority within the
  21. // group, which is obtained from the QOS Priority object. The 802.1 priority,
  22. // is set by the wrapper. The non conforming values are obtained from the
  23. // packet.
  24. //
  25. // The flows of the following servicetypes have no internal priority.
  26. // SERVICETYPE_BESTEFFORT
  27. // SERVICETYPE_NONCONFORMING
  28. // SERVICETYPE_QUALITATIVE.
  29. //
  30. // SERVICETYPE_BESTEFFORT is treated as SERVICETYPE_QUALITATIVE in the sequencer, so the no of priority
  31. // groups is 1 less than the no. of servicetypes.
  32. #define RELATIVE_PRIORITIES 8
  33. #define PRIORITY_GROUPS (NUM_TC_SERVICETYPES - 1)
  34. #define INTERNAL_PRIORITIES (((PRIORITY_GROUPS - 2) * RELATIVE_PRIORITIES) + 2)
  35. #define DEFAULT_PRIORITY_OFFSET 3
  36. #define DEFAULT_MIN_QUANTUM 1500
  37. #define PRIORITY_GROUP_NON_CONFORMING 0
  38. #define PRIORITY_GROUP_BEST_EFFORT 1
  39. #define PRIORITY_GROUP_CONTROLLED_LOAD 2
  40. #define PRIORITY_GROUP_GUARANTEED 3
  41. #define PRIORITY_GROUP_NETWORK_CONTROL 4
  42. //
  43. // For maintaining stats
  44. //
  45. #define SEQUENCER_AVERAGING_ARRAY_SIZE 256
  46. #define NETCARD_AVERAGING_ARRAY_SIZE 256
  47. #define SEQUENCER_FLOW_AVERAGING_ARRAY_SIZE 256
  48. // The DRR Sequencer's pipe information
  49. typedef struct _DSEQ_PIPE {
  50. // ContextInfo - Generic context info
  51. // Lock - Protects pipe and flow data
  52. // Flags - See below
  53. // Flows - List of all installed flows
  54. // ActiveFlows - Lists of flows that are waiting to send packets
  55. // PriorityLevels - Number of priority offsets for each priority group
  56. // StartPriority - Lowest internal priority value for each priority group
  57. // ActiveFlowCount - Number of active flows for each service type
  58. // MaxOutstandingSends - Maximum number of outstanding sends
  59. // OutstandingSends - Number of outstanding sends
  60. // PacketsInNetcardAveragingArray
  61. // PacketsInSequencer - Current number packets in sequencer
  62. // PacketsInSequencerAveragingArray
  63. // Bandwidth - Link speed
  64. // MinimumQuantum - Minimum quantum size for DRR
  65. // MinimumRate - Smallest rate currently assigned to a flow
  66. // TimerResolution - Timer resolution in OS time units
  67. // PsFlags - Flags from pipe parameters
  68. // PsPipeContext - PS's pipe context value
  69. PS_PIPE_CONTEXT ContextInfo;
  70. PS_DRRSEQ_STATS Stats;
  71. PRUNNING_AVERAGE PacketsInNetcardAveragingArray;
  72. ULONG PacketsInSequencer;
  73. PRUNNING_AVERAGE PacketsInSequencerAveragingArray;
  74. NDIS_SPIN_LOCK Lock;
  75. ULONG Flags;
  76. LIST_ENTRY Flows;
  77. LIST_ENTRY ActiveFlows[INTERNAL_PRIORITIES];
  78. ULONG PriorityLevels[PRIORITY_GROUPS];
  79. ULONG StartPriority[PRIORITY_GROUPS];
  80. ULONG ActiveFlowCount[PRIORITY_GROUPS];
  81. ULONG TotalActiveFlows;
  82. ULONG MaxOutstandingSends;
  83. ULONG ConfiguredMaxOutstandingSends;
  84. // This is added to keep track of what the Registry/User-asked value of MOS is, while we might
  85. // have changed MOS to be able to do DRR on this Pipe/WanLink. When we switch back from DRR mode
  86. // with MOS=1, we'll use this going forward.
  87. ULONG IsslowFlowCount;
  88. // This is added to keep track of the number of active/current ISSLOW flows. We will do DRR on this
  89. // WanLink (if it is a WanLink) only if this count is 0.
  90. ULONG OutstandingSends;
  91. ULONG Bandwidth;
  92. ULONG MinimumQuantum;
  93. ULONG MinimumRate;
  94. ULONG TimerResolution;
  95. ULONG PsFlags;
  96. HANDLE PsPipeContext;
  97. PPS_PROCS PsProcs;
  98. PSU_SEND_COMPLETE PreviousUpcallsSendComplete;
  99. PPS_PIPE_CONTEXT PreviousUpcallsSendCompletePipeContext;
  100. } DSEQ_PIPE, *PDSEQ_PIPE;
  101. // Pipe flag values
  102. #define DSEQ_DEQUEUE 1
  103. #define DSEQ_PASSTHRU 2
  104. typedef enum _FLOW_STATE {
  105. DRRSEQ_FLOW_CREATED = 1,
  106. DRRSEQ_FLOW_DELETED
  107. } FLOW_STATE;
  108. // The DRR Sequencer's flow information
  109. typedef struct _DSEQ_FLOW {
  110. // ContextInfo - Generic context info
  111. // ActiveLinks - Links in active flow list
  112. // Links - Links in installed flow list
  113. // PacketQueue - Self-explanatory
  114. // PacketSendTime - Send time for current packet
  115. // LastConformanceTime - Absolute conformance time of last packet
  116. // TokenRate - TokenRate from GQOS
  117. // UserPriority - Priority offset assigned by user
  118. // Priority - Internal priority
  119. // PriorityGroup - Priority group for flow
  120. // Quantum - Quantum assigned to flow for DRR
  121. // DeficitCounter - Current value of DRR deficit counter
  122. // Flags - See below
  123. // PsFlowContext - PS's flow context value
  124. // BucketSize - TokenBucketSize from GQOS
  125. // NumPacketsInSeq - Number of packets from this flow in the sequencer
  126. // PacketsInSeqAveragingArray-Data for computing average packets in seq from this flow
  127. PS_FLOW_CONTEXT ContextInfo;
  128. LIST_ENTRY ActiveLinks;
  129. LIST_ENTRY Links;
  130. LIST_ENTRY PacketQueue;
  131. LARGE_INTEGER PacketSendTime;
  132. LARGE_INTEGER LastConformanceTime;
  133. ULONG TokenRate;
  134. ULONG UserPriority;
  135. ULONG Priority;
  136. ULONG PriorityGroup;
  137. ULONG Quantum;
  138. ULONG DeficitCounter;
  139. ULONG Flags;
  140. HANDLE PsFlowContext;
  141. ULONG BucketSize;
  142. ULONG PacketsInSequencer;
  143. PS_DRRSEQ_STATS Stats;
  144. PRUNNING_AVERAGE PacketsInSeqAveragingArray;
  145. FLOW_STATE State;
  146. } DSEQ_FLOW, *PDSEQ_FLOW;
  147. #define MAX_DEQUEUED_PACKETS 8
  148. //
  149. // Values for Drr Seq Flow flags: [ Don't know why 1 was not used here]
  150. #define FLOW_USER_PRIORITY 0x00000002
  151. // GPC_ISSLOW_FLOW 0x00000040 Indicates that this is an ISSLOW flow.
  152. // Make sure not to use the same flag for something else.
  153. // The following macro checks a packet for conformance based on the flow's
  154. // LastPacketTime, the current time, and the timer resolution.
  155. #define PacketIsConforming(_flow, _packetinfo, _curtime, _r) \
  156. ( (_flow)->PacketSendTime.QuadPart <= ((_curtime).QuadPart + (_r)) && \
  157. (_packetinfo)->PacketLength <= (_flow)->BucketSize \
  158. )
  159. #define AdjustLastPacketTime(_flow, _curtime, _r) \
  160. if ((_curtime).QuadPart > ((_flow)->PacketSendTime.QuadPart + (_r))) \
  161. if ((_curtime).QuadPart > ((_flow)->LastConformanceTime.QuadPart - (_r))) \
  162. (_flow)->PacketSendTime = (_flow)->LastConformanceTime; \
  163. else \
  164. (_flow)->PacketSendTime = (_curtime);
  165. #define LOCK_PIPE(_p) NdisAcquireSpinLock(&(_p)->Lock)
  166. #define UNLOCK_PIPE(_p) NdisReleaseSpinLock(&(_p)->Lock)
  167. /* External */
  168. /* Static */
  169. /* Forward */
  170. NDIS_STATUS
  171. DrrSeqInitializePipe (
  172. IN HANDLE PsPipeContext,
  173. IN PPS_PIPE_PARAMETERS PipeParameters,
  174. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  175. IN PPS_PROCS PsProcs,
  176. IN PPS_UPCALLS Upcalls
  177. );
  178. NDIS_STATUS
  179. DrrSeqModifyPipe (
  180. IN PPS_PIPE_CONTEXT PipeContext,
  181. IN PPS_PIPE_PARAMETERS PipeParameters
  182. );
  183. VOID
  184. DrrSeqDeletePipe (
  185. IN PPS_PIPE_CONTEXT PipeContext
  186. );
  187. NDIS_STATUS
  188. DrrSeqCreateFlow (
  189. IN PPS_PIPE_CONTEXT PipeContext,
  190. IN HANDLE PsFlowContext,
  191. IN PCO_CALL_PARAMETERS CallParameters,
  192. IN PPS_FLOW_CONTEXT ComponentFlowContext
  193. );
  194. NDIS_STATUS
  195. DrrSeqModifyFlow (
  196. IN PPS_PIPE_CONTEXT PipeContext,
  197. IN PPS_FLOW_CONTEXT FlowContext,
  198. IN PCO_CALL_PARAMETERS CallParameters
  199. );
  200. VOID
  201. DrrSeqDeleteFlow (
  202. IN PPS_PIPE_CONTEXT PipeContext,
  203. IN PPS_FLOW_CONTEXT FlowContext
  204. );
  205. VOID
  206. DrrSeqEmptyFlow (
  207. IN PPS_PIPE_CONTEXT PipeContext,
  208. IN PPS_FLOW_CONTEXT FlowContext
  209. );
  210. static NDIS_STATUS
  211. DrrSeqCreateClassMap (
  212. IN PPS_PIPE_CONTEXT PipeContext,
  213. IN HANDLE PsClassMapContext,
  214. IN PTC_CLASS_MAP_FLOW ClassMap,
  215. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
  216. );
  217. static NDIS_STATUS
  218. DrrSeqDeleteClassMap (
  219. IN PPS_PIPE_CONTEXT PipeContext,
  220. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
  221. );
  222. BOOLEAN
  223. DrrSeqSubmitPacket (
  224. IN PPS_PIPE_CONTEXT PipeContext,
  225. IN PPS_FLOW_CONTEXT FlowContext,
  226. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  227. IN PPACKET_INFO_BLOCK PacketInfo
  228. );
  229. VOID
  230. DrrSeqSendComplete (
  231. IN PPS_PIPE_CONTEXT PipeContext,
  232. IN PNDIS_PACKET Packet
  233. );
  234. VOID
  235. DrrSetInformation(
  236. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  237. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  238. IN NDIS_OID Oid,
  239. IN ULONG Len,
  240. IN PVOID Data);
  241. VOID
  242. DrrQueryInformation (
  243. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  244. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  245. IN NDIS_OID Oid,
  246. IN ULONG Len,
  247. IN PVOID Data,
  248. IN OUT PULONG BytesWritten,
  249. IN OUT PULONG BytesNeeded,
  250. IN OUT PNDIS_STATUS Status);
  251. VOID
  252. DrrSeqSendComplete (
  253. IN PPS_PIPE_CONTEXT PipeContext,
  254. IN PNDIS_PACKET Packet
  255. );
  256. /* End Forward */
  257. VOID
  258. InitializeDrrSequencer(
  259. PPSI_INFO Info)
  260. /*++
  261. Routine Description:
  262. Initialization routine for the DRR sequencer. This routine just
  263. fills in the PSI_INFO struct and returns.
  264. Arguments:
  265. Info - Pointer to component interface info struct
  266. Return Values:
  267. NDIS_STATUS_SUCCESS
  268. --*/
  269. {
  270. Info->PipeContextLength = ((sizeof(DSEQ_PIPE) + 7) & ~7);
  271. Info->FlowContextLength = ((sizeof(DSEQ_FLOW) + 7) & ~7);
  272. Info->ClassMapContextLength = sizeof(PS_CLASS_MAP_CONTEXT);
  273. Info->InitializePipe = DrrSeqInitializePipe;
  274. Info->ModifyPipe = DrrSeqModifyPipe;
  275. Info->DeletePipe = DrrSeqDeletePipe;
  276. Info->CreateFlow = DrrSeqCreateFlow;
  277. Info->ModifyFlow = DrrSeqModifyFlow;
  278. Info->DeleteFlow = DrrSeqDeleteFlow;
  279. Info->EmptyFlow = DrrSeqEmptyFlow;
  280. Info->CreateClassMap = DrrSeqCreateClassMap;
  281. Info->DeleteClassMap = DrrSeqDeleteClassMap;
  282. Info->SubmitPacket = DrrSeqSubmitPacket;
  283. Info->ReceivePacket = NULL;
  284. Info->ReceiveIndication = NULL;
  285. Info->SetInformation = DrrSetInformation;
  286. Info->QueryInformation = DrrQueryInformation;
  287. } // InitializeDrrSequencer
  288. VOID
  289. CleanupDrrSequencer(
  290. VOID)
  291. /*++
  292. Routine Description:
  293. Cleanup routine for the DRR sequencer.
  294. Arguments:
  295. Return Values:
  296. NDIS_STATUS_SUCCESS
  297. --*/
  298. {
  299. } // CleanupDrrSequencer
  300. VOID
  301. AdjustFlowQuanta(
  302. PDSEQ_PIPE Pipe,
  303. ULONG MinRate)
  304. /*++
  305. Routine Description:
  306. Adjust the quantum value for all flows based on the new minimum value. If MinRate
  307. is unspecified then a search for the new minimum rate will be performed.
  308. Arguments:
  309. Pipe - Pointer to pipe context information
  310. MinRate - New value for minimum rate, or GQPS_UNSPECIFIED to force a search
  311. Return Values:
  312. --*/
  313. {
  314. PDSEQ_FLOW Flow;
  315. PLIST_ENTRY Entry;
  316. if (MinRate == QOS_NOT_SPECIFIED) {
  317. if (Pipe->Bandwidth != 0) {
  318. MinRate = Pipe->Bandwidth;
  319. }
  320. for (Entry = Pipe->Flows.Flink; Entry != &Pipe->Flows; Entry = Entry->Flink) {
  321. Flow = CONTAINING_RECORD(Entry, DSEQ_FLOW, Links);
  322. if ((Flow->TokenRate < MinRate) && (Flow->PriorityGroup > PRIORITY_GROUP_BEST_EFFORT) &&
  323. (Flow->PriorityGroup != PRIORITY_GROUP_NETWORK_CONTROL)) {
  324. MinRate = Flow->TokenRate;
  325. }
  326. }
  327. }
  328. for (Entry = Pipe->Flows.Flink; Entry != &Pipe->Flows; Entry = Entry->Flink) {
  329. Flow = CONTAINING_RECORD(Entry, DSEQ_FLOW, Links);
  330. if ((Flow->TokenRate == QOS_NOT_SPECIFIED) ||
  331. (Flow->PriorityGroup == PRIORITY_GROUP_NETWORK_CONTROL) ||
  332. (Flow->PriorityGroup <= PRIORITY_GROUP_BEST_EFFORT)) {
  333. Flow->Quantum = Pipe->MinimumQuantum;
  334. } else {
  335. Flow->Quantum = (ULONG)((ULONGLONG)(Flow->TokenRate * Pipe->MinimumQuantum) / MinRate);
  336. }
  337. PsAssert((LONG)Flow->Quantum > 0);
  338. }
  339. Pipe->MinimumRate = MinRate;
  340. PsAssert(Pipe->MinimumRate != 0);
  341. } // AdjustFlowQuanta
  342. VOID
  343. DequeuePackets(
  344. PDSEQ_PIPE Pipe)
  345. /*++
  346. Routine Description:
  347. Select the next packet(s) to send. The lock must be held upon entry to this
  348. routine.
  349. Arguments:
  350. Pipe - Pointer to pipe context information
  351. Return Values:
  352. --*/
  353. {
  354. PDSEQ_FLOW Flow;
  355. LARGE_INTEGER CurrentTime;
  356. PLIST_ENTRY LowPriorityList = &Pipe->ActiveFlows[0];
  357. PLIST_ENTRY CurrentLink;
  358. PPACKET_INFO_BLOCK PacketInfo;
  359. PNDIS_PACKET Packet;
  360. ULONG Priority;
  361. ULONG PriorityGroup;
  362. PPACKET_INFO_BLOCK PacketsToSend[MAX_DEQUEUED_PACKETS];
  363. ULONG SendingPriority[MAX_DEQUEUED_PACKETS];
  364. ULONG PacketSendCount = 0;
  365. ULONG MaxDequeuedPackets = Pipe->MaxOutstandingSends - Pipe->OutstandingSends;
  366. ULONG i;
  367. // Need to call this to disable the user APCs after this point.
  368. // Note that the DDK says it should be called at PASSIVE. But it can very well be
  369. // called at DISPATCH.
  370. KeEnterCriticalRegion();
  371. Pipe->Flags |= DSEQ_DEQUEUE;
  372. PsGetCurrentTime(&CurrentTime);
  373. PsAssert(Pipe->MaxOutstandingSends >= Pipe->OutstandingSends);
  374. if (MaxDequeuedPackets > MAX_DEQUEUED_PACKETS) {
  375. MaxDequeuedPackets = MAX_DEQUEUED_PACKETS;
  376. }
  377. // First update the conformance status of the flows in the lowest priority list
  378. CurrentLink = LowPriorityList->Flink;
  379. while (CurrentLink != LowPriorityList) {
  380. // Get the flow pointer from the linkage and set new value for CurrentLink
  381. Flow = CONTAINING_RECORD(CurrentLink, DSEQ_FLOW, ActiveLinks);
  382. CurrentLink = CurrentLink->Flink;
  383. // If this flow's priority is higher than the DRR priority, then
  384. // it is a candidate for a status change.
  385. if (Flow->Priority > 0) {
  386. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  387. if (PacketIsConforming(Flow, PacketInfo, CurrentTime, Pipe->TimerResolution)) {
  388. // Move flow to higher priority list
  389. Flow->DeficitCounter = Flow->Quantum;
  390. RemoveEntryList(&Flow->ActiveLinks);
  391. InsertTailList(&Pipe->ActiveFlows[Flow->Priority], &Flow->ActiveLinks);
  392. }
  393. }
  394. }
  395. // Now select the next packet(s) to send
  396. for (PriorityGroup = PRIORITY_GROUPS - 1;
  397. ((PriorityGroup > 0) && (Pipe->ActiveFlowCount[PriorityGroup] == 0));
  398. PriorityGroup--) ;
  399. Priority = Pipe->StartPriority[PriorityGroup] + Pipe->PriorityLevels[PriorityGroup] - 1;
  400. while ((PacketSendCount < MaxDequeuedPackets) &&
  401. (Pipe->TotalActiveFlows > 0) &&
  402. Priority < INTERNAL_PRIORITIES) {
  403. if (!IsListEmpty(&Pipe->ActiveFlows[Priority])) {
  404. // Get first flow in the current list, and get a pointer to the info
  405. // about the first packet
  406. CurrentLink = Pipe->ActiveFlows[Priority].Flink;
  407. Flow = CONTAINING_RECORD(CurrentLink, DSEQ_FLOW, ActiveLinks);
  408. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  409. if (Pipe->PsFlags & PS_DISABLE_DRR) {
  410. // DRR is disabled. Remove the first packet from the queue
  411. // and send it.
  412. RemoveEntryList(&PacketInfo->SchedulerLinks);
  413. Flow->LastConformanceTime.QuadPart = PacketInfo->ConformanceTime.QuadPart;
  414. if (Priority > 0) {
  415. AdjustLastPacketTime(Flow, CurrentTime, Pipe->TimerResolution);
  416. } else {
  417. Flow->PacketSendTime = CurrentTime;
  418. }
  419. InterlockedIncrement( &Pipe->OutstandingSends );
  420. if(Pipe->OutstandingSends > Pipe->Stats.MaxPacketsInNetcard){
  421. Pipe->Stats.MaxPacketsInNetcard = Pipe->OutstandingSends;
  422. }
  423. if(gEnableAvgStats)
  424. {
  425. //
  426. // Track max packets outstanding. This is a measure
  427. // of how congested the media gets. Of course, it
  428. // will be clipped by the MaxOutstandingSends parameter.
  429. // So - for a valid reading, need to set MOS very large.
  430. //
  431. Pipe->Stats.AveragePacketsInNetcard =
  432. RunningAverage(Pipe->PacketsInNetcardAveragingArray,
  433. Pipe->OutstandingSends);
  434. }
  435. SendingPriority[PacketSendCount] = Priority;
  436. PacketsToSend[PacketSendCount++] = PacketInfo;
  437. // For logging purposes...
  438. PacketInfo->ConformanceTime = Flow->PacketSendTime;
  439. // If the flow has no more packets to send, remove it from the list.
  440. // Otherwise move it to the end of the appropriate list, depending on
  441. // the conformance time of the next packet.
  442. RemoveEntryList(&Flow->ActiveLinks);
  443. if (IsListEmpty(&Flow->PacketQueue)) {
  444. Pipe->TotalActiveFlows--;
  445. Pipe->ActiveFlowCount[Flow->PriorityGroup]--;
  446. }
  447. else {
  448. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  449. Flow->PacketSendTime.QuadPart +=
  450. (PacketInfo->ConformanceTime.QuadPart - Flow->LastConformanceTime.QuadPart);
  451. if (!PacketIsConforming(Flow, PacketInfo, CurrentTime, Pipe->TimerResolution)) {
  452. InsertTailList(LowPriorityList, &Flow->ActiveLinks);
  453. } else {
  454. InsertTailList(&Pipe->ActiveFlows[Priority], &Flow->ActiveLinks);
  455. }
  456. }
  457. }
  458. else if (PacketInfo->PacketLength <= Flow->DeficitCounter) {
  459. // DRR is being used and the flow has a large enough deficit counter
  460. // to send the packet. Remove the packet from the queue and send it.
  461. RemoveEntryList(&PacketInfo->SchedulerLinks);
  462. Flow->LastConformanceTime.QuadPart = PacketInfo->ConformanceTime.QuadPart;
  463. if (Priority > 0) {
  464. AdjustLastPacketTime(Flow, CurrentTime, Pipe->TimerResolution);
  465. } else {
  466. Flow->PacketSendTime = CurrentTime;
  467. }
  468. Flow->DeficitCounter -= PacketInfo->PacketLength;
  469. InterlockedIncrement( &Pipe->OutstandingSends );
  470. if(Pipe->OutstandingSends > Pipe->Stats.MaxPacketsInNetcard){
  471. Pipe->Stats.MaxPacketsInNetcard = Pipe->OutstandingSends;
  472. }
  473. if(gEnableAvgStats)
  474. {
  475. //
  476. // Track max packets outstanding. This is a measure
  477. // of how congested the media gets. Of course, it
  478. // will be clipped by the MaxOutstandingSends parameter.
  479. // So - for a valid reading, need to set MOS very large.
  480. //
  481. Pipe->Stats.AveragePacketsInNetcard =
  482. RunningAverage(Pipe->PacketsInNetcardAveragingArray,
  483. Pipe->OutstandingSends);
  484. }
  485. SendingPriority[PacketSendCount] = Priority;
  486. PacketsToSend[PacketSendCount++] = PacketInfo;
  487. // For logging purposes...
  488. PacketInfo->ConformanceTime = Flow->PacketSendTime;
  489. // If the flow has no more packets to send, remove it from the list.
  490. // If the flow still has conforming packets to send, leave it at the head
  491. // of the list. If the flow has non-conforming packets to send, move it
  492. // to the lowest priority list. If we are servicing the zero priority
  493. // level, then no conformance checking is necessary.
  494. if (IsListEmpty(&Flow->PacketQueue)) {
  495. RemoveEntryList(&Flow->ActiveLinks);
  496. Pipe->TotalActiveFlows--;
  497. Pipe->ActiveFlowCount[Flow->PriorityGroup]--;
  498. }
  499. else {
  500. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  501. Flow->PacketSendTime.QuadPart +=
  502. (PacketInfo->ConformanceTime.QuadPart - Flow->LastConformanceTime.QuadPart);
  503. if ((Priority > 0) &&
  504. !PacketIsConforming(Flow, PacketInfo, CurrentTime, Pipe->TimerResolution)) {
  505. Flow->DeficitCounter = Flow->Quantum;
  506. RemoveEntryList(&Flow->ActiveLinks);
  507. InsertTailList(LowPriorityList, &Flow->ActiveLinks);
  508. }
  509. }
  510. }
  511. else {
  512. // The packet cannot be sent because the flow's deficit counter
  513. // is too small. Place the flow at the end of the same priority
  514. // queue and increment the flow's deficit counter by its quantum.
  515. Flow->DeficitCounter += Flow->Quantum;
  516. RemoveEntryList(&Flow->ActiveLinks);
  517. InsertTailList(&Pipe->ActiveFlows[Priority], &Flow->ActiveLinks);
  518. }
  519. }
  520. else {
  521. Priority--;
  522. }
  523. }
  524. //
  525. // We're gonna send these now, which means they're leaving the
  526. // sequencer. Update the stats.
  527. //
  528. Pipe->PacketsInSequencer -= PacketSendCount;
  529. Flow->PacketsInSequencer -= PacketSendCount;
  530. if(gEnableAvgStats)
  531. {
  532. Flow->Stats.AveragePacketsInSequencer =
  533. RunningAverage(Flow->PacketsInSeqAveragingArray,
  534. Flow->PacketsInSequencer);
  535. }
  536. // Send the next group of packets
  537. UNLOCK_PIPE(Pipe);
  538. if (PacketSendCount == 0) {
  539. PsDbgOut(DBG_CRITICAL_ERROR, DBG_SCHED_DRR, ("PSCHED: No packets selected\n"));
  540. }
  541. for (i = 0; i < PacketSendCount; i++) {
  542. PacketInfo = PacketsToSend[i];
  543. Flow = (PDSEQ_FLOW)PacketInfo->FlowContext;
  544. Packet = PacketInfo->NdisPacket;
  545. //
  546. // The 802.1 priority is already set by the wrapper. But, if the packet
  547. // is non-conforming, then we want to reset it. We also want to clear
  548. // the IP Precedence Bits.
  549. //
  550. if ((SendingPriority[i] == 0)) {
  551. //
  552. // Non conforming packet!
  553. //
  554. NDIS_PACKET_8021Q_INFO VlanPriInfo;
  555. VlanPriInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo);
  556. VlanPriInfo.TagHeader.UserPriority = PacketInfo->UserPriorityNonConforming;
  557. NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo) = VlanPriInfo.Value;
  558. Flow->Stats.NonconformingPacketsTransmitted ++;
  559. Pipe->Stats.NonconformingPacketsTransmitted ++;
  560. //
  561. // Reset the TOS byte for IP Packets.
  562. //
  563. if(NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) == NDIS_PROTOCOL_ID_TCP_IP) {
  564. if(!PacketInfo->IPHdr) {
  565. PacketInfo->IPHdr = GetIpHeader(PacketInfo->IPHeaderOffset, Packet);
  566. }
  567. SET_TOS_XSUM(Packet,
  568. PacketInfo->IPHdr,
  569. PacketInfo->TOSNonConforming);
  570. }
  571. }
  572. PsDbgSched(DBG_INFO, DBG_SCHED_DRR,
  573. DRR_SEQUENCER, PKT_DEQUEUE, Flow->PsFlowContext,
  574. Packet, PacketInfo->PacketLength, SendingPriority[i],
  575. CurrentTime.QuadPart,
  576. PacketInfo->ConformanceTime.QuadPart,
  577. Pipe->PacketsInSequencer,
  578. 0);
  579. if (!(*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  580. Pipe->ContextInfo.NextComponentContext,
  581. Flow->ContextInfo.NextComponentContext,
  582. (PacketInfo->ClassMapContext != NULL) ?
  583. ((PPS_CLASS_MAP_CONTEXT)PacketInfo->ClassMapContext)->NextComponentContext : NULL,
  584. PacketInfo)) {
  585. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  586. }
  587. }
  588. LOCK_PIPE(Pipe);
  589. Pipe->Flags &= ~DSEQ_DEQUEUE;
  590. // Re-enable the APCs again.
  591. KeLeaveCriticalRegion();
  592. } // DequeuePackets
  593. NDIS_STATUS
  594. DrrSeqInitializePipe (
  595. IN HANDLE PsPipeContext,
  596. IN PPS_PIPE_PARAMETERS PipeParameters,
  597. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  598. IN PPS_PROCS PsProcs,
  599. IN PPS_UPCALLS Upcalls
  600. )
  601. /*++
  602. Routine Description:
  603. Pipe initialization routine for the DRR sequencer.
  604. Arguments:
  605. PsPipeContext - PS pipe context value
  606. PipeParameters - Pointer to pipe parameters
  607. ComponentPipeContext - Pointer to this component's context area
  608. PsProcs - PS's support routines
  609. Upcalls - Previous component's upcall table
  610. Return Values:
  611. Status value from next component
  612. --*/
  613. {
  614. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)ComponentPipeContext;
  615. HANDLE NdisHandle;
  616. ULONG i;
  617. ULONG PriorityLevel = 0;
  618. PS_UPCALLS DrrSeqUpcalls;
  619. NDIS_STATUS Status;
  620. NdisAllocateSpinLock(&Pipe->Lock);
  621. Pipe->Flags = 0;
  622. //
  623. // Relative Priorities allow us to further subdivide each priority group
  624. // into sub priorities. This does not exist for NonConforming, BestEffort,
  625. // and Qualitative.
  626. //
  627. Pipe->PriorityLevels[PRIORITY_GROUP_NON_CONFORMING] = 1;
  628. Pipe->PriorityLevels[PRIORITY_GROUP_BEST_EFFORT] = 1;
  629. Pipe->PriorityLevels[PRIORITY_GROUP_CONTROLLED_LOAD] = RELATIVE_PRIORITIES;
  630. Pipe->PriorityLevels[PRIORITY_GROUP_GUARANTEED] = RELATIVE_PRIORITIES;
  631. Pipe->PriorityLevels[PRIORITY_GROUP_NETWORK_CONTROL] = RELATIVE_PRIORITIES;
  632. InitializeListHead(&Pipe->Flows);
  633. for (i = 0; i < INTERNAL_PRIORITIES; i++) {
  634. InitializeListHead(&Pipe->ActiveFlows[i]);
  635. }
  636. for (i = 0; i < PRIORITY_GROUPS; i++) {
  637. Pipe->ActiveFlowCount[i] = 0;
  638. Pipe->StartPriority[i] = PriorityLevel;
  639. PriorityLevel += Pipe->PriorityLevels[i];
  640. }
  641. Pipe->TotalActiveFlows = 0;
  642. Pipe->OutstandingSends = 0;
  643. NdisZeroMemory(&Pipe->Stats, sizeof(PS_DRRSEQ_STATS));
  644. Pipe->PacketsInSequencer = 0;
  645. Pipe->PacketsInSequencerAveragingArray = NULL;
  646. Pipe->PacketsInNetcardAveragingArray = NULL;
  647. Status = CreateAveragingArray(&Pipe->PacketsInSequencerAveragingArray,
  648. SEQUENCER_AVERAGING_ARRAY_SIZE);
  649. if(Status != NDIS_STATUS_SUCCESS)
  650. {
  651. return(Status);
  652. }
  653. Status = CreateAveragingArray(&Pipe->PacketsInNetcardAveragingArray,
  654. NETCARD_AVERAGING_ARRAY_SIZE);
  655. if(Status != NDIS_STATUS_SUCCESS)
  656. {
  657. DeleteAveragingArray(Pipe->PacketsInSequencerAveragingArray);
  658. return(Status);
  659. }
  660. Pipe->MinimumQuantum = PipeParameters->MTUSize - PipeParameters->HeaderSize;
  661. if (Pipe->MinimumQuantum == 0) {
  662. Pipe->MinimumQuantum = DEFAULT_MIN_QUANTUM;
  663. }
  664. Pipe->Bandwidth = PipeParameters->Bandwidth;
  665. // This will be set to something more realistic when the first flow is created.
  666. Pipe->MinimumRate = (PipeParameters->Bandwidth > 0) ? PipeParameters->Bandwidth : QOS_NOT_SPECIFIED;
  667. PsAssert(Pipe->MinimumRate != 0);
  668. Pipe->PsFlags = PipeParameters->Flags;
  669. Pipe->IsslowFlowCount = 0;
  670. Pipe->ConfiguredMaxOutstandingSends = Pipe->MaxOutstandingSends = PipeParameters->MaxOutstandingSends;
  671. // Change the MOS if necessary..
  672. if( ( PipeParameters->MediaType == NdisMediumWan) &&
  673. ( Pipe->Bandwidth <= MAX_LINK_SPEED_FOR_DRR) )
  674. {
  675. Pipe->MaxOutstandingSends = 1;
  676. }
  677. (*PsProcs->GetTimerInfo)(&Pipe->TimerResolution);
  678. Pipe->TimerResolution /= 2;
  679. Pipe->PsPipeContext = PsPipeContext;
  680. Pipe->PsProcs = PsProcs;
  681. if(Upcalls)
  682. {
  683. Pipe->PreviousUpcallsSendComplete = Upcalls->SendComplete;
  684. Pipe->PreviousUpcallsSendCompletePipeContext = Upcalls->PipeContext;
  685. }
  686. else
  687. {
  688. Pipe->PreviousUpcallsSendComplete = 0;
  689. Pipe->PreviousUpcallsSendCompletePipeContext = 0;
  690. }
  691. DrrSeqUpcalls.SendComplete = DrrSeqSendComplete;
  692. DrrSeqUpcalls.PipeContext = ComponentPipeContext;
  693. /* This put the DrrSeq in the pass-thru mode when the MaxOutStandingSends == MAX */
  694. if( Pipe->MaxOutstandingSends == 0xffffffff )
  695. Pipe->Flags |= DSEQ_PASSTHRU;
  696. else
  697. Pipe->Flags &= ~ DSEQ_PASSTHRU;
  698. PsDbgOut(DBG_INFO,
  699. DBG_SCHED_DRR,
  700. ("PSCHED: DrrSeq pipe initialized at %x.\n",
  701. &Pipe));
  702. Status = (*Pipe->ContextInfo.NextComponent->InitializePipe)(
  703. PsPipeContext,
  704. PipeParameters,
  705. Pipe->ContextInfo.NextComponentContext,
  706. PsProcs,
  707. &DrrSeqUpcalls);
  708. if (Status != NDIS_STATUS_SUCCESS)
  709. {
  710. NdisFreeSpinLock(&Pipe->Lock);
  711. DeleteAveragingArray(Pipe->PacketsInSequencerAveragingArray);
  712. DeleteAveragingArray(Pipe->PacketsInNetcardAveragingArray);
  713. }
  714. return Status;
  715. } // DrrSeqInitializePipe
  716. //
  717. // Unload routine: currently do nothing
  718. //
  719. void
  720. UnloadSequencer()
  721. {
  722. }
  723. NDIS_STATUS
  724. DrrSeqModifyPipe (
  725. IN PPS_PIPE_CONTEXT PipeContext,
  726. IN PPS_PIPE_PARAMETERS PipeParameters
  727. )
  728. /*++
  729. Routine Description:
  730. Pipe parameter modification routine for the DRR sequencer.
  731. Arguments:
  732. PipeContext - Pointer to this component's pipe context area
  733. PipeParameters - Pointer to pipe parameters
  734. Return Values:
  735. Status value from next component
  736. --*/
  737. {
  738. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  739. ULONG MinQuantum = PipeParameters->MTUSize - PipeParameters->HeaderSize;
  740. BOOLEAN AdjustQuanta = FALSE;
  741. ULONG MinRate = Pipe->MinimumRate;
  742. LOCK_PIPE(Pipe);
  743. (*Pipe->PsProcs->GetTimerInfo)(&Pipe->TimerResolution);
  744. Pipe->TimerResolution /= 2;
  745. if ((MinQuantum > 0) && (MinQuantum != Pipe->MinimumQuantum)) {
  746. Pipe->MinimumQuantum = MinQuantum;
  747. AdjustQuanta = TRUE;
  748. }
  749. Pipe->Bandwidth = PipeParameters->Bandwidth;
  750. Pipe->ConfiguredMaxOutstandingSends = Pipe->MaxOutstandingSends = PipeParameters->MaxOutstandingSends;
  751. // Change the MOS if necessary..
  752. if( ( PipeParameters->MediaType == NdisMediumWan) &&
  753. ( Pipe->Bandwidth <= MAX_LINK_SPEED_FOR_DRR) )
  754. {
  755. Pipe->MaxOutstandingSends = 1;
  756. }
  757. // This put the DrrSeq in the pass-thru mode when the MaxOutStandingSends == MAX
  758. if( Pipe->MaxOutstandingSends == 0xffffffff )
  759. {
  760. // Make sure not to do this. It could lead to packets queued up in the sequencer being never sent
  761. // [ Pipe->Flags |= DSEQ_PASSTHRU; ]
  762. }
  763. else
  764. {
  765. Pipe->Flags &= ~ DSEQ_PASSTHRU;
  766. }
  767. if (Pipe->MinimumRate > Pipe->Bandwidth) {
  768. MinRate = QOS_NOT_SPECIFIED;
  769. AdjustQuanta = TRUE;
  770. }
  771. if (AdjustQuanta) {
  772. AdjustFlowQuanta(Pipe, MinRate);
  773. }
  774. UNLOCK_PIPE(Pipe);
  775. return (*PipeContext->NextComponent->ModifyPipe)(
  776. PipeContext->NextComponentContext,
  777. PipeParameters);
  778. } // DrrSeqModifyPipe
  779. VOID
  780. DrrSeqDeletePipe (
  781. IN PPS_PIPE_CONTEXT PipeContext
  782. )
  783. /*++
  784. Routine Description:
  785. Pipe removal routine for token bucket conformer.
  786. Arguments:
  787. PipeContext - Pointer to this component's pipe context area
  788. Return Values:
  789. --*/
  790. {
  791. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  792. DeleteAveragingArray(Pipe->PacketsInSequencerAveragingArray);
  793. DeleteAveragingArray(Pipe->PacketsInNetcardAveragingArray);
  794. PsDbgOut(DBG_INFO, DBG_SCHED_DRR, ("PSCHED: DrrSeq pipe deleted\n"));
  795. PsAssert(Pipe->OutstandingSends == 0);
  796. NdisFreeSpinLock(&Pipe->Lock);
  797. (*Pipe->ContextInfo.NextComponent->DeletePipe)(Pipe->ContextInfo.NextComponentContext);
  798. } // DrrSeqDeletePipe
  799. NDIS_STATUS
  800. DrrSeqCreateFlow (
  801. IN PPS_PIPE_CONTEXT PipeContext,
  802. IN HANDLE PsFlowContext,
  803. IN PCO_CALL_PARAMETERS CallParameters,
  804. IN PPS_FLOW_CONTEXT ComponentFlowContext
  805. )
  806. /*++
  807. Routine Description:
  808. Flow creation routine for the DRR sequencer.
  809. Arguments:
  810. PipeContext - Pointer to this component's pipe context area
  811. PsFlowContext - PS flow context value
  812. CallParameters - Pointer to call parameters for flow
  813. ComponentFlowContext - Pointer to this component's flow context area
  814. Return Values:
  815. Status value from next component
  816. --*/
  817. {
  818. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  819. PDSEQ_FLOW Flow = (PDSEQ_FLOW)ComponentFlowContext;
  820. SERVICETYPE ServiceType;
  821. ULONG ParamsLength;
  822. LPQOS_OBJECT_HDR QoSObject;
  823. ULONG UserPriority;
  824. ULONG i;
  825. NDIS_STATUS Status;
  826. ServiceType = CallParameters->CallMgrParameters->Transmit.ServiceType;
  827. if ((ServiceType < SERVICETYPE_BESTEFFORT) || (ServiceType > SERVICETYPE_QUALITATIVE)) {
  828. return NDIS_STATUS_FAILURE;
  829. }
  830. Flow->TokenRate = CallParameters->CallMgrParameters->Transmit.TokenRate;
  831. Flow->BucketSize = CallParameters->CallMgrParameters->Transmit.TokenBucketSize;
  832. InitializeListHead(&Flow->PacketQueue);
  833. PsGetCurrentTime(&Flow->PacketSendTime);
  834. Flow->LastConformanceTime = Flow->PacketSendTime;
  835. Flow->PsFlowContext = PsFlowContext;
  836. Flow->State = DRRSEQ_FLOW_CREATED;
  837. // Set the flow's priority group based on service type.
  838. switch (ServiceType) {
  839. case SERVICETYPE_CONTROLLEDLOAD:
  840. Flow->PriorityGroup = PRIORITY_GROUP_CONTROLLED_LOAD;
  841. break;
  842. case SERVICETYPE_GUARANTEED:
  843. Flow->PriorityGroup = PRIORITY_GROUP_GUARANTEED;
  844. break;
  845. case SERVICETYPE_NETWORK_CONTROL:
  846. Flow->PriorityGroup = PRIORITY_GROUP_NETWORK_CONTROL;
  847. break;
  848. case SERVICETYPE_QUALITATIVE:
  849. default:
  850. Flow->PriorityGroup = PRIORITY_GROUP_BEST_EFFORT;
  851. }
  852. Flow->Flags = 0;
  853. // Save the flow in a list so that quantum values can be adjusted if
  854. // a new flow is added with a smaller rate than the existing flows.
  855. LOCK_PIPE(Pipe);
  856. InsertTailList(&Pipe->Flows, &Flow->Links);
  857. // If this flow's rate is smaller than the rate assigned to any existing
  858. // flow, adjust the other flow's quantum values accordingly.
  859. if (ServiceType == SERVICETYPE_BESTEFFORT || ServiceType == SERVICETYPE_NETWORK_CONTROL ||
  860. ServiceType == SERVICETYPE_QUALITATIVE) {
  861. Flow->Quantum = Pipe->MinimumQuantum;
  862. }
  863. else if (Flow->TokenRate < Pipe->MinimumRate) {
  864. AdjustFlowQuanta(Pipe, Flow->TokenRate);
  865. }
  866. else {
  867. Flow->Quantum = (ULONG)((ULONGLONG)(Flow->TokenRate * Pipe->MinimumQuantum) / Pipe->MinimumRate);
  868. PsAssert((LONG)Flow->Quantum > 0);
  869. }
  870. Flow->DeficitCounter = 0;
  871. // If this is a RAS-ISSLOW flow, need to set the MOS back to whatever requested by the user..
  872. if( ((PGPC_CLIENT_VC)(PsFlowContext))->Flags & GPC_ISSLOW_FLOW)
  873. {
  874. Pipe->MaxOutstandingSends = Pipe->ConfiguredMaxOutstandingSends;
  875. Pipe->IsslowFlowCount++;
  876. Flow->Flags |= GPC_ISSLOW_FLOW;
  877. }
  878. UNLOCK_PIPE(Pipe);
  879. // Now set default values for UserPriority
  880. UserPriority = (Pipe->PriorityLevels[Flow->PriorityGroup] - 1) / 2;
  881. // Look for the priority object and traffic class in the call manager specific parameters
  882. ParamsLength = CallParameters->CallMgrParameters->CallMgrSpecific.Length;
  883. if (CallParameters->CallMgrParameters->CallMgrSpecific.ParamType == PARAM_TYPE_GQOS_INFO) {
  884. QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
  885. while ((ParamsLength > 0) && (QoSObject->ObjectType != QOS_OBJECT_END_OF_LIST)) {
  886. if (QoSObject->ObjectType == QOS_OBJECT_PRIORITY) {
  887. UserPriority = ((LPQOS_PRIORITY)QoSObject)->SendPriority;
  888. Flow->Flags |= FLOW_USER_PRIORITY;
  889. }
  890. ParamsLength -= QoSObject->ObjectLength;
  891. QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject + QoSObject->ObjectLength);
  892. }
  893. }
  894. Flow->UserPriority = UserPriority;
  895. if (UserPriority < Pipe->PriorityLevels[Flow->PriorityGroup]) {
  896. Flow->Priority = Pipe->StartPriority[Flow->PriorityGroup] + UserPriority;
  897. }
  898. else {
  899. Flow->Priority = Pipe->StartPriority[Flow->PriorityGroup] +
  900. Pipe->PriorityLevels[Flow->PriorityGroup] - 1;
  901. }
  902. Flow->PacketsInSequencer = 0;
  903. NdisZeroMemory(&Flow->Stats, sizeof(PS_DRRSEQ_STATS));
  904. Status = CreateAveragingArray(&Flow->PacketsInSeqAveragingArray,
  905. SEQUENCER_FLOW_AVERAGING_ARRAY_SIZE);
  906. if(Status != NDIS_STATUS_SUCCESS){
  907. LOCK_PIPE(Pipe);
  908. RemoveEntryList(&Flow->Links);
  909. if(Flow->TokenRate == Pipe->MinimumRate) {
  910. AdjustFlowQuanta(Pipe, QOS_NOT_SPECIFIED);
  911. }
  912. UNLOCK_PIPE(Pipe);
  913. return(Status);
  914. }
  915. PsDbgOut(DBG_INFO, DBG_SCHED_DRR,
  916. ("PSCHED: DrrSeq flow created. Quantum = %u, Priority = %u\n", Flow->Quantum, Flow->Priority));
  917. Status = (*Pipe->ContextInfo.NextComponent->CreateFlow)(
  918. Pipe->ContextInfo.NextComponentContext,
  919. PsFlowContext,
  920. CallParameters,
  921. Flow->ContextInfo.NextComponentContext);
  922. if(Status != NDIS_STATUS_SUCCESS)
  923. {
  924. DeleteAveragingArray(Flow->PacketsInSeqAveragingArray);
  925. LOCK_PIPE(Pipe);
  926. RemoveEntryList(&Flow->Links);
  927. if(Flow->TokenRate == Pipe->MinimumRate) {
  928. AdjustFlowQuanta(Pipe, QOS_NOT_SPECIFIED);
  929. }
  930. UNLOCK_PIPE(Pipe);
  931. }
  932. return Status;
  933. } // DrrSeqCreateFlow
  934. NDIS_STATUS
  935. DrrSeqModifyFlow (
  936. IN PPS_PIPE_CONTEXT PipeContext,
  937. IN PPS_FLOW_CONTEXT FlowContext,
  938. IN PCO_CALL_PARAMETERS CallParameters
  939. )
  940. /*++
  941. Routine Description:
  942. Flow modification routine for the DRR sequencer.
  943. Arguments:
  944. PipeContext - Pointer to this component's pipe context area
  945. FlowContext - Pointer to this component's flow context area
  946. CallParameters - Pointer to call parameters for flow
  947. Return Values:
  948. Status value from next component
  949. --*/
  950. {
  951. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  952. PDSEQ_FLOW Flow = (PDSEQ_FLOW)FlowContext;
  953. SERVICETYPE ServiceType;
  954. ULONG TokenRate;
  955. ULONG ParamsLength;
  956. LPQOS_OBJECT_HDR QoSObject;
  957. LPQOS_PRIORITY PriorityObject = NULL;
  958. ULONG i;
  959. ULONG OldPriorityGroup;
  960. ULONG OldRate;
  961. ULONG OldPriority;
  962. PPACKET_INFO_BLOCK PacketInfo;
  963. LARGE_INTEGER CurrentTime;
  964. ServiceType = CallParameters->CallMgrParameters->Transmit.ServiceType;
  965. if ((ServiceType != SERVICETYPE_NOCHANGE) &&
  966. ((ServiceType < SERVICETYPE_BESTEFFORT) || (ServiceType > SERVICETYPE_QUALITATIVE))) {
  967. return NDIS_STATUS_FAILURE;
  968. }
  969. // Look for the priority and traffic class objects in the call manager
  970. // specific parameters, and save the pointers if found.
  971. ParamsLength = CallParameters->CallMgrParameters->CallMgrSpecific.Length;
  972. if (CallParameters->CallMgrParameters->CallMgrSpecific.ParamType == PARAM_TYPE_GQOS_INFO) {
  973. QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
  974. while ((ParamsLength > 0) && (QoSObject->ObjectType != QOS_OBJECT_END_OF_LIST)) {
  975. if (QoSObject->ObjectType == QOS_OBJECT_PRIORITY) {
  976. PriorityObject = (LPQOS_PRIORITY)QoSObject;
  977. }
  978. ParamsLength -= QoSObject->ObjectLength;
  979. QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject + QoSObject->ObjectLength);
  980. }
  981. }
  982. LOCK_PIPE(Pipe);
  983. OldPriorityGroup = Flow->PriorityGroup;
  984. OldPriority = Flow->Priority;
  985. if (ServiceType != SERVICETYPE_NOCHANGE)
  986. {
  987. // Set the flow's priority group based on service type.
  988. switch (ServiceType) {
  989. case SERVICETYPE_CONTROLLEDLOAD:
  990. Flow->PriorityGroup = PRIORITY_GROUP_CONTROLLED_LOAD;
  991. break;
  992. case SERVICETYPE_GUARANTEED:
  993. Flow->PriorityGroup = PRIORITY_GROUP_GUARANTEED;
  994. break;
  995. case SERVICETYPE_NETWORK_CONTROL:
  996. Flow->PriorityGroup = PRIORITY_GROUP_NETWORK_CONTROL;
  997. break;
  998. case SERVICETYPE_QUALITATIVE:
  999. default:
  1000. Flow->PriorityGroup = PRIORITY_GROUP_BEST_EFFORT;
  1001. }
  1002. TokenRate = CallParameters->CallMgrParameters->Transmit.TokenRate;
  1003. OldRate = Flow->TokenRate;
  1004. if ((TokenRate != OldRate) || (OldPriorityGroup != Flow->PriorityGroup)) {
  1005. // If this flow's rate is smaller than the rate assigned to any existing
  1006. // flow, adjust the other flows' quantum values accordingly. If this flow's
  1007. // old rate was equal to the minimum rate, then locate the new minimum rate and
  1008. // adjust the other flows' quantum values accordingly.
  1009. Flow->TokenRate = TokenRate;
  1010. if ((OldRate == Pipe->MinimumRate) && (OldPriorityGroup > PRIORITY_GROUP_BEST_EFFORT) &&
  1011. (OldPriorityGroup != PRIORITY_GROUP_NETWORK_CONTROL)) {
  1012. AdjustFlowQuanta(Pipe, QOS_NOT_SPECIFIED);
  1013. }
  1014. else if (Flow->PriorityGroup <= PRIORITY_GROUP_BEST_EFFORT || Flow->PriorityGroup == PRIORITY_GROUP_NETWORK_CONTROL) {
  1015. Flow->Quantum = Pipe->MinimumQuantum;
  1016. }
  1017. else if (TokenRate < Pipe->MinimumRate) {
  1018. AdjustFlowQuanta(Pipe, TokenRate);
  1019. }
  1020. else {
  1021. PsAssert(Pipe->MinimumRate != 0);
  1022. Flow->Quantum = (ULONG)((ULONGLONG)(TokenRate * Pipe->MinimumQuantum) / Pipe->MinimumRate);
  1023. PsAssert((LONG)Flow->Quantum > 0);
  1024. }
  1025. }
  1026. Flow->BucketSize = CallParameters->CallMgrParameters->Transmit.TokenBucketSize;
  1027. }
  1028. // Now set the new values for UserPriority and Priority
  1029. if (PriorityObject != NULL) {
  1030. Flow->UserPriority = PriorityObject->SendPriority;
  1031. Flow->Flags |= FLOW_USER_PRIORITY;
  1032. }
  1033. else if ((Flow->Flags & FLOW_USER_PRIORITY) == 0) {
  1034. Flow->UserPriority = (Pipe->PriorityLevels[Flow->PriorityGroup] - 1) / 2;
  1035. }
  1036. if (Flow->UserPriority < Pipe->PriorityLevels[Flow->PriorityGroup]) {
  1037. Flow->Priority = Pipe->StartPriority[Flow->PriorityGroup] + Flow->UserPriority;
  1038. }
  1039. else {
  1040. Flow->Priority = Pipe->StartPriority[Flow->PriorityGroup] +
  1041. Pipe->PriorityLevels[Flow->PriorityGroup] - 1;
  1042. }
  1043. // Move the flow to the proper priority list if necessary
  1044. if ((Flow->Priority != OldPriority) && !IsListEmpty(&Flow->PacketQueue)) {
  1045. Pipe->ActiveFlowCount[OldPriorityGroup]--;
  1046. RemoveEntryList(&Flow->ActiveLinks);
  1047. PacketInfo = (PPACKET_INFO_BLOCK)Flow->PacketQueue.Flink;
  1048. PsGetCurrentTime(&CurrentTime);
  1049. Flow->DeficitCounter = Flow->Quantum;
  1050. Pipe->ActiveFlowCount[Flow->PriorityGroup]++;
  1051. if (!PacketIsConforming(Flow, PacketInfo, CurrentTime, Pipe->TimerResolution)) {
  1052. InsertTailList(&Pipe->ActiveFlows[0], &Flow->ActiveLinks);
  1053. } else {
  1054. InsertTailList(&Pipe->ActiveFlows[Flow->Priority], &Flow->ActiveLinks);
  1055. }
  1056. }
  1057. UNLOCK_PIPE(Pipe);
  1058. PsDbgOut(DBG_INFO, DBG_SCHED_DRR,
  1059. ("PSCHED: DrrSeq flow modified. Quantum = %u, Priority = %u\n", Flow->Quantum, Flow->Priority));
  1060. return (*Pipe->ContextInfo.NextComponent->ModifyFlow)(
  1061. Pipe->ContextInfo.NextComponentContext,
  1062. Flow->ContextInfo.NextComponentContext,
  1063. CallParameters);
  1064. } // DrrSeqModifyFlow
  1065. VOID
  1066. DrrSeqDeleteFlow (
  1067. IN PPS_PIPE_CONTEXT PipeContext,
  1068. IN PPS_FLOW_CONTEXT FlowContext
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. Flow removal routine for the DRR sequencer.
  1073. Arguments:
  1074. PipeContext - Pointer to this component's pipe context area
  1075. FlowContext - Pointer to this component's flow context area
  1076. Return Values:
  1077. --*/
  1078. {
  1079. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1080. PDSEQ_FLOW Flow = (PDSEQ_FLOW)FlowContext;
  1081. PPACKET_INFO_BLOCK PacketInfo;
  1082. PNDIS_PACKET Packet;
  1083. LIST_ENTRY DropList;
  1084. InitializeListHead(&DropList);
  1085. LOCK_PIPE(Pipe);
  1086. if( (Flow->State & DRRSEQ_FLOW_DELETED) != 0)
  1087. {
  1088. UNLOCK_PIPE(Pipe);
  1089. goto DELETE_SEQ_FLOW;
  1090. }
  1091. Flow->State = DRRSEQ_FLOW_DELETED;
  1092. RemoveEntryList(&Flow->Links);
  1093. if (!IsListEmpty(&Flow->PacketQueue))
  1094. {
  1095. // Remove flow from active list
  1096. RemoveEntryList(&Flow->ActiveLinks);
  1097. Pipe->ActiveFlowCount[Flow->PriorityGroup]--;
  1098. Pipe->TotalActiveFlows--;
  1099. while (!IsListEmpty(&Flow->PacketQueue)) {
  1100. // Drop any packets that remain queued for this flow.
  1101. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&Flow->PacketQueue);
  1102. InsertTailList(&DropList, &PacketInfo->SchedulerLinks);
  1103. }
  1104. }
  1105. if (Flow->TokenRate == Pipe->MinimumRate) {
  1106. AdjustFlowQuanta(Pipe, QOS_NOT_SPECIFIED);
  1107. }
  1108. if( Flow->Flags & GPC_ISSLOW_FLOW)
  1109. {
  1110. // If this is an ISSLOW flow, we have one less now.
  1111. Pipe->IsslowFlowCount--;
  1112. if(Pipe->IsslowFlowCount == 0)
  1113. {
  1114. // If there are no more ISSLOW flows, turn DRR back on.
  1115. Pipe->MaxOutstandingSends = 1;
  1116. }
  1117. }
  1118. UNLOCK_PIPE(Pipe);
  1119. while (!IsListEmpty(&DropList)) {
  1120. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&DropList);
  1121. Packet = PacketInfo->NdisPacket;
  1122. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  1123. }
  1124. DELETE_SEQ_FLOW:
  1125. DeleteAveragingArray(Flow->PacketsInSeqAveragingArray);
  1126. PsDbgOut(DBG_INFO, DBG_SCHED_DRR, ("PSCHED: DrrSeq flow deleted\n"));
  1127. (*Pipe->ContextInfo.NextComponent->DeleteFlow)(
  1128. Pipe->ContextInfo.NextComponentContext,
  1129. Flow->ContextInfo.NextComponentContext);
  1130. }
  1131. VOID
  1132. DrrSeqEmptyFlow (
  1133. IN PPS_PIPE_CONTEXT PipeContext,
  1134. IN PPS_FLOW_CONTEXT FlowContext
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. Flow removal routine for the DRR sequencer.
  1139. Arguments:
  1140. PipeContext - Pointer to this component's pipe context area
  1141. FlowContext - Pointer to this component's flow context area
  1142. Return Values:
  1143. --*/
  1144. {
  1145. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1146. PDSEQ_FLOW Flow = (PDSEQ_FLOW)FlowContext;
  1147. PPACKET_INFO_BLOCK PacketInfo;
  1148. PNDIS_PACKET Packet;
  1149. LIST_ENTRY DropList;
  1150. InitializeListHead(&DropList);
  1151. LOCK_PIPE(Pipe);
  1152. Flow->State = DRRSEQ_FLOW_DELETED;
  1153. RemoveEntryList(&Flow->Links);
  1154. if (!IsListEmpty(&Flow->PacketQueue))
  1155. {
  1156. // Remove flow from active list
  1157. RemoveEntryList(&Flow->ActiveLinks);
  1158. Pipe->ActiveFlowCount[Flow->PriorityGroup]--;
  1159. Pipe->TotalActiveFlows--;
  1160. while (!IsListEmpty(&Flow->PacketQueue)) {
  1161. // Drop any packets that remain queued for this flow.
  1162. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&Flow->PacketQueue);
  1163. InsertTailList(&DropList, &PacketInfo->SchedulerLinks);
  1164. }
  1165. }
  1166. if (Flow->TokenRate == Pipe->MinimumRate) {
  1167. AdjustFlowQuanta(Pipe, QOS_NOT_SPECIFIED);
  1168. }
  1169. if( Flow->Flags & GPC_ISSLOW_FLOW)
  1170. {
  1171. // If this is an ISSLOW flow, we have one less now.
  1172. Pipe->IsslowFlowCount--;
  1173. if(Pipe->IsslowFlowCount == 0)
  1174. {
  1175. // If there are no more ISSLOW flows, turn DRR back on.
  1176. Pipe->MaxOutstandingSends = 1;
  1177. }
  1178. }
  1179. UNLOCK_PIPE(Pipe);
  1180. while (!IsListEmpty(&DropList)) {
  1181. PacketInfo = (PPACKET_INFO_BLOCK)RemoveHeadList(&DropList);
  1182. Packet = PacketInfo->NdisPacket;
  1183. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  1184. }
  1185. PsDbgOut(DBG_INFO, DBG_SCHED_DRR, ("PSCHED: DrrSeq flow emptied\n"));
  1186. (*Pipe->ContextInfo.NextComponent->EmptyFlow)(
  1187. Pipe->ContextInfo.NextComponentContext,
  1188. Flow->ContextInfo.NextComponentContext);
  1189. }
  1190. static NDIS_STATUS
  1191. DrrSeqCreateClassMap (
  1192. IN PPS_PIPE_CONTEXT PipeContext,
  1193. IN HANDLE PsClassMapContext,
  1194. IN PTC_CLASS_MAP_FLOW ClassMap,
  1195. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext)
  1196. {
  1197. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1198. return (*Pipe->ContextInfo.NextComponent->CreateClassMap)(
  1199. Pipe->ContextInfo.NextComponentContext,
  1200. PsClassMapContext,
  1201. ClassMap,
  1202. ComponentClassMapContext->NextComponentContext);
  1203. }
  1204. static NDIS_STATUS
  1205. DrrSeqDeleteClassMap (
  1206. IN PPS_PIPE_CONTEXT PipeContext,
  1207. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext)
  1208. {
  1209. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1210. return (*Pipe->ContextInfo.NextComponent->DeleteClassMap)(
  1211. Pipe->ContextInfo.NextComponentContext,
  1212. ComponentClassMapContext->NextComponentContext);
  1213. }
  1214. BOOLEAN
  1215. DrrSeqSubmitPacket (
  1216. IN PPS_PIPE_CONTEXT PipeContext,
  1217. IN PPS_FLOW_CONTEXT FlowContext,
  1218. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  1219. IN PPACKET_INFO_BLOCK PacketInfo
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Packet submission routine for the DRR sequencer.
  1224. Arguments:
  1225. PipeContext - Pointer to this component's pipe context area
  1226. FlowContext - Pointer to this component's flow context area
  1227. Packet - Pointer to packet
  1228. Return Values:
  1229. Always returns TRUE
  1230. --*/
  1231. {
  1232. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1233. PDSEQ_FLOW Flow = (PDSEQ_FLOW)FlowContext;
  1234. LARGE_INTEGER CurrentTime;
  1235. PNDIS_PACKET Packet = PacketInfo->NdisPacket;
  1236. BOOLEAN FlowInactive;
  1237. PGPC_CLIENT_VC Vc = Flow->PsFlowContext;
  1238. if(Pipe->Flags & DSEQ_PASSTHRU)
  1239. {
  1240. InterlockedIncrement( &Pipe->OutstandingSends );
  1241. if(Pipe->OutstandingSends > Pipe->Stats.MaxPacketsInNetcard){
  1242. Pipe->Stats.MaxPacketsInNetcard = Pipe->OutstandingSends;
  1243. }
  1244. if(gEnableAvgStats)
  1245. {
  1246. //
  1247. // Track max packets outstanding. This is a measure
  1248. // of how congested the media gets. Of course, it
  1249. // will be clipped by the MaxOutstandingSends parameter.
  1250. // So - for a valid reading, need to set MOS very large.
  1251. //
  1252. Pipe->Stats.AveragePacketsInNetcard =
  1253. RunningAverage(Pipe->PacketsInNetcardAveragingArray,
  1254. Pipe->OutstandingSends);
  1255. }
  1256. //
  1257. // Note: The 802.1p is already set by the wrapper
  1258. //
  1259. if (!(*Pipe->ContextInfo.NextComponent->SubmitPacket)(
  1260. Pipe->ContextInfo.NextComponentContext,
  1261. Flow->ContextInfo.NextComponentContext,
  1262. (ClassMapContext != NULL) ? ClassMapContext->NextComponentContext : NULL,
  1263. PacketInfo)) {
  1264. (*Pipe->PsProcs->DropPacket)(Pipe->PsPipeContext, Flow->PsFlowContext, Packet, NDIS_STATUS_FAILURE);
  1265. }
  1266. return TRUE;
  1267. }
  1268. LOCK_PIPE(Pipe);
  1269. if (Flow->State == DRRSEQ_FLOW_DELETED)
  1270. {
  1271. UNLOCK_PIPE(Pipe);
  1272. return FALSE;
  1273. }
  1274. //
  1275. // On WanLinks, when we are doing DRR, we need to put a maximum on the queue-limit.
  1276. // NDISWAN has a queue limit of 132KBytes on a modem link; So, we'll limit it to 120
  1277. // packets by default.
  1278. //
  1279. if( ( Pipe->Bandwidth <= MAX_LINK_SPEED_FOR_DRR) &&
  1280. ( Pipe->MaxOutstandingSends == 1) &&
  1281. ( Pipe->PacketsInSequencer >= 120) )
  1282. {
  1283. UNLOCK_PIPE( Pipe);
  1284. return FALSE;
  1285. }
  1286. //
  1287. // There is one case where the PIPE might go away because the send-complete happened
  1288. // on a VC belonging to it before the send returned. So, to prevent that, we add a
  1289. // Ref on that VC and take it out just before the send returns.
  1290. //
  1291. // Add a Ref.
  1292. InterlockedIncrement(&Vc->RefCount);
  1293. PacketInfo->FlowContext = FlowContext;
  1294. PacketInfo->ClassMapContext = ClassMapContext;
  1295. Pipe->PacketsInSequencer++;
  1296. if(Pipe->PacketsInSequencer > Pipe->Stats.MaxPacketsInSequencer){
  1297. Pipe->Stats.MaxPacketsInSequencer = Pipe->PacketsInSequencer;
  1298. }
  1299. Flow->PacketsInSequencer++;
  1300. if (Flow->PacketsInSequencer > Flow->Stats.MaxPacketsInSequencer){
  1301. Flow->Stats.MaxPacketsInSequencer = Flow->PacketsInSequencer;
  1302. }
  1303. if(gEnableAvgStats)
  1304. {
  1305. //
  1306. // Track packets in the sequencer at any time.
  1307. //
  1308. Pipe->Stats.AveragePacketsInSequencer =
  1309. RunningAverage(Pipe->PacketsInSequencerAveragingArray,
  1310. Pipe->PacketsInSequencer);
  1311. Flow->Stats.AveragePacketsInSequencer =
  1312. RunningAverage(Flow->PacketsInSeqAveragingArray, Flow->PacketsInSequencer);
  1313. }
  1314. FlowInactive = IsListEmpty(&Flow->PacketQueue);
  1315. InsertTailList(&Flow->PacketQueue, &PacketInfo->SchedulerLinks);
  1316. PsGetCurrentTime(&CurrentTime);
  1317. PsDbgSched(DBG_INFO,
  1318. DBG_SCHED_DRR,
  1319. DRR_SEQUENCER, PKT_ENQUEUE, Flow->PsFlowContext,
  1320. Packet, PacketInfo->PacketLength, Flow->Priority,
  1321. CurrentTime.QuadPart,
  1322. PacketInfo->ConformanceTime.QuadPart,
  1323. Pipe->PacketsInSequencer,
  1324. 0);
  1325. if (FlowInactive) {
  1326. Flow->PacketSendTime.QuadPart +=
  1327. (PacketInfo->ConformanceTime.QuadPart - Flow->LastConformanceTime.QuadPart);
  1328. Flow->DeficitCounter = Flow->Quantum;
  1329. Pipe->TotalActiveFlows++;
  1330. Pipe->ActiveFlowCount[Flow->PriorityGroup]++;
  1331. if (!PacketIsConforming(Flow, PacketInfo, CurrentTime, Pipe->TimerResolution)) {
  1332. InsertTailList(&Pipe->ActiveFlows[0], &Flow->ActiveLinks);
  1333. } else {
  1334. InsertTailList(&Pipe->ActiveFlows[Flow->Priority], &Flow->ActiveLinks);
  1335. }
  1336. }
  1337. while ((Pipe->TotalActiveFlows > 0) &&
  1338. (Pipe->OutstandingSends < Pipe->MaxOutstandingSends) &&
  1339. ((Pipe->Flags & DSEQ_DEQUEUE) == 0)) {
  1340. DequeuePackets(Pipe);
  1341. }
  1342. UNLOCK_PIPE(Pipe);
  1343. // Take out the ref.
  1344. DerefClVc(Vc);
  1345. return TRUE;
  1346. } // DrrSeqSubmitPacket
  1347. VOID
  1348. DrrSeqSendComplete (
  1349. IN PPS_PIPE_CONTEXT PipeContext,
  1350. IN PNDIS_PACKET Packet
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Send complete handler for the DRR sequencer.
  1355. Arguments:
  1356. PipeContext - Pointer to this component's pipe context area
  1357. FlowContext - Pointer to this component's flow context area
  1358. Packet - Packet that has completed sending
  1359. Return Values:
  1360. --*/
  1361. {
  1362. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)PipeContext;
  1363. InterlockedDecrement( &Pipe->OutstandingSends);
  1364. // Need to do this only if the sequencer is not in the bypass mode //
  1365. if( (Pipe->Flags & DSEQ_PASSTHRU) == 0)
  1366. {
  1367. LOCK_PIPE(Pipe);
  1368. PsAssert((LONG)Pipe->OutstandingSends >= 0);
  1369. while ((Pipe->TotalActiveFlows > 0) &&
  1370. (Pipe->OutstandingSends < Pipe->MaxOutstandingSends) &&
  1371. ((Pipe->Flags & DSEQ_DEQUEUE) == 0)) {
  1372. DequeuePackets(Pipe);
  1373. }
  1374. UNLOCK_PIPE(Pipe);
  1375. }
  1376. //
  1377. // Call the previous upcalls (if any)
  1378. //
  1379. if(Pipe->PreviousUpcallsSendComplete)
  1380. {
  1381. (*Pipe->PreviousUpcallsSendComplete)(Pipe->PreviousUpcallsSendCompletePipeContext, Packet);
  1382. }
  1383. } // DrrSeqSendComplete
  1384. VOID
  1385. DrrSetInformation (
  1386. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  1387. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  1388. IN NDIS_OID Oid,
  1389. IN ULONG Len,
  1390. IN PVOID Data)
  1391. {
  1392. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)ComponentPipeContext;
  1393. PDSEQ_FLOW Flow = (PDSEQ_FLOW)ComponentFlowContext;
  1394. switch(Oid)
  1395. {
  1396. case OID_QOS_STATISTICS_BUFFER:
  1397. if(Flow) {
  1398. NdisZeroMemory(&Flow->Stats, sizeof(PS_DRRSEQ_STATS));
  1399. }
  1400. else {
  1401. NdisZeroMemory(&Pipe->Stats, sizeof(PS_DRRSEQ_STATS));
  1402. }
  1403. break;
  1404. default:
  1405. break;
  1406. }
  1407. (*Pipe->ContextInfo.NextComponent->SetInformation)(
  1408. Pipe->ContextInfo.NextComponentContext,
  1409. (Flow)?Flow->ContextInfo.NextComponentContext:0,
  1410. Oid,
  1411. Len,
  1412. Data);
  1413. }
  1414. VOID
  1415. DrrQueryInformation (
  1416. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  1417. IN PPS_FLOW_CONTEXT ComponentFlowContext,
  1418. IN NDIS_OID Oid,
  1419. IN ULONG Len,
  1420. IN PVOID Data,
  1421. IN OUT PULONG BytesWritten,
  1422. IN OUT PULONG BytesNeeded,
  1423. IN OUT PNDIS_STATUS Status)
  1424. {
  1425. PDSEQ_PIPE Pipe = (PDSEQ_PIPE)ComponentPipeContext;
  1426. PDSEQ_FLOW Flow = (PDSEQ_FLOW)ComponentFlowContext;
  1427. PS_COMPONENT_STATS Stats;
  1428. ULONG Size;
  1429. ULONG RemainingLength;
  1430. switch(Oid)
  1431. {
  1432. case OID_QOS_STATISTICS_BUFFER:
  1433. Size = sizeof(PS_DRRSEQ_STATS) + FIELD_OFFSET(PS_COMPONENT_STATS, Stats);
  1434. if(*Status == NDIS_STATUS_SUCCESS)
  1435. {
  1436. //
  1437. // The previous component has succeeded - Let us
  1438. // see if we can write the data
  1439. //
  1440. RemainingLength = Len - *BytesWritten;
  1441. if(RemainingLength < Size) {
  1442. *Status = NDIS_STATUS_BUFFER_TOO_SHORT;
  1443. *BytesNeeded = Size + *BytesWritten;
  1444. *BytesWritten = 0;
  1445. }
  1446. else {
  1447. PPS_COMPONENT_STATS Cstats = (PPS_COMPONENT_STATS) Data;
  1448. *BytesWritten += Size;
  1449. *BytesNeeded = 0;
  1450. if(Flow) {
  1451. Cstats->Type = PS_COMPONENT_DRRSEQ;
  1452. Cstats->Length = sizeof(PS_DRRSEQ_STATS);
  1453. NdisMoveMemory(&Cstats->Stats, &Flow->Stats, sizeof(PS_DRRSEQ_STATS));
  1454. }
  1455. else {
  1456. Cstats->Type = PS_COMPONENT_DRRSEQ;
  1457. Cstats->Length = sizeof(PS_DRRSEQ_STATS);
  1458. NdisMoveMemory(&Cstats->Stats, &Pipe->Stats, sizeof(PS_DRRSEQ_STATS));
  1459. }
  1460. //
  1461. // Advance Data so that the next component can update its stats
  1462. //
  1463. Data = (PVOID) ((PUCHAR)Data + Size);
  1464. }
  1465. }
  1466. else {
  1467. *BytesNeeded += Size;
  1468. *BytesWritten = 0;
  1469. }
  1470. break;
  1471. default:
  1472. break;
  1473. }
  1474. (*Pipe->ContextInfo.NextComponent->QueryInformation)(
  1475. Pipe->ContextInfo.NextComponentContext,
  1476. (Flow)?Flow->ContextInfo.NextComponentContext : 0,
  1477. Oid,
  1478. Len,
  1479. Data,
  1480. BytesWritten,
  1481. BytesNeeded,
  1482. Status);
  1483. }