lp-fragmenter.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "lp-fragmenter.hpp"
27 #include "link-service.hpp"
28 #include <ndn-cxx/encoding/tlv.hpp>
29 
30 namespace nfd {
31 namespace face {
32 
33 NFD_LOG_INIT("LpFragmenter");
34 
35 static_assert(lp::tlv::LpPacket < 253, "LpPacket TLV-TYPE must fit in 1 octet");
36 static_assert(lp::tlv::Sequence < 253, "Sequence TLV-TYPE must fit in 1 octet");
37 static_assert(lp::tlv::FragIndex < 253, "FragIndex TLV-TYPE must fit in 1 octet");
38 static_assert(lp::tlv::FragCount < 253, "FragCount TLV-TYPE must fit in 1 octet");
39 static_assert(lp::tlv::Fragment < 253, "Fragment TLV-TYPE must fit in 1 octet");
40 
44 static const size_t MAX_SINGLE_FRAG_OVERHEAD =
45  1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
46  1 + 1 + 8 + // Sequence TLV
47  1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
48 
52 static const size_t MAX_FRAG_OVERHEAD =
53  1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
54  1 + 1 + 8 + // Sequence TLV
55  1 + 1 + 8 + // FragIndex TLV
56  1 + 1 + 8 + // FragCount TLV
57  1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
58 
60  : nMaxFragments(400)
61 {
62 }
63 
65  : m_options(options)
66  , m_linkService(linkService)
67 {
68 }
69 
70 void
72 {
73  m_options = options;
74 }
75 
76 const LinkService*
78 {
79  return m_linkService;
80 }
81 
82 std::tuple<bool, std::vector<lp::Packet>>
83 LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
84 {
85  BOOST_ASSERT(packet.has<lp::FragmentField>());
86  BOOST_ASSERT(!packet.has<lp::FragIndexField>());
87  BOOST_ASSERT(!packet.has<lp::FragCountField>());
88 
89  if (MAX_SINGLE_FRAG_OVERHEAD + packet.wireEncode().size() <= mtu) {
90  // fast path: fragmentation not needed
91  // To qualify for fast path, the packet must have space for adding a sequence number,
92  // because another NDNLPv2 feature may require the sequence number.
93  return std::make_tuple(true, std::vector<lp::Packet>{packet});
94  }
95 
96  ndn::Buffer::const_iterator netPktBegin, netPktEnd;
97  std::tie(netPktBegin, netPktEnd) = packet.get<lp::FragmentField>();
98  size_t netPktSize = std::distance(netPktBegin, netPktEnd);
99 
100  // compute size of other NDNLPv2 headers to be placed on the first fragment
101  size_t firstHeaderSize = 0;
102  const Block& packetWire = packet.wireEncode();
103  if (packetWire.type() == lp::tlv::LpPacket) {
104  for (const Block& element : packetWire.elements()) {
105  if (element.type() != lp::tlv::Fragment) {
106  firstHeaderSize += element.size();
107  }
108  }
109  }
110 
111  // compute payload size
112  if (MAX_FRAG_OVERHEAD + firstHeaderSize + 1 > mtu) { // 1-octet fragment
113  NFD_LOG_FACE_WARN("fragmentation error, MTU too small for first fragment: DROP");
114  return std::make_tuple(false, std::vector<lp::Packet>{});
115  }
116  size_t firstPayloadSize = std::min(netPktSize, mtu - firstHeaderSize - MAX_FRAG_OVERHEAD);
117  size_t payloadSize = mtu - MAX_FRAG_OVERHEAD;
118  size_t fragCount = 1 + ((netPktSize - firstPayloadSize) / payloadSize) +
119  ((netPktSize - firstPayloadSize) % payloadSize != 0);
120 
121  // compute FragCount
122  if (fragCount > m_options.nMaxFragments) {
123  NFD_LOG_FACE_WARN("fragmentation error, FragCount over limit: DROP");
124  return std::make_pair(false, std::vector<lp::Packet>{});
125  }
126 
127  // populate fragments
128  std::vector<lp::Packet> frags(fragCount);
129  frags.front() = packet; // copy input packet to preserve other NDNLPv2 fields
130  size_t fragIndex = 0;
131  auto fragBegin = netPktBegin,
132  fragEnd = fragBegin + firstPayloadSize;
133  while (fragBegin < netPktEnd) {
134  lp::Packet& frag = frags[fragIndex];
135  frag.add<lp::FragIndexField>(fragIndex);
136  frag.add<lp::FragCountField>(fragCount);
137  frag.set<lp::FragmentField>(std::make_pair(fragBegin, fragEnd));
138  BOOST_ASSERT(frag.wireEncode().size() <= mtu);
139 
140  ++fragIndex;
141  fragBegin = fragEnd;
142  fragEnd = std::min(netPktEnd, fragBegin + payloadSize);
143  }
144  BOOST_ASSERT(fragIndex == fragCount);
145 
146  return std::make_pair(true, frags);
147 }
148 
149 std::ostream&
150 operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh)
151 {
152  if (flh.obj.getLinkService() == nullptr) {
153  os << "[id=0,local=unknown,remote=unknown] ";
154  }
155  else {
156  os << FaceLogHelper<LinkService>(*flh.obj.getLinkService());
157  }
158  return os;
159 }
160 
161 } // namespace face
162 } // namespace nfd
size_t nMaxFragments
maximum number of fragments in a packet
void setOptions(const Options &options)
set options for fragmenter
#define NFD_LOG_FACE_WARN(msg)
Log a message at WARN level.
Definition: face-log.hpp:88
LpFragmenter(const Options &options=Options(), const LinkService *linkService=nullptr)
const LinkService * getLinkService() const
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
std::tuple< bool, std::vector< lp::Packet > > fragmentPacket(const lp::Packet &packet, size_t mtu)
fragments a network-layer packet into link-layer packets
Options that control the behavior of LpFragmenter.
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
static const size_t MAX_SINGLE_FRAG_OVERHEAD
maximum overhead on a single fragment, not counting other NDNLPv2 headers
static const size_t MAX_FRAG_OVERHEAD
maximum overhead of adding fragmentation to payload, not counting other NDNLPv2 headers ...