Skip to content

Instantly share code, notes, and snippets.

@yoursunny
Last active October 11, 2015 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoursunny/22a7d53711b4e9bc198a to your computer and use it in GitHub Desktop.
Save yoursunny/22a7d53711b4e9bc198a to your computer and use it in GitHub Desktop.
NFD Face System design for LinkService http://redmine.named-data.net/issues/2222 and permanent face http://redmine.named-data.net/issues/2491
// Face design
// This design incorporates:
// Link Services http://redmine.named-data.net/issues/2222
// Permanent Face http://redmine.named-data.net/issues/2491
// -------- Face, Socket, LinkService --------
namespace nfd {
namespace face {
typedef uint64_t FaceId;
enum class FaceState {
NONE,
DOWN,
UP
};
// may need more states when we have tunnel authentication (eg. UNAUTHENTICATED)
class Face : noncopyable
{
public:
Face(LinkService& service, Socket& socket);
public: // upper interface connected to forwarding
void
sendInterest(const Interest& interest);
void
sendData(const Data& interest);
void
sendNack(const Nack& interest);
Signal<LinkService, Interest>& afterReceiveInterest;
Signal<LinkService, Data>& afterReceiveData;
Signal<LinkService, Nack>& afterReceiveNack;
public: // static properties
FaceId
getId() const; // from Face
FaceUri
getLocalUri() const; // from Socket
FaceUri
getRemoteUri() const; // from Socket
FacePersistency
getPersistency() const; // from Socket
LinkType // point-to-point|multi-access
getLinkType() const; // from Socket
public: // dynamic properties
FaceState
getState() const; // from Socket
Signal<Link, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
FaceCounters
getCounters() const; // network layer packet counters from LinkService, link layer packet and byte counters from Socket
};
class Socket
{
public:
struct Packet
{
Block packet;
NetworkAddress localAddr;
NetworkAddress remoteAddr;
}
public: // upper interface
void
send(const Packet& packet); // increment counter and call .doSend
Signal<Link, Packet> afterReceive;
private: // upper interface to be overridden by subclass
virtual void
doSend(const Packet& packet) = 0;
protected: // upper interface to be invoked by subclass
void
receive(const Packet& packet); // increment counter and signal afterReceive
public: // static properties
FaceUri
getLocalUri() const;
FaceUri
getRemoteUri() const;
FacePersistency
getPersistency() const;
// If persistency==PERMANENT, Socket is responsible for recovery.
// But tunnel authentication should be done by another component through a signal.
LinkType
getLinkType() const;
public: // dynamic properties
FaceState
getState() const;
Signal<Link, FaceState/*old*/, FaceState/*new*/> afterStateChange;
// This should be UP/DOWN only.
// Tunnel authentication's UNAUTHENTICATED state should come from LinkService or mgmt.
// By that time, we may define a separate enum as SocketState{DOWN,UP}.
LinkCounters
getCounters() const; // link layer packet and byte counters
protected:
void
changeState(FaceState newState); // UP/DOWN only
};
class LinkService
{
public:
void
setSocket(Socket& link);
public: // upper interface connected to forwarding
void
sendInterest(const Interest& interest); // increment counter and call .doSendInterest
void
sendData(const Data& interest); // increment counter and call .doSendData
void
sendNack(const Nack& interest); // increment counter and call .doSendNack
Signal<LinkService, Interest> afterReceiveInterest;
Signal<LinkService, Data> afterReceiveData;
Signal<LinkService, Nack> afterReceiveNack;
private: // upper interface to be overridden in subclass
virtual void
doSendInterest(const Interest& interest) = 0;
virtual void
doSendData(const Data& interest) = 0;
virtual void
doSendNack(const Nack& interest) = 0;
protected: // upper interface to be invoked in subclass
void
receiveInterest(const Interest& interest); // increment counter and signal afterReceiveInterest
void
receiveData(const Data& data); // increment counter and signal afterReceiveData
void
receiveNack(const Nack& nack); // increment counter and signal afterReceiveNack
protected: // lower interface
bool
sendPacket(const Socket::Packet& packet);
private: // lower interface
virtual void
receivePacket(const Socket::Packet& packet) = 0;
public: // dynamic properties
NetCounters
getCounters(); // network layer packet counters
};
} // namespace face
} // namespace nfd
// -------- generic LinkService --------
namespace nfd {
namespace face {
class GenericLinkService : public LinkService
{
public:
class Options
{
bool enableFragmentation;
bool enableReassembly;
// send path and receive path should have separate options if it makes sense
time::nanoseconds reassemblyTimeout;
// (other options can be added when necessary)
bool allowLocalFields;
// enableLocalFields enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy.
// Nack is always enabled, because there's no harm keeping it enabled.
// When decoding, implementation should ensure a field is attached on a correct network layer packet type,
// especially when protocol defines "packet MUST be dropped" (eg. Nack is only allowed on an Interest).
};
explicit
GenericLinkService(const Options& options);
const Options&
getOptions() const;
void
setOptions(const Options& options);
private: // send path entrypoint
virtual void
doSendInterest(const Interest& interest) override;
virtual void
doSendData(const Data& interest) override;
virtual void
doSendNack(const Nack& interest) override;
private: // receive path entrypoint
virtual void
receivePacket(const Socket::Packet& packet) override;
};
// Apart from packet encoding/decoding (which includes Nack, IncomingFaceId, NextHopFaceId, CachePolicy),
// we only have fragmentation+reassembly service for now.
// So we only need a few classes for fragmentation and reassembly (similar to NDNLPv1 implementation),
// plus a separate step for assigning sequence numbers.
// Unlike NDNLPv1 implementation, sequence number allocation should happen after fragmentation;
// which is necessary to accomodate transmitting IDLE packets from other services.
// Each of doSendX methods should do encoding, invoke fragmentation, invoke seq allocation, and invoke .sendPacket to pass down LpPacket;
// the latter 3 steps should be done in a common helper function;
// in case fragmentation is disabled, that helper function can invoke .sendPacket straight.
// receivePacket should call reassembly, do decoding, and invoke .receiveX to pass up network layer packet;
// in case reassembly is disabled, this method can skip reassembly step.
} // namespace face
} // namespace nfd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment