Project

General

Profile

Actions

Feature #4849

closed

EndpointId in forwarding and Strategy API

Added by Junxiao Shi about 5 years ago. Updated almost 4 years ago.

Status:
Abandoned
Priority:
Normal
Category:
Forwarding
Target version:
-
Start date:
Due date:
% Done:

80%

Estimated time:
3.00 h

Description

In Forwarder class and Strategy base class APIs, add inEndpointId argument alongside inFace, and add outEndpointId argument alongside outFace.


Related issues 3 (1 open2 closed)

Related to NFD - Feature #4843: EndpointId in LinkServiceAbandonedMd Ashiqur Rahman

Actions
Blocks NFD - Feature #4281: Develop self-learning for broadcast and ad hoc wireless facesNew

Actions
Blocked by NFD - Feature #4842: EndpointId in PIT in-record and out-recordClosedMd Ashiqur Rahman

Actions
Actions #1

Updated by Junxiao Shi about 5 years ago

  • Blocks Feature #4281: Develop self-learning for broadcast and ad hoc wireless faces added
Actions #2

Updated by Junxiao Shi about 5 years ago

  • Blocked by Feature #4842: EndpointId in PIT in-record and out-record added
Actions #3

Updated by Md Ashiqur Rahman about 5 years ago

Should the fw::UnsolicitedDataPolicy and fw::UnsolicitedDataDecision also have this column?

Actions #4

Updated by Md Ashiqur Rahman about 5 years ago

Oh, wait, this is appearing to be a little vague in the issue description, so in the following code of the Forwarder class, we have:

Forwarder::Forwarder()
  : m_unsolicitedDataPolicy(new fw::DefaultUnsolicitedDataPolicy())
  , m_fib(m_nameTree)
  , m_pit(m_nameTree)
  , m_measurements(m_nameTree)
  , m_strategyChoice(*this)
{
  m_faceTable.afterAdd.connect([this] (Face& face) {
    face.afterReceiveInterest.connect(
      [this, &face] (const Interest& interest) {
        this->startProcessInterest(face, interest);
      });
    face.afterReceiveData.connect(
      [this, &face] (const Data& data) {
        this->startProcessData(face, data);
      });
    face.afterReceiveNack.connect(
      [this, &face] (const lp::Nack& nack) {
        this->startProcessNack(face, nack);
      });
    face.onDroppedInterest.connect(
      [this, &face] (const Interest& interest) {
        this->onDroppedInterest(face, interest);
      });
  });

  m_faceTable.beforeRemove.connect([this] (Face& face) {
    cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
  });

  m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
}

Shouldn't the afterReceiveInterest, the related startProcessInterest and so on also receive the endpointId filed? or will the endpointId be processed after the startProcess... methods are called?

I was under the impression that the endpointId would be processed by lp and then given to the forwarder (maybe I misunderstood from the NFD call discussion). Or is it going to be processed by forwarder directly and then given to the strategy?

Actions #5

Updated by Junxiao Shi about 5 years ago

Actions #6

Updated by Junxiao Shi about 5 years ago

  • Subject changed from EndpointId in Strategy API to EndpointId in forwarding and Strategy API

I was under the impression that the endpointId would be processed by lp and then given to the forwarder

Correct. #4843 should change LinkService.

Actions #7

Updated by Md Ashiqur Rahman about 5 years ago

In the Strategy class, should the Strategy::sendDataToAll method receive the endpointId at all?

void
Strategy::sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data,
                   const Face& outFace, uint64_t outEndpointId)
{
  BOOST_ASSERT(pitEntry->getInterest().matchesData(data));

  // delete the PIT entry's in-record based on outFace and outEndpointId,
  // since Data is sent to outFace with outEndpointId from which the Interest was received
  pitEntry->deleteInRecord(outFace, outEndpointId);

  m_forwarder.onOutgoingData(data, *const_pointer_cast<Face>(outFace.shared_from_this()), outEndpointId);
}

void
Strategy::sendDataToAll(const shared_ptr<pit::Entry>& pitEntry,
                        const Face& inFace, uint64_t inEndpointId, const Data& data)
{
  std::set<Face*> pendingDownstreams;
  auto now = time::steady_clock::now();

  // remember pending downstreams
  for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
    if (inRecord.getExpiry() > now) {
      if (inRecord.getFace().getId() == inFace.getId() &&
          inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
        continue;
      }
      pendingDownstreams.insert(&inRecord.getFace());
    }
  }

  for (const Face* pendingDownstream : pendingDownstreams) {
    this->sendData(pitEntry, data, *pendingDownstream, 0);
  }
}

The pendingDownstream set built from the Face class does not contain the endpointId column. then in case of this sendDataToAll method, how is the sendData going to know which outEndpontId-s will receive the Data packet?

Or should I just set the value to 0 for now and worry about this in issue #4281?

Actions #8

Updated by Junxiao Shi about 5 years ago

The pendingDownstream set built from the Face class does not contain the endpointId column.

pendingDownstreams should be keyed by FaceId+EndpointId, not just FaceId or Face pointer.

Actions #9

Updated by Md Ashiqur Rahman about 5 years ago

The pendingDownstream set built from the Face class does not contain the endpointId column.

pendingDownstreams should be keyed by FaceId+EndpointId, not just FaceId or Face pointer.

Do you mean something like this:

std::set< std::pair<Face*,uint64_t> > pendingDownstreams;
...
...
for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
    if (inRecord.getExpiry() > now) {
      if (inRecord.getFace().getId() == inFace.getId()
          inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
        continue;
      }
      pendingDownstreams.insert(std::make_pair(&inRecord.getFace(), &inRecord.getEndpointId()));
    }
  }
...
...
for (std::pair<const Face*, uint64_t> pendingDownstream : pendingDownstreams) {
  this->sendData(pitEntry, data, *pendingDownstream.first, pendingDownstream.second);
}

I'm not understanding the purpose of the inEndpointId argument in the Strategy::sendDataToAll method.

If I do this:

      if (inRecord.getFace().getId() == inFace.getId() && inRecord.getEndpointId() == inEndpointId &&
          inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
        continue;
      }

then am I not just picking up only one next hop to send back the Data? Whereas I can have multiple next-hops through multiple NIC's?

Actions #10

Updated by Junxiao Shi about 5 years ago

The expected behavior of sendDataToAll is sending Data to every FaceId+EndpointId combination among PIT downstream records, except inFace+inEndpointId; for ad-hoc wireless face when EndpointId is zero, the Data can be sent.
You can decide on internal implementation as long as this behavior is achieved.

Actions #11

Updated by Md Ashiqur Rahman about 5 years ago

The modifications affected by this issue appears to be propagated over many strategies too.
Should I just add the desired parameter in the function for now and later focus on the actual values to be passed for the function calls? i.e. set the parameter value passed for endpointId to 0 for now.

Actions #12

Updated by Junxiao Shi about 5 years ago

Should I just add the desired parameter in the function for now and later focus on the actual values to be passed for the function calls? i.e. set the parameter value passed for endpointId to 0 for now.

Yes, that's fine for individual strategies. In strategy class Doxygen, indicate this limitation: \note This strategy is not EndpointId-aware..

Actions #13

Updated by Md Ashiqur Rahman about 5 years ago

  • % Done changed from 0 to 90
Actions #14

Updated by Junxiao Shi about 5 years ago

  • Status changed from New to In Progress
  • % Done changed from 90 to 50

Change 5270 adds EndpointId to the strategy API but did not fully implement it because face system does not fully implement sending and receiving packets with EndpointId. This limitation is to be addressed in another commit under this issue.
In Strategy::sendDataToAll: Even on a wireless ad hoc link, a node shouldn't send Data back to a non-zero endpointId because that would unicast the Data back to where it comes from.

NFD Developer Guide strategy API section must be updated accordingly.

Actions #15

Updated by Md Ashiqur Rahman about 5 years ago

  • % Done changed from 50 to 100
Actions #16

Updated by Md Ashiqur Rahman about 5 years ago

Junxiao Shi wrote:

Change 5270 adds EndpointId to the strategy API but did not fully implement it because face system does not fully implement sending and receiving packets with EndpointId. This limitation is to be addressed in another commit under this issue.
In Strategy::sendDataToAll: Even on a wireless ad hoc link, a node shouldn't send Data back to a non-zero endpointId because that would unicast the Data back to where it comes from.

Question: Do we consider an EndpointID=0 as a broadcast address and other values as unicast? or a nullptr as broadcast address and others as unicast?

NFD Developer Guide strategy API section must be updated accordingly.

Does this affect the completion percentage of this task?

Actions #17

Updated by Junxiao Shi about 5 years ago

Question: Do we consider an EndpointID=0 as a broadcast address and other values as unicast? or a nullptr as broadcast address and others as unicast?

The convention described in NDN LAN thesis and implemented in esp8266ndn is:

  • EndpointId zero means "default". It means broadcast for broadcast-capable interfaces, such as Ethernet. It still means unicast for point-to-point interfaces, such as TCP tunnel.
  • EndpointId is not nilable so nullptr is not a valid value for this field.

NFD Developer Guide strategy API section must be updated accordingly.

Does this affect the completion percentage of this task?

Yes.

Actions #18

Updated by Md Ashiqur Rahman about 5 years ago

  • % Done changed from 100 to 60
Actions #19

Updated by Md Ashiqur Rahman about 5 years ago

If I wish to set the default endpoint=0 for LINK_TYPE_AD_HOC,

      auto endpoint = inRecord.getEndpointId();
      if (inRecord.getFace().getId() == ingress.face.getId() &&
          inRecord.getEndpointId() == ingress.endpoint &&
          inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
        continue;
      }
      else if (inRecord.getFace().getId() == ingress.face.getId() &&
               inRecord.getFace().getLinkType() == ndn::nfd::LINK_TYPE_AD_HOC) {
        endpoint = 0;
      }
      pendingDownstreams.emplace(&inRecord.getFace(), endpoint);

the current inRecord.getEndpointId() is non-const. However, as we discussed previously, to update the tables too with FaceEndpoint, should I set as shown in the code snippet and later when we add the new FaceEndpoint class in tables, then do a const_cast?

Actions #20

Updated by Md Ashiqur Rahman about 5 years ago

To-do: Developer guide update: #4849-14

Actions #21

Updated by Davide Pesavento almost 5 years ago

  • % Done changed from 60 to 80
Actions #22

Updated by Junxiao Shi almost 5 years ago

nfd:commit:c70794810592a90847656a97caf27f0326668240 breaks self-learning strategy.

  1. Forwarder::onContentStoreMiss inserts PIT in-record with EndpointId=0.
  2. SelfLearningStrategy::afterReceiveInterest attempts to insert SelfLearningStrategy::InRecordInfo to a PIT in-record with proper EndpointId.
  3. The latter segfaults because the PIT in-record does not exist.

To fix this error, the ingress passed to strategy needs to set EndpointId=0 as well.

Actions #23

Updated by Davide Pesavento over 4 years ago

  • Target version deleted (v0.7)
Actions #24

Updated by Davide Pesavento almost 4 years ago

  • Status changed from In Progress to Abandoned
Actions

Also available in: Atom PDF