blob: ad10054641ce654c915c52d82745c94fc73e8a4b [file] [log] [blame]
Junxiao Shi65f1a712014-11-20 14:59:36 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Junxiao Shi65f1a712014-11-20 14:59:36 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Junxiao Shi7357ef22016-09-07 02:39:37 +000022#include "fib-entry.hpp"
Junxiao Shi65f1a712014-11-20 14:59:36 -070023#include "encoding/block-helpers.hpp"
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050024#include "encoding/encoding-buffer.hpp"
25#include "encoding/tlv-nfd.hpp"
Junxiao Shi65f1a712014-11-20 14:59:36 -070026#include "util/concepts.hpp"
27
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050028#include <boost/range/adaptor/reversed.hpp>
29
Junxiao Shi65f1a712014-11-20 14:59:36 -070030namespace ndn {
31namespace nfd {
32
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050033BOOST_CONCEPT_ASSERT((StatusDatasetItem<NextHopRecord>));
34BOOST_CONCEPT_ASSERT((StatusDatasetItem<FibEntry>));
Junxiao Shi65f1a712014-11-20 14:59:36 -070035
36NextHopRecord::NextHopRecord()
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050037 : m_faceId(0) // INVALID_FACEID
Junxiao Shi65f1a712014-11-20 14:59:36 -070038 , m_cost(0)
39{
40}
41
42NextHopRecord::NextHopRecord(const Block& block)
43{
44 this->wireDecode(block);
45}
46
47NextHopRecord&
48NextHopRecord::setFaceId(uint64_t faceId)
49{
50 m_faceId = faceId;
51 m_wire.reset();
52 return *this;
53}
54
55NextHopRecord&
56NextHopRecord::setCost(uint64_t cost)
57{
58 m_cost = cost;
59 m_wire.reset();
60 return *this;
61}
62
Alexander Afanasyev74633892015-02-08 18:08:46 -080063template<encoding::Tag TAG>
Junxiao Shi65f1a712014-11-20 14:59:36 -070064size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080065NextHopRecord::wireEncode(EncodingImpl<TAG>& block) const
Junxiao Shi65f1a712014-11-20 14:59:36 -070066{
67 size_t totalLength = 0;
Junxiao Shi65f1a712014-11-20 14:59:36 -070068
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050069 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost);
70 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::FaceId, m_faceId);
Junxiao Shi65f1a712014-11-20 14:59:36 -070071
72 totalLength += block.prependVarNumber(totalLength);
73 totalLength += block.prependVarNumber(ndn::tlv::nfd::NextHopRecord);
74 return totalLength;
75}
76
77template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080078NextHopRecord::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Junxiao Shi65f1a712014-11-20 14:59:36 -070079
80template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080081NextHopRecord::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Junxiao Shi65f1a712014-11-20 14:59:36 -070082
83const Block&
84NextHopRecord::wireEncode() const
85{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050086 if (m_wire.hasWire())
Junxiao Shi65f1a712014-11-20 14:59:36 -070087 return m_wire;
Junxiao Shi65f1a712014-11-20 14:59:36 -070088
89 EncodingEstimator estimator;
90 size_t estimatedSize = wireEncode(estimator);
91
92 EncodingBuffer buffer(estimatedSize, 0);
93 wireEncode(buffer);
94
95 m_wire = buffer.block();
96 return m_wire;
97}
98
99void
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500100NextHopRecord::wireDecode(const Block& block)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700101{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500102 if (block.type() != tlv::nfd::NextHopRecord) {
103 BOOST_THROW_EXCEPTION(Error("expecting NextHopRecord, but Block has type " + to_string(block.type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700104 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500105 m_wire = block;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700106 m_wire.parse();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700107 Block::element_const_iterator val = m_wire.elements_begin();
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500108
Junxiao Shi65f1a712014-11-20 14:59:36 -0700109 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500110 BOOST_THROW_EXCEPTION(Error("unexpected end of NextHopRecord"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700111 }
112 else if (val->type() != tlv::nfd::FaceId) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500113 BOOST_THROW_EXCEPTION(Error("expecting FaceId, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700114 }
115 m_faceId = readNonNegativeInteger(*val);
116 ++val;
117
118 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500119 BOOST_THROW_EXCEPTION(Error("unexpected end of NextHopRecord"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700120 }
121 else if (val->type() != tlv::nfd::Cost) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500122 BOOST_THROW_EXCEPTION(Error("expecting Cost, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700123 }
124 m_cost = readNonNegativeInteger(*val);
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500125 ++val;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700126}
127
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500128bool
129operator==(const NextHopRecord& a, const NextHopRecord& b)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700130{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500131 return a.getFaceId() == b.getFaceId() &&
132 a.getCost() == b.getCost();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700133}
134
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500135std::ostream&
136operator<<(std::ostream& os, const NextHopRecord& nh)
137{
138 return os << "NextHopRecord("
139 << "FaceId: " << nh.getFaceId() << ", "
140 << "Cost: " << nh.getCost()
141 << ")";
142}
143
144////////////////////
145
146FibEntry::FibEntry() = default;
147
Junxiao Shi65f1a712014-11-20 14:59:36 -0700148FibEntry::FibEntry(const Block& block)
149{
150 this->wireDecode(block);
151}
152
153FibEntry&
154FibEntry::setPrefix(const Name& prefix)
155{
156 m_prefix = prefix;
157 m_wire.reset();
158 return *this;
159}
160
161FibEntry&
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500162FibEntry::addNextHopRecord(const NextHopRecord& nh)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700163{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500164 m_nextHopRecords.push_back(nh);
165 m_wire.reset();
166 return *this;
167}
168
169FibEntry&
170FibEntry::clearNextHopRecords()
171{
172 m_nextHopRecords.clear();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700173 m_wire.reset();
174 return *this;
175}
176
Alexander Afanasyev74633892015-02-08 18:08:46 -0800177template<encoding::Tag TAG>
Junxiao Shi65f1a712014-11-20 14:59:36 -0700178size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800179FibEntry::wireEncode(EncodingImpl<TAG>& block) const
Junxiao Shi65f1a712014-11-20 14:59:36 -0700180{
181 size_t totalLength = 0;
182
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500183 for (const auto& nh : m_nextHopRecords | boost::adaptors::reversed) {
184 totalLength += nh.wireEncode(block);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700185 }
Junxiao Shi65f1a712014-11-20 14:59:36 -0700186 totalLength += m_prefix.wireEncode(block);
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500187
Junxiao Shi65f1a712014-11-20 14:59:36 -0700188 totalLength += block.prependVarNumber(totalLength);
189 totalLength += block.prependVarNumber(tlv::nfd::FibEntry);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700190 return totalLength;
191}
192
193template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800194FibEntry::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700195
196template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800197FibEntry::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700198
199const Block&
200FibEntry::wireEncode() const
201{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500202 if (m_wire.hasWire())
Junxiao Shi65f1a712014-11-20 14:59:36 -0700203 return m_wire;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700204
205 EncodingEstimator estimator;
206 size_t estimatedSize = wireEncode(estimator);
207
208 EncodingBuffer buffer(estimatedSize, 0);
209 wireEncode(buffer);
210
211 m_wire = buffer.block();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700212 return m_wire;
213}
214
215void
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500216FibEntry::wireDecode(const Block& block)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700217{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500218 if (block.type() != tlv::nfd::FibEntry) {
219 BOOST_THROW_EXCEPTION(Error("expecting FibEntry, but Block has type " + to_string(block.type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700220 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500221 m_wire = block;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700222 m_wire.parse();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700223 Block::element_const_iterator val = m_wire.elements_begin();
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500224
Junxiao Shi65f1a712014-11-20 14:59:36 -0700225 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500226 BOOST_THROW_EXCEPTION(Error("unexpected end of FibEntry"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700227 }
228 else if (val->type() != tlv::Name) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500229 BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700230 }
231 m_prefix.wireDecode(*val);
232 ++val;
233
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500234 m_nextHopRecords.clear();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700235 for (; val != m_wire.elements_end(); ++val) {
236 if (val->type() != tlv::nfd::NextHopRecord) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500237 BOOST_THROW_EXCEPTION(Error("expecting NextHopRecord, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700238 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500239 m_nextHopRecords.emplace_back(*val);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700240 }
241}
242
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500243bool
244operator==(const FibEntry& a, const FibEntry& b)
245{
246 const auto& aNextHops = a.getNextHopRecords();
247 const auto& bNextHops = b.getNextHopRecords();
248
249 if (a.getPrefix() != b.getPrefix() ||
250 aNextHops.size() != bNextHops.size())
251 return false;
252
253 std::vector<bool> matched(bNextHops.size(), false);
254 return std::all_of(aNextHops.begin(), aNextHops.end(),
255 [&] (const NextHopRecord& nh) {
256 for (size_t i = 0; i < bNextHops.size(); ++i) {
257 if (!matched[i] && bNextHops[i] == nh) {
258 matched[i] = true;
259 return true;
260 }
261 }
262 return false;
263 });
264}
265
266std::ostream&
267operator<<(std::ostream& os, const FibEntry& entry)
268{
269 os << "FibEntry(Prefix: " << entry.getPrefix() << ",\n"
270 << " NextHops: [";
271
272 bool first = true;
273 for (const auto& nh : entry.getNextHopRecords()) {
274 if (!first)
275 os << ",\n ";
276 first = false;
277 os << nh;
278 }
279 os << "]\n";
280
281 return os << " )";
282}
283
Junxiao Shi65f1a712014-11-20 14:59:36 -0700284} // namespace nfd
285} // namespace ndn