Files
2022-06-21 21:23:33 +08:00

206 lines
7.8 KiB
C++

#include "PCONStrategy.hpp"
#include <ndn-cxx/lp/tags.hpp>
NFD_LOG_INIT(PCONStrategy);
namespace nfd
{
namespace fw
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//// PCONStrategy
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const time::milliseconds PCONStrategy::RETX_SUPPRESSION_INITIAL(10);
const time::milliseconds PCONStrategy::RETX_SUPPRESSION_MAX(250);
PCONStrategy::PCONStrategy(nfd::Forwarder &forwarder, const ndn::Name &name)
: Strategy(forwarder), ProcessNackTraits<PCONStrategy>(this), m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name &
PCONStrategy::getStrategyName()
{
static Name strategyName("/localhost/nfd/strategy/PCON/%FD%01");
return strategyName;
}
/**
* 收到 Interest 之后处理
* @param ingress
* @param interest
* @param pitEntry
*/
void
PCONStrategy::afterReceiveInterest(const nfd::FaceEndpoint &ingress, const ndn::Interest &interest,
const std::shared_ptr<nfd::pit::Entry> &pitEntry)
{
const fib::Entry &fibEntry = this->lookupFib(*pitEntry);
const fib::NextHopList &nexthops = fibEntry.getNextHops();
// 获取度量信息
MtForwardingInfo *measurementInfo = this->getPrefixMeasurements(fibEntry);
// 如果度量信息不存在,则创建一个新的
if (measurementInfo == nullptr)
{
measurementInfo = this->addPrefixMeasurements(fibEntry);
const Name prefixName = fibEntry.getPrefix();
measurementInfo->setPrefix(prefixName.toUri());
// 初始化转发概率
initializeForwMap(measurementInfo, nexthops);
}
// Interest 抑制
RetxSuppressionResult suppression = m_retxSuppression.decidePerPitEntry(*pitEntry);
if (suppression == RetxSuppressionResult::SUPPRESS)
{
NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
return;
}
Face *outFace = nullptr;
// 如果face是 LOCAL 的,不做额外的处理,直接按最短路径转发
if (ingress.face.getScope() != ndn::nfd::FACE_SCOPE_NON_LOCAL)
{
// 对于本地的face,直接按最佳路径走即可
auto selected = std::find_if(nexthops.begin(), nexthops.end(), [&](const auto &nexthop) {
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry);
});
if (selected != nexthops.end())
{
outFace = &((*selected).getFace());
}
}
else
{
// Random number between 0 and 1.
double r = ((double)rand() / (RAND_MAX));
double percSum = 0;
// Add all eligbile faces to list (excludes current downstream)
std::vector<Face *> eligbleFaces;
for (auto &n : fibEntry.getNextHops())
{
if (isNextHopEligible(ingress.face, interest, n, pitEntry))
{
// Add up percentage Sum.
percSum += measurementInfo->getforwPerc(n.getFace().getId());
eligbleFaces.push_back(&n.getFace());
}
}
if (eligbleFaces.size() < 1)
{
// 回环抑制
return;
}
else if (eligbleFaces.size() == 1)
{
// 只有一个有效下一跳,直接转发
outFace = eligbleFaces.front();
}
else
{
// 有多个下一跳,按概率转发
// Choose face according to current forwarding percentage:
double forwPerc = 0;
for (auto face : eligbleFaces)
{
forwPerc += measurementInfo->getforwPerc(face->getId()) / percSum;
if (r < forwPerc)
{
outFace = face;
break;
}
}
}
}
// 无法转发,返回Nack
if (outFace == nullptr)
{
lp::NackHeader nackHeader;
nackHeader.setReason(lp::NackReason::NO_ROUTE);
this->sendNack(pitEntry, ingress, nackHeader);
this->rejectPendingInterest(pitEntry);
return;
}
else
{
// 可以转发则直接转发
this->sendInterest(pitEntry, FaceEndpoint(*outFace, 0), interest);
}
// TODO: 探测
}
void
PCONStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry> &pitEntry,
const FaceEndpoint &ingress, const Data &data)
{
Name currentPrefix;
MtForwardingInfo *measurementInfo;
std::tie(currentPrefix, measurementInfo) = this->findPrefixMeasurementsLPM(
*pitEntry);
// 判断是否携带拥塞标记,如果携带拥塞标记,则将转发概率转移到其它接口
if (data.getCongestionMark() > 0)
{
// std::cout << ">>2: " << data.getCongestionMark() << std::endl;
double fwPerc = measurementInfo->getforwPerc(ingress.face.getId());
double change_perc = CHANGE_PER_MARK * fwPerc;
this->reduceFwPerc(measurementInfo, ingress.face.getId(), change_perc);
}
}
/**
* 收到 Nack 时处理
* @param ingress
* @param nack
* @param pitEntry
*/
void PCONStrategy::afterReceiveNack(const nfd::FaceEndpoint &ingress, const ndn::lp::Nack &nack,
const std::shared_ptr<nfd::pit::Entry> &pitEntry)
{
this->processNack(ingress.face, nack, pitEntry);
}
/**
* @brief 初始化转发概率
*
* @param measurementInfo
* @param nextHops
*/
void
PCONStrategy::initializeForwMap(MtForwardingInfo *measurementInfo,
const fib::NextHopList &nextHops)
{
int lowestId = std::numeric_limits<int>::max();
int minCost = std::numeric_limits<int>::max();
// 找到开销最小的下一跳
for (auto &n : nextHops)
{
if (n.getCost() < minCost)
{
minCost = n.getCost();
lowestId = n.getFace().getId();
}
}
// 开销最小的路径转发概率为 100%, 其它为0
for (auto &n : nextHops)
{
double perc = 0.0;
if (n.getFace().getId() == lowestId)
{
perc = 1.0;
}
measurementInfo->setforwPerc(n.getFace().getId(), perc);
}
}
}
}