📄 wcett.c
字号:
//
// We have received no valid packet-pair samples.
// Reduce the bandwidth estimate.
//
Bandwidth = WcettDecodeBandwidth(Link->wcett.Bandwidth);
Bandwidth = WcettDefaultBandwidth(Bandwidth);
}
else {
uint Delay;
//
// Calculate the bandwidth using the minimum delay sample
// from the last sample period.
//
Delay = Link->MetricInfo.Wcett.PktPair.CurrMin;
Bandwidth = WcettConvertPktPairDelayToBandwidth(Delay);
}
Link->wcett.Bandwidth = WcettEncodeBandwidth(Bandwidth);
}
//* WcettSendPktPairProbes
//
// Sends probes to adjacent nodes as needed.
//
Time
WcettSendPktPairProbes(
MiniportAdapter *VA,
Time Now)
{
NeighborCache *NC = &VA->NC;
NeighborCacheEntry *NCE;
NDIS_PACKET *ProbePackets = NULL;
NDIS_PACKET *FirstPkt, *SecondPkt, *Packet;
Link *Adj;
Time Timeout;
KIRQL OldIrql;
NDIS_STATUS Status;
uint Diff;
Timeout = MAXTIME;
KeAcquireSpinLock(&NC->Lock, &OldIrql);
//
// Loop through outgoing links, creating a probe pair for each,
// when warranted by timeout value. Store the probe packets temporarily
// on a list since we can't send them while holding the lock on the
// Neighbor Cache.
//
for (NCE = NC->FirstNCE; NCE != SentinelNCE(NC); NCE = NCE->Next) {
//
// For link quality metric, if layer 2 driver supports it,
// we prefer OID_MSRC_QUERY_SIB_TABLE to packet pair.
//
if (NCE->Flags & VRR_NCE_FLAG_SIB_OID)
continue;
Adj = &NCE->AdjOut;
if (Adj->MetricInfo.Wcett.PktPair.ProbeTimeout <= Now) {
//
// Is it time to calculate a new link bandwidth?
//
if ((Adj->MetricInfo.Wcett.PktPair.PairsSent % VA->MetricParams.Wcett.PktPairMinOverProbes) == 0) {
//
// Update the bandwidth using CurrMin.
//
WcettUpdateBandwidth(Adj);
//
// Reset CurrMin to a large number.
//
Adj->MetricInfo.Wcett.PktPair.CurrMin = (uint)-1;
}
//
// Create two packets, one with Seq and another with Seq + 1.
//
Status = PktPairCreateProbePacket(VA, Adj, 0, &FirstPkt,
Adj->MetricInfo.Wcett.PktPair.ProbeSeq, FALSE, METRIC_TYPE_PKTPAIR);
if (Status == NDIS_STATUS_SUCCESS) {
Status = PktPairCreateProbePacket(VA, Adj, 0, &SecondPkt,
Adj->MetricInfo.Wcett.PktPair.ProbeSeq + 1, TRUE, METRIC_TYPE_PKTPAIR);
if (Status == NDIS_STATUS_SUCCESS) {
//
// We created both packets successfuly. Bump the
// sequence number by two.
//
Adj->MetricInfo.Wcett.PktPair.ProbeSeq += 2;
Adj->MetricInfo.Wcett.PktPair.PairsSent++;
Adj->MetricInfo.Wcett.PktPair.Outstanding = Adj->MetricInfo.Wcett.PktPair.ProbeSeq - 1;
//
// Queue the packets using the OrigPacket link.
// The queue is "backward", so insert second packet
// first.
//
PC(SecondPkt)->OrigPacket = ProbePackets;
PC(FirstPkt)->OrigPacket = SecondPkt;
ProbePackets = FirstPkt;
}
else {
//
// We failed to create the second probe.
//
KdPrint(("VRR!WcettSendPktPairProbes SECOND PktPairCreateProbePacket returned %x\n", Status));
PktPairSendProbeComplete(VA, FirstPkt, Status);
}
}
else {
//
// We failed to create the first probe.
//
KdPrint(("VRR!WcettSendPktPairProbes FIRST PktPairCreateProbePacket returned %x\n", Status));
}
//
// Calculate next probe timeout. Randomize by adding 25% delay.
//
Diff = VA->MetricParams.Wcett.PktPairProbePeriod + GetRandomNumber(VA->MetricParams.Wcett.PktPairProbePeriod >> 2);
Adj->MetricInfo.Wcett.PktPair.ProbeTimeout = Now + Diff;
}
//
// We need to keep track of only the earliest timeout.
//
if (Adj->MetricInfo.Wcett.PktPair.ProbeTimeout < Timeout)
Timeout = Adj->MetricInfo.Wcett.PktPair.ProbeTimeout;
}
KeReleaseSpinLock(&NC->Lock, OldIrql);
//
// Loop through queued packets, sending out each probe.
//
while ((Packet = ProbePackets) != NULL) {
ProbePackets = PC(Packet)->OrigPacket;
PC(Packet)->OrigPacket = NULL;
if (PC(Packet)->PA == NULL) {
//
// This means the packet is trying to use a physical adapter
// that no longer exists.
//
VRRASSERT(PC(Packet)->TransmitComplete == PktPairSendProbeComplete);
PktPairSendProbeComplete(VA, Packet, NDIS_STATUS_FAILURE);
} else {
//
// Transmit the packet.
//
ProtocolTransmit(PC(Packet)->PA, Packet);
}
}
return Timeout;
}
//* WcettReceivePktPairProbe
//
// Receive a Probe, and Reply if necessary.
//
void
WcettReceivePktPairProbe(
MiniportAdapter *VA,
InternalProbe *Probe)
{
NeighborCache *NC = &VA->NC;
NeighborCacheEntry *NCE;
Link *Adj;
Time Now, OutDelta;
LARGE_INTEGER Timestamp;
LARGE_INTEGER Frequency;
KIRQL OldIrql;
boolint SendProbeReply = FALSE;
//
// Do not send a response to ourselves.
//
if (VirtualAddressEqual(Probe->Opt.From, VA->Address))
return;
Timestamp = KeQueryPerformanceCounter(&Frequency);
Now = Timestamp.QuadPart;
OutDelta = 0;
//
// When we receive a probe:
// - Find the NCE for the sender.
// - If the seq number is even, store current time
// and seq number.
// - If the seq number is odd, and if it is the next expected
// probe, send a reply.
//
KeAcquireSpinLock(&NC->Lock, &OldIrql);
//
// Find NCE of the sender. Bail if Hello protocol has yet to see sender.
//
NCE = FindNCE(NC,
Probe->Opt.From,
Probe->Opt.InIf, // InIf = recv's rx = LocIF.
Probe->Opt.OutIf, // OutIf = sender's tx = RemIF.
VRR_NCE_STATE_VALID);
if (NCE == NULL) {
VrrKdPrint("WcettReceivePktPairProbe: no NCE(s)",Probe->Opt.From,NULL);
} else {
Adj = &NCE->AdjIn;
if ((Probe->Opt.Seq % 2) == 0) {
Adj->MetricInfo.Wcett.PktPair.TimeLastProbeRcvd = Now;
Adj->MetricInfo.Wcett.PktPair.LastProbeSeq = Probe->Opt.Seq;
}
else if ((Adj->MetricInfo.Wcett.PktPair.TimeLastProbeRcvd != 0) &&
((Adj->MetricInfo.Wcett.PktPair.LastProbeSeq + 1) == Probe->Opt.Seq)) {
//
// Calculate OutDelta - the packet-pair delay.
// We must scale OutDelta to 100ns units.
//
OutDelta = Now - Adj->MetricInfo.Wcett.PktPair.TimeLastProbeRcvd;
Adj->MetricInfo.Wcett.PktPair.TimeLastProbeRcvd = 0;
if ((10000000L * OutDelta) < OutDelta) {
//
// We got an overly large OutDelta, so we
// can't report a reasonable number. Therefore, don't.
//
KdPrint(("VRR!WcettReceivePktPairProbe: Not sending reply due to OutDelta overflow.\n"));
}
OutDelta = (10000000L * OutDelta)/Frequency.QuadPart;
//
// Remember to send probe reply, and update counters.
//
SendProbeReply = TRUE;
Adj->MetricInfo.Wcett.PktPair.RepliesSent++;
}
}
KeReleaseSpinLock(&NC->Lock, OldIrql);
if (SendProbeReply) {
InterlockedIncrement((PLONG)&VA->CountXmitProbeReply);
PktPairSendProbeReply(VA, Probe, Now, OutDelta);
}
}
//* WcettReceiveProbe
//
// Receive a Probe. Called from ReceiveSRPacket.
// We have already verified that the MetricType is WCETT.
//
void
WcettReceiveProbe(
MiniportAdapter *VA,
InternalProbe *Probe,
VRRIf InIf)
{
VRRASSERT(Probe->Opt.MetricType == METRIC_TYPE_WCETT);
if (Probe->Opt.ProbeType == METRIC_TYPE_PKTPAIR)
WcettReceivePktPairProbe(VA, Probe);
}
//* WcettReceivePktPairProbeReply
//
// Receive a Probe Reply. Called from ReceiveSRPacket.
//
void
WcettReceivePktPairProbeReply(
MiniportAdapter *VA,
InternalProbeReply *ProbeReply)
{
NeighborCache *NC = &VA->NC;
NeighborCacheEntry *NCE;
Link *Adj;
KIRQL OldIrql;
PRPktPair *Special;
//
// Loop through NCE looking for the neighbor to whom the
// probe to which this probe reply is a response was sent.
//
KeAcquireSpinLock(&NC->Lock, &OldIrql);
NCE = FindNCE(NC,
ProbeReply->Opt.From,
ProbeReply->Opt.InIf, // LocIF: local IF to which counterparty sent Reply.
ProbeReply->Opt.OutIf, // RemIF: remote IF from which counterparty sent Reply.
VRR_NCE_STATE_VALID);
if (NCE == NULL) {
VrrKdPrint("WcettReceivePktPairProbeReply: no NCE(s)",ProbeReply->Opt.From,NULL);
KdPrint(("WcettReceivePktPairProbeReply: ProbeRep->OutIf=%u, ProbeRep->InIf=%u\n",
ProbeReply->Opt.OutIf,ProbeReply->Opt.InIf));
}
else {
Adj = &NCE->AdjOut;
// if (VirtualAddressEqual(ProbeReply->Opt.From,
// LC->nodes[Adj->targetIndex].address) &&
// (ProbeReply->Opt.OutIf == Adj->inif) &&
// (ProbeReply->Opt.InIf == Adj->outif)) {
//
// Found NCE to which probe was sent.
// If it's a response for the last probe
// we sent, calculate the bandwidth on the link.
//
if (Adj->MetricInfo.Wcett.PktPair.Outstanding ==
ProbeReply->Opt.Seq) {
Special = (PRPktPair *)ProbeReply->Opt.Special;
Adj->MetricInfo.Wcett.PktPair.RepliesRcvd++;
//
// Update CurrMin from this sample.
//
WcettUpdateMin(Adj, Special->OutDelta);
if (Adj->MetricInfo.Wcett.PktPair.PairsSent < VA->MetricParams.Wcett.PktPairMinOverProbes) {
//
// Update the bandwidth and keep accumulating CurrMin.
// This lets the bandwidth converge quickly
// after first discovering the link.
//
WcettUpdateBandwidth(Adj);
}
}
else {
//
// We got a late probe reply. Throw it away.
// This should not happen too often.
//
KdPrint(("VRR!WcettPktPairReceiveProbeReply LATE outstanding %u rcvd %u\n",
Adj->MetricInfo.Wcett.PktPair.Outstanding, ProbeReply->Opt.Seq));
}
Adj->MetricInfo.Wcett.PktPair.Outstanding = 0;
}
KeReleaseSpinLock(&NC->Lock, OldIrql);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -