blob: ef47f6a67ee62eeecd0c2d74497b573964353a1f [file] [log] [blame]
Junxiao Shi65f1a712014-11-20 14:59:36 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento88a0d812017-08-19 21:31:42 -04002/*
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 Pesaventof8503d22017-02-17 01:19:10 -050037 : m_faceId(INVALID_FACE_ID)
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
Davide Pesavento88a0d812017-08-19 21:31:42 -040077NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(NextHopRecord);
Junxiao Shi65f1a712014-11-20 14:59:36 -070078
79const Block&
80NextHopRecord::wireEncode() const
81{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050082 if (m_wire.hasWire())
Junxiao Shi65f1a712014-11-20 14:59:36 -070083 return m_wire;
Junxiao Shi65f1a712014-11-20 14:59:36 -070084
85 EncodingEstimator estimator;
86 size_t estimatedSize = wireEncode(estimator);
87
88 EncodingBuffer buffer(estimatedSize, 0);
89 wireEncode(buffer);
90
91 m_wire = buffer.block();
92 return m_wire;
93}
94
95void
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050096NextHopRecord::wireDecode(const Block& block)
Junxiao Shi65f1a712014-11-20 14:59:36 -070097{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -050098 if (block.type() != tlv::nfd::NextHopRecord) {
99 BOOST_THROW_EXCEPTION(Error("expecting NextHopRecord, but Block has type " + to_string(block.type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700100 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500101 m_wire = block;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700102 m_wire.parse();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700103 Block::element_const_iterator val = m_wire.elements_begin();
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500104
Junxiao Shi65f1a712014-11-20 14:59:36 -0700105 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500106 BOOST_THROW_EXCEPTION(Error("unexpected end of NextHopRecord"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700107 }
108 else if (val->type() != tlv::nfd::FaceId) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500109 BOOST_THROW_EXCEPTION(Error("expecting FaceId, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700110 }
111 m_faceId = readNonNegativeInteger(*val);
112 ++val;
113
114 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500115 BOOST_THROW_EXCEPTION(Error("unexpected end of NextHopRecord"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700116 }
117 else if (val->type() != tlv::nfd::Cost) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500118 BOOST_THROW_EXCEPTION(Error("expecting Cost, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700119 }
120 m_cost = readNonNegativeInteger(*val);
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500121 ++val;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700122}
123
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500124bool
125operator==(const NextHopRecord& a, const NextHopRecord& b)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700126{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500127 return a.getFaceId() == b.getFaceId() &&
128 a.getCost() == b.getCost();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700129}
130
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500131std::ostream&
132operator<<(std::ostream& os, const NextHopRecord& nh)
133{
134 return os << "NextHopRecord("
135 << "FaceId: " << nh.getFaceId() << ", "
136 << "Cost: " << nh.getCost()
137 << ")";
138}
139
140////////////////////
141
142FibEntry::FibEntry() = default;
143
Junxiao Shi65f1a712014-11-20 14:59:36 -0700144FibEntry::FibEntry(const Block& block)
145{
146 this->wireDecode(block);
147}
148
149FibEntry&
150FibEntry::setPrefix(const Name& prefix)
151{
152 m_prefix = prefix;
153 m_wire.reset();
154 return *this;
155}
156
157FibEntry&
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500158FibEntry::addNextHopRecord(const NextHopRecord& nh)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700159{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500160 m_nextHopRecords.push_back(nh);
161 m_wire.reset();
162 return *this;
163}
164
165FibEntry&
166FibEntry::clearNextHopRecords()
167{
168 m_nextHopRecords.clear();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700169 m_wire.reset();
170 return *this;
171}
172
Alexander Afanasyev74633892015-02-08 18:08:46 -0800173template<encoding::Tag TAG>
Junxiao Shi65f1a712014-11-20 14:59:36 -0700174size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800175FibEntry::wireEncode(EncodingImpl<TAG>& block) const
Junxiao Shi65f1a712014-11-20 14:59:36 -0700176{
177 size_t totalLength = 0;
178
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500179 for (const auto& nh : m_nextHopRecords | boost::adaptors::reversed) {
180 totalLength += nh.wireEncode(block);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700181 }
Junxiao Shi65f1a712014-11-20 14:59:36 -0700182 totalLength += m_prefix.wireEncode(block);
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500183
Junxiao Shi65f1a712014-11-20 14:59:36 -0700184 totalLength += block.prependVarNumber(totalLength);
185 totalLength += block.prependVarNumber(tlv::nfd::FibEntry);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700186 return totalLength;
187}
188
Davide Pesavento88a0d812017-08-19 21:31:42 -0400189NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(FibEntry);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700190
191const Block&
192FibEntry::wireEncode() const
193{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500194 if (m_wire.hasWire())
Junxiao Shi65f1a712014-11-20 14:59:36 -0700195 return m_wire;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700196
197 EncodingEstimator estimator;
198 size_t estimatedSize = wireEncode(estimator);
199
200 EncodingBuffer buffer(estimatedSize, 0);
201 wireEncode(buffer);
202
203 m_wire = buffer.block();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700204 return m_wire;
205}
206
207void
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500208FibEntry::wireDecode(const Block& block)
Junxiao Shi65f1a712014-11-20 14:59:36 -0700209{
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500210 if (block.type() != tlv::nfd::FibEntry) {
211 BOOST_THROW_EXCEPTION(Error("expecting FibEntry, but Block has type " + to_string(block.type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700212 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500213 m_wire = block;
Junxiao Shi65f1a712014-11-20 14:59:36 -0700214 m_wire.parse();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700215 Block::element_const_iterator val = m_wire.elements_begin();
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500216
Junxiao Shi65f1a712014-11-20 14:59:36 -0700217 if (val == m_wire.elements_end()) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500218 BOOST_THROW_EXCEPTION(Error("unexpected end of FibEntry"));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700219 }
220 else if (val->type() != tlv::Name) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500221 BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700222 }
223 m_prefix.wireDecode(*val);
224 ++val;
225
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500226 m_nextHopRecords.clear();
Junxiao Shi65f1a712014-11-20 14:59:36 -0700227 for (; val != m_wire.elements_end(); ++val) {
228 if (val->type() != tlv::nfd::NextHopRecord) {
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500229 BOOST_THROW_EXCEPTION(Error("expecting NextHopRecord, but Block has type " + to_string(val->type())));
Junxiao Shi65f1a712014-11-20 14:59:36 -0700230 }
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500231 m_nextHopRecords.emplace_back(*val);
Junxiao Shi65f1a712014-11-20 14:59:36 -0700232 }
233}
234
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500235bool
236operator==(const FibEntry& a, const FibEntry& b)
237{
238 const auto& aNextHops = a.getNextHopRecords();
239 const auto& bNextHops = b.getNextHopRecords();
240
241 if (a.getPrefix() != b.getPrefix() ||
242 aNextHops.size() != bNextHops.size())
243 return false;
244
245 std::vector<bool> matched(bNextHops.size(), false);
246 return std::all_of(aNextHops.begin(), aNextHops.end(),
247 [&] (const NextHopRecord& nh) {
248 for (size_t i = 0; i < bNextHops.size(); ++i) {
249 if (!matched[i] && bNextHops[i] == nh) {
250 matched[i] = true;
251 return true;
252 }
253 }
254 return false;
255 });
256}
257
258std::ostream&
259operator<<(std::ostream& os, const FibEntry& entry)
260{
261 os << "FibEntry(Prefix: " << entry.getPrefix() << ",\n"
262 << " NextHops: [";
263
Davide Pesaventocf415762017-02-25 23:46:47 -0500264 std::copy(entry.getNextHopRecords().begin(), entry.getNextHopRecords().end(),
265 make_ostream_joiner(os, ",\n "));
266
Davide Pesaventoa6f32ca2017-02-11 20:08:23 -0500267 os << "]\n";
268
269 return os << " )";
270}
271
Junxiao Shi65f1a712014-11-20 14:59:36 -0700272} // namespace nfd
273} // namespace ndn