face.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "face.hpp"
23 #include "detail/face-impl.hpp"
24 
25 #include "encoding/tlv.hpp"
26 #include "security/key-chain.hpp"
28 #include "util/time.hpp"
29 #include "util/random.hpp"
30 #include "util/face-uri.hpp"
31 
32 // A callback scheduled through io.post and io.dispatch may be invoked after the face
33 // is destructed. To prevent this situation, these macros captures Face::m_impl as weak_ptr,
34 // and skips callback execution if the face has been destructed.
35 #define IO_CAPTURE_WEAK_IMPL(OP) \
36  { \
37  weak_ptr<Impl> implWeak(m_impl); \
38  m_ioService.OP([=] { \
39  auto impl = implWeak.lock(); \
40  if (impl != nullptr) {
41 #define IO_CAPTURE_WEAK_IMPL_END \
42  } \
43  }); \
44  }
45 
46 namespace ndn {
47 
48 Face::Face(shared_ptr<Transport> transport)
49  : m_internalIoService(new boost::asio::io_service())
50  , m_ioService(*m_internalIoService)
51  , m_internalKeyChain(new KeyChain())
52  , m_impl(make_shared<Impl>(*this))
53 {
54  construct(transport, *m_internalKeyChain);
55 }
56 
57 Face::Face(boost::asio::io_service& ioService)
58  : m_ioService(ioService)
59  , m_internalKeyChain(new KeyChain())
60  , m_impl(make_shared<Impl>(*this))
61 {
62  construct(nullptr, *m_internalKeyChain);
63 }
64 
65 Face::Face(const std::string& host, const std::string& port)
66  : m_internalIoService(new boost::asio::io_service())
67  , m_ioService(*m_internalIoService)
68  , m_internalKeyChain(new KeyChain())
69  , m_impl(make_shared<Impl>(*this))
70 {
71  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
72 }
73 
74 Face::Face(shared_ptr<Transport> transport, KeyChain& keyChain)
75  : m_internalIoService(new boost::asio::io_service())
76  , m_ioService(*m_internalIoService)
77  , m_impl(make_shared<Impl>(*this))
78 {
79  construct(transport, keyChain);
80 }
81 
82 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService)
83  : m_ioService(ioService)
84  , m_internalKeyChain(new KeyChain())
85  , m_impl(make_shared<Impl>(*this))
86 {
87  construct(transport, *m_internalKeyChain);
88 }
89 
90 Face::Face(shared_ptr<Transport> transport, boost::asio::io_service& ioService, KeyChain& keyChain)
91  : m_ioService(ioService)
92  , m_impl(make_shared<Impl>(*this))
93 {
94  construct(transport, keyChain);
95 }
96 
97 shared_ptr<Transport>
98 Face::makeDefaultTransport()
99 {
100  // transport=unix:///var/run/nfd.sock
101  // transport=tcp://localhost:6363
102 
103  std::string transportUri;
104 
105  const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT");
106  if (transportEnviron != nullptr) {
107  transportUri = transportEnviron;
108  }
109  else {
110  ConfigFile config;
111  transportUri = config.getParsedConfiguration().get<std::string>("transport", "");
112  }
113 
114  if (transportUri.empty()) {
115  // transport not specified, use default Unix transport.
116  return UnixTransport::create("");
117  }
118 
119  std::string protocol;
120  try {
121  util::FaceUri uri(transportUri);
122  protocol = uri.getScheme();
123 
124  if (protocol == "unix") {
125  return UnixTransport::create(transportUri);
126  }
127  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
128  return TcpTransport::create(transportUri);
129  }
130  else {
131  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
132  }
133  }
134  catch (const Transport::Error& error) {
135  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
136  }
137  catch (const util::FaceUri::Error& error) {
138  BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
139  }
140 }
141 
142 void
143 Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
144 {
145  if (transport == nullptr) {
146  transport = makeDefaultTransport();
147  }
148  BOOST_ASSERT(transport != nullptr);
149  m_transport = transport;
150 
151  m_nfdController.reset(new nfd::Controller(*this, keyChain));
152 
153  IO_CAPTURE_WEAK_IMPL(post) {
154  impl->ensureConnected(false);
156 }
157 
158 Face::~Face() = default;
159 
160 shared_ptr<Transport>
162 {
163  return m_transport;
164 }
165 
166 const PendingInterestId*
168  const DataCallback& afterSatisfied,
169  const NackCallback& afterNacked,
170  const TimeoutCallback& afterTimeout)
171 {
172  shared_ptr<Interest> interestToExpress = make_shared<Interest>(interest);
173 
174  // Use `interestToExpress` to avoid wire format creation for the original Interest
175  if (interestToExpress->wireEncode().size() > MAX_NDN_PACKET_SIZE) {
176  BOOST_THROW_EXCEPTION(Error("Interest size exceeds maximum limit"));
177  }
178 
179  // If the same ioService thread, dispatch directly calls the method
180  IO_CAPTURE_WEAK_IMPL(dispatch) {
181  impl->asyncExpressInterest(interestToExpress, afterSatisfied, afterNacked, afterTimeout);
183 
184  return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
185 }
186 
187 const PendingInterestId*
189  const OnData& onData,
190  const OnTimeout& onTimeout)
191 {
192  return this->expressInterest(
193  interest,
194  [onData] (const Interest& interest, const Data& data) {
195  if (onData != nullptr) {
196  onData(interest, const_cast<Data&>(data));
197  }
198  },
199  [onTimeout] (const Interest& interest, const lp::Nack& nack) {
200  if (onTimeout != nullptr) {
201  onTimeout(interest);
202  }
203  },
204  onTimeout
205  );
206 }
207 
208 const PendingInterestId*
209 Face::expressInterest(const Name& name, const Interest& tmpl,
210  const OnData& onData, const OnTimeout& onTimeout)
211 {
212  return expressInterest(Interest(tmpl).setName(name).setNonce(0),
213  onData, onTimeout);
214 }
215 
216 void
217 Face::removePendingInterest(const PendingInterestId* pendingInterestId)
218 {
219  IO_CAPTURE_WEAK_IMPL(post) {
220  impl->asyncRemovePendingInterest(pendingInterestId);
222 }
223 
224 void
226 {
227  IO_CAPTURE_WEAK_IMPL(post) {
228  impl->asyncRemoveAllPendingInterests();
230 }
231 
232 size_t
234 {
235  return m_impl->m_pendingInterestTable.size();
236 }
237 
238 void
239 Face::put(const Data& data)
240 {
241  Block wire = data.wireEncode();
242 
243  shared_ptr<lp::CachePolicyTag> cachePolicyTag = data.getTag<lp::CachePolicyTag>();
244  if (cachePolicyTag != nullptr) {
245  lp::Packet packet;
246  packet.add<lp::CachePolicyField>(*cachePolicyTag);
247  packet.add<lp::FragmentField>(std::make_pair(wire.begin(), wire.end()));
248  wire = packet.wireEncode();
249  }
250 
251  if (wire.size() > MAX_NDN_PACKET_SIZE)
252  BOOST_THROW_EXCEPTION(Error("Data size exceeds maximum limit"));
253 
254  IO_CAPTURE_WEAK_IMPL(dispatch) {
255  impl->asyncSend(wire);
257 }
258 
259 void
260 Face::put(const lp::Nack& nack)
261 {
262  lp::Packet packet;
263  packet.add<lp::NackField>(nack.getHeader());
264  const Block& interestWire = nack.getInterest().wireEncode();
265  packet.add<lp::FragmentField>(std::make_pair(interestWire.begin(), interestWire.end()));
266 
267  Block wire = packet.wireEncode();
268 
269  if (wire.size() > MAX_NDN_PACKET_SIZE)
270  BOOST_THROW_EXCEPTION(Error("Nack size exceeds maximum limit"));
271 
272  IO_CAPTURE_WEAK_IMPL(dispatch) {
273  impl->asyncSend(wire);
275 }
276 
277 const RegisteredPrefixId*
279  const InterestCallback& onInterest,
280  const RegisterPrefixFailureCallback& onFailure,
281  const security::SigningInfo& signingInfo,
282  uint64_t flags)
283 {
284  return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags);
285 }
286 
287 const RegisteredPrefixId*
289  const InterestCallback& onInterest,
290  const RegisterPrefixSuccessCallback& onSuccess,
291  const RegisterPrefixFailureCallback& onFailure,
292  const security::SigningInfo& signingInfo,
293  uint64_t flags)
294 {
295  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
296 
297  nfd::CommandOptions options;
298  options.setSigningInfo(signingInfo);
299 
300  return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
301  onSuccess, onFailure, flags, options);
302 }
303 
304 const InterestFilterId*
306  const InterestCallback& onInterest)
307 {
308  auto filter = make_shared<InterestFilterRecord>(interestFilter, onInterest);
309 
310  IO_CAPTURE_WEAK_IMPL(post) {
311  impl->asyncSetInterestFilter(filter);
313 
314  return reinterpret_cast<const InterestFilterId*>(filter.get());
315 }
316 
317 #ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
318 
319 const RegisteredPrefixId*
321  const OnInterest& onInterest,
322  const RegisterPrefixSuccessCallback& onSuccess,
323  const RegisterPrefixFailureCallback& onFailure,
324  const security::v1::IdentityCertificate& certificate,
325  uint64_t flags)
326 {
327  security::SigningInfo signingInfo;
328  if (!certificate.getName().empty()) {
329  signingInfo = signingByCertificate(certificate.getName());
330  }
331  return setInterestFilter(interestFilter, onInterest, onSuccess, onFailure, signingInfo, flags);
332 }
333 
334 const RegisteredPrefixId*
336  const OnInterest& onInterest,
337  const RegisterPrefixFailureCallback& onFailure,
338  const security::v1::IdentityCertificate& certificate,
339  uint64_t flags)
340 {
341  security::SigningInfo signingInfo;
342  if (!certificate.getName().empty()) {
343  signingInfo = signingByCertificate(certificate.getName());
344  }
345  return setInterestFilter(interestFilter, onInterest, onFailure, signingInfo, flags);
346 }
347 
348 const RegisteredPrefixId*
350  const OnInterest& onInterest,
351  const RegisterPrefixSuccessCallback& onSuccess,
352  const RegisterPrefixFailureCallback& onFailure,
353  const Name& identity,
354  uint64_t flags)
355 {
356  security::SigningInfo signingInfo = signingByIdentity(identity);
357  return setInterestFilter(interestFilter, onInterest,
358  onSuccess, onFailure,
359  signingInfo, flags);
360 }
361 
362 const RegisteredPrefixId*
364  const OnInterest& onInterest,
365  const RegisterPrefixFailureCallback& onFailure,
366  const Name& identity,
367  uint64_t flags)
368 {
369  security::SigningInfo signingInfo = signingByIdentity(identity);
370  return setInterestFilter(interestFilter, onInterest, onFailure, signingInfo, flags);
371 }
372 
373 #endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
374 
375 const RegisteredPrefixId*
377  const RegisterPrefixSuccessCallback& onSuccess,
378  const RegisterPrefixFailureCallback& onFailure,
379  const security::SigningInfo& signingInfo,
380  uint64_t flags)
381 {
382  nfd::CommandOptions options;
383  options.setSigningInfo(signingInfo);
384 
385  return m_impl->registerPrefix(prefix, nullptr, onSuccess, onFailure, flags, options);
386 }
387 
388 #ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
389 const RegisteredPrefixId*
391  const RegisterPrefixSuccessCallback& onSuccess,
392  const RegisterPrefixFailureCallback& onFailure,
393  const security::v1::IdentityCertificate& certificate,
394  uint64_t flags)
395 {
396  security::SigningInfo signingInfo;
397  if (!certificate.getName().empty()) {
398  signingInfo = signingByCertificate(certificate.getName());
399  }
400  return registerPrefix(prefix, onSuccess, onFailure, signingInfo, flags);
401 }
402 
403 const RegisteredPrefixId*
405  const RegisterPrefixSuccessCallback& onSuccess,
406  const RegisterPrefixFailureCallback& onFailure,
407  const Name& identity,
408  uint64_t flags)
409 {
410  security::SigningInfo signingInfo = signingByIdentity(identity);
411  return registerPrefix(prefix, onSuccess, onFailure, signingInfo, flags);
412 }
413 #endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
414 
415 void
416 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
417 {
418  IO_CAPTURE_WEAK_IMPL(post) {
419  impl->asyncUnregisterPrefix(registeredPrefixId, nullptr, nullptr);
421 }
422 
423 void
424 Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
425 {
426  IO_CAPTURE_WEAK_IMPL(post) {
427  impl->asyncUnsetInterestFilter(interestFilterId);
429 }
430 
431 void
432 Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
433  const UnregisterPrefixSuccessCallback& onSuccess,
434  const UnregisterPrefixFailureCallback& onFailure)
435 {
436  IO_CAPTURE_WEAK_IMPL(post) {
437  impl->asyncUnregisterPrefix(registeredPrefixId, onSuccess, onFailure);
439 }
440 
441 void
442 Face::doProcessEvents(const time::milliseconds& timeout, bool keepThread)
443 {
444  if (m_ioService.stopped()) {
445  m_ioService.reset(); // ensure that run()/poll() will do some work
446  }
447 
448  try {
449  if (timeout < time::milliseconds::zero()) {
450  // do not block if timeout is negative, but process pending events
451  m_ioService.poll();
452  return;
453  }
454 
455  if (timeout > time::milliseconds::zero()) {
456  boost::asio::io_service& ioService = m_ioService;
457  unique_ptr<boost::asio::io_service::work>& work = m_impl->m_ioServiceWork;
458  m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.scheduleEvent(timeout,
459  [&ioService, &work] {
460  ioService.stop();
461  work.reset();
462  });
463  }
464 
465  if (keepThread) {
466  // work will ensure that m_ioService is running until work object exists
467  m_impl->m_ioServiceWork.reset(new boost::asio::io_service::work(m_ioService));
468  }
469 
470  m_ioService.run();
471  }
472  catch (...) {
473  m_impl->m_ioServiceWork.reset();
474  m_impl->m_pendingInterestTable.clear();
475  m_impl->m_registeredPrefixTable.clear();
476  throw;
477  }
478 }
479 
480 void
482 {
483  IO_CAPTURE_WEAK_IMPL(post) {
484  this->asyncShutdown();
486 }
487 
488 void
489 Face::asyncShutdown()
490 {
491  m_impl->m_pendingInterestTable.clear();
492  m_impl->m_registeredPrefixTable.clear();
493 
494  if (m_transport->isConnected())
495  m_transport->close();
496 
497  m_impl->m_ioServiceWork.reset();
498 }
499 
503 template<typename NETPKT>
504 static void
505 extractLpLocalFields(NETPKT& netPacket, const lp::Packet& lpPacket)
506 {
507  if (lpPacket.has<lp::IncomingFaceIdField>()) {
508  netPacket.setTag(make_shared<lp::IncomingFaceIdTag>(lpPacket.get<lp::IncomingFaceIdField>()));
509  }
510 }
511 
512 void
513 Face::onReceiveElement(const Block& blockFromDaemon)
514 {
515  lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet,
516  // no need to distinguish
517 
518  Buffer::const_iterator begin, end;
519  std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
520  Block netPacket(&*begin, std::distance(begin, end));
521  switch (netPacket.type()) {
522  case tlv::Interest: {
523  auto interest = make_shared<Interest>(netPacket);
524  if (lpPacket.has<lp::NackField>()) {
525  auto nack = make_shared<lp::Nack>(std::move(*interest));
526  nack->setHeader(lpPacket.get<lp::NackField>());
527  extractLpLocalFields(*nack, lpPacket);
528  m_impl->nackPendingInterests(*nack);
529  }
530  else {
531  extractLpLocalFields(*interest, lpPacket);
532  m_impl->processInterestFilters(*interest);
533  }
534  break;
535  }
536  case tlv::Data: {
537  auto data = make_shared<Data>(netPacket);
538  extractLpLocalFields(*data, lpPacket);
539  m_impl->satisfyPendingInterests(*data);
540  break;
541  }
542  }
543 }
544 
545 } // namespace ndn
size_t wireEncode(EncodingImpl< TAG > &encoder) const
append packet to encoder
Definition: packet.cpp:42
Copyright (c) 2013-2016 Regents of the University of California.
Definition: common.hpp:74
const NackHeader & getHeader() const
Definition: nack.hpp:65
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:120
Copyright (c) 2013-2016 Regents of the University of California.
Definition: common.hpp:98
implementation detail of Face
Definition: face-impl.hpp:51
Buffer::const_iterator end() const
Definition: block.cpp:486
const RegisteredPrefixId * setInterestFilter(const InterestFilter &interestFilter, const InterestCallback &onInterest, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Set InterestFilter to dispatch incoming matching interest to onInterest callback and register the fil...
Definition: face.cpp:278
Packet & add(const typename FIELD::ValueType &value)
add a FIELD with value
Definition: packet.hpp:156
declares the set of Interests a producer can serve, which starts with a name prefix, plus an optional regular expression
const Interest & getInterest() const
Definition: nack.hpp:53
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
represents an Interest packet
Definition: interest.hpp:42
function< void(const Interest &)> OnTimeout
Callback invoked when expressed Interest times out.
Definition: face.hpp:89
bool has() const
Definition: packet.hpp:75
function< void(const InterestFilter &, const Interest &)> OnInterest
Callback invoked when incoming Interest matches the specified InterestFilter.
Definition: face.hpp:100
virtual void doProcessEvents(const time::milliseconds &timeout, bool keepThread)
Definition: face.cpp:442
Signing parameters passed to KeyChain.
SigningInfo signingByCertificate(const Name &certName)
void unregisterPrefix(const RegisteredPrefixId *registeredPrefixId, const UnregisterPrefixSuccessCallback &onSuccess, const UnregisterPrefixFailureCallback &onFailure)
Unregister prefix from RIB.
Definition: face.cpp:432
static shared_ptr< UnixTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
represents a Network Nack
Definition: nack.hpp:40
const Name & getName() const
Get name of the Data packet.
Definition: data.hpp:318
provides a tag type for simple types
Definition: tag.hpp:58
size_t size() const
Definition: block.cpp:504
#define IO_CAPTURE_WEAK_IMPL(OP)
Copyright (c) 2013-2016 Regents of the University of California.
Definition: face.cpp:35
void removeAllPendingInterests()
Cancel all previously expressed Interests.
Definition: face.cpp:225
size_t wireEncode(EncodingImpl< TAG > &encoder, bool wantUnsignedPortionOnly=false) const
Fast encoding or block size estimation.
Definition: data.cpp:52
detail::FieldDecl< field_location_tags::Fragment, std::pair< Buffer::const_iterator, Buffer::const_iterator >, tlv::Fragment > FragmentField
The value of the wire encoded field is the data between the provided iterators.
Definition: fields.hpp:77
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:100
contains options for ControlCommand execution
shared_ptr< Transport > getTransport()
Definition: face.cpp:161
static shared_ptr< TcpTransport > create(const std::string &uri)
Create transport with parameters defined in URI.
void shutdown()
Shutdown face operations.
Definition: face.cpp:481
SigningInfo signingByIdentity(const Name &identity)
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: interest.cpp:217
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:110
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:105
Name abstraction to represent an absolute name.
Definition: name.hpp:46
void unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
Remove the registered prefix entry with the registeredPrefixId.
Definition: face.cpp:416
detail::FieldDecl< field_location_tags::Header, NackHeader, tlv::Nack > NackField
Definition: fields.hpp:53
CommandOptions & setSigningInfo(const security::SigningInfo &signingInfo)
sets signing parameters
function< void(const InterestFilter &, const Interest &)> InterestCallback
Callback invoked when incoming Interest matches the specified InterestFilter.
Definition: face.hpp:94
#define IO_CAPTURE_WEAK_IMPL_END
Definition: face.cpp:41
function< void(const Interest &, Data &)> OnData
Callback invoked when expressed Interest gets satisfied with Data packet.
Definition: face.hpp:83
size_t getNPendingInterests() const
Get number of pending Interests.
Definition: face.cpp:233
bool empty() const
Check if name is emtpy.
Definition: name.hpp:390
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:115
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
const PendingInterestId * expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express Interest.
Definition: face.cpp:167
static void extractLpLocalFields(NETPKT &netPacket, const lp::Packet &lpPacket)
extract local fields from NDNLPv2 packet and tag onto a network layer packet
Definition: face.cpp:505
function< void(const Interest &)> TimeoutCallback
Callback invoked when expressed Interest times out.
Definition: face.hpp:77
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:72
represents a Data packet
Definition: data.hpp:37
const RegisteredPrefixId * registerPrefix(const Name &prefix, const RegisterPrefixSuccessCallback &onSuccess, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Register prefix with the connected NDN forwarder.
Definition: face.cpp:376
Face(shared_ptr< Transport > transport=nullptr)
Create Face using given transport (or default transport if omitted)
Definition: face.cpp:48
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when expressed Interest gets satisfied with a Data packet.
Definition: face.hpp:67
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:217
Buffer::const_iterator begin() const
Definition: block.cpp:477
void put(const Data &data)
Publish data packet.
Definition: face.cpp:239
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size