|
// in Strategy (naive)
|
|
|
|
class Strategy
|
|
{
|
|
public: // triggers
|
|
virtual void
|
|
afterNewNexthop(const pit::Entry& pitEntry);
|
|
};
|
|
|
|
// in forwarding (naive)
|
|
|
|
void triggerStrategyAfterNewNexthop(const fib::Entry& fibEntry) {
|
|
|
|
auto range = nt.partialEnumerate(fibEntry.getPrefix(),
|
|
[] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
|
|
bool wantThis = nte.hasPitEntries() && nte.getFibEntry() != nullptr;
|
|
bool wantSubTree = nte.getFibEntry() != nullptr;
|
|
return std::make_pair(wantThis, wantSubTree);
|
|
});
|
|
|
|
for (const name_tree::Entry& nte : range) {
|
|
for (const shared_ptr<pit::Entry>& pitEntry : nte.getPitEntries()) {
|
|
// trigger strategy on pitEntry
|
|
// 1. lookup StrategyChoice table to determine effective strategy for pitEntry.getName()
|
|
// 2. invoke the strategy
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// in Fib
|
|
|
|
class Fib
|
|
{
|
|
public:
|
|
signal::Signal<Fib, fib::Entry> afterNewNexthop;
|
|
};
|
|
|
|
// in forwarding, triggerStrategyAfterNewNexthop is connected to afterNewNexthop
|
|
|
|
// in Strategy (better)
|
|
|
|
class Strategy
|
|
{
|
|
public: // triggers
|
|
virtual bool
|
|
supportsNewNexthop() const;
|
|
|
|
virtual void
|
|
afterNewNexthop(const pit::Entry& pitEntry);
|
|
};
|
|
|
|
// ************************************************************************************************
|
|
|
|
// in forwarding (better)
|
|
|
|
void triggerStrategyAfterNewNexthop(const fib::Entry& fibEntry) {
|
|
|
|
auto range = nt.partialEnumerate(fibEntry.getPrefix(),
|
|
[] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
|
|
// TODO is it possible to skip some enumeration
|
|
// 1. we should skip this subtree if no strategy within this subtree supports NewNexthop trigger
|
|
// 2. we can easily know the effective strategy for nte: either nte has SC, or nte's ancestor has it
|
|
// 3. but, how to know there's no other SC within subtree?
|
|
bool wantTree = nte.getFibEntry() != nullptr;
|
|
bool wantThis = nte.hasPitEntries() && wantTree;
|
|
return std::make_pair(wantThis, wantTree);
|
|
});
|
|
|
|
for (const name_tree::Entry& nte : range) {
|
|
// 1. lookup StrategyChoice table to determine effective strategy for nte.getName()
|
|
for (const shared_ptr<pit::Entry>& pitEntry : nte.getPitEntries()) {
|
|
// 2. trigger strategy on pitEntry
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// a concrete strategy
|
|
|
|
// "building block" in a separate class does not make sense, because there's no logic other than "retain PIT entry".
|
|
// Creating a new strategy also does not make sense, because after FIB nexthop is in place, forwarding logic is almost same as forwarding new Interest,
|
|
// and that differs per strategy. Duplicating an existing strategy greatly increases code complexity and maintenance.
|
|
|
|
// Start with modifying BestRouteStrategy2, then AsfStrategy and MulticastStrategy.
|
|
|
|
class BestRouteStrategy2 : public Strategy
|
|
{
|
|
public:
|
|
void
|
|
afterReceiveInterest(const FaceEnpoint& ingress, const Interest& interest, const shared_ptr<pit::Entry>& pitEntry)
|
|
{
|
|
const fib::Entry& fibEntry = fib.lookup(pitEntry);
|
|
if (fibEntry_has_usable_nexthops) {
|
|
forward_to_these_nexthops();
|
|
} else if (pitEntry_has_existing_out_records) {
|
|
// do nothing
|
|
} else {
|
|
// this->sendNacks(pitEntry);
|
|
// this->rejectPendingInterest(pitEntry);
|
|
this->setExpiryTimer(pitEntry, interest.getInterestLifetime());
|
|
|
|
// to support either Nack or retain in the same strategy, use a strategy parameter (#3868)
|
|
}
|
|
}
|
|
|
|
bool
|
|
supportsNewNexthop() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void
|
|
afterNewNexthop(const shared_ptr<pit::Entry>& pitEntry)
|
|
{
|
|
const fib::Entry& fibEntry = fib.lookup(pitEntry);
|
|
if (fibEntry_has_usable_nexthops) {
|
|
forward_to_these_nexthops();
|
|
} else if (pitEntry_has_existing_out_records) {
|
|
// do nothing
|
|
}
|
|
}
|
|
};
|
|
|