rib-module.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2020, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "rib-module.hpp"
27 #include "canonizer.hpp"
28 #include "face-module.hpp"
29 #include "find-face.hpp"
30 #include "format-helpers.hpp"
31 
32 namespace nfd {
33 namespace tools {
34 namespace nfdc {
35 
36 void
38 {
39  CommandDefinition defRouteList("route", "list");
40  defRouteList
41  .setTitle("print RIB routes")
44  parser.addCommand(defRouteList, &RibModule::list);
45  parser.addAlias("route", "list", "");
46 
47  CommandDefinition defRouteShow("route", "show");
48  defRouteShow
49  .setTitle("show routes toward a prefix")
51  parser.addCommand(defRouteShow, &RibModule::show);
52 
53  CommandDefinition defRouteAdd("route", "add");
54  defRouteAdd
55  .setTitle("add a route")
63  parser.addCommand(defRouteAdd, &RibModule::add);
64 
65  CommandDefinition defRouteRemove("route", "remove");
66  defRouteRemove
67  .setTitle("remove a route")
71  parser.addCommand(defRouteRemove, &RibModule::remove);
72 }
73 
74 void
76 {
77  auto nexthopIt = ctx.args.find("nexthop");
78  std::set<uint64_t> nexthops;
79  auto origin = ctx.args.getOptional<RouteOrigin>("origin");
80 
81  if (nexthopIt != ctx.args.end()) {
82  FindFace findFace(ctx);
83  FindFace::Code res = findFace.execute(nexthopIt->second, true);
84 
85  ctx.exitCode = static_cast<int>(res);
86  switch (res) {
87  case FindFace::Code::OK:
88  break;
92  ctx.err << findFace.getErrorReason() << '\n';
93  return;
94  default:
95  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
96  return;
97  }
98 
99  nexthops = findFace.getFaceIds();
100  }
101 
102  listRoutesImpl(ctx, [&] (const RibEntry& entry, const Route& route) {
103  return (nexthops.empty() || nexthops.count(route.getFaceId()) > 0) &&
104  (!origin || route.getOrigin() == *origin);
105  });
106 }
107 
108 void
110 {
111  auto prefix = ctx.args.get<Name>("prefix");
112 
113  listRoutesImpl(ctx, [&] (const RibEntry& entry, const Route& route) {
114  return entry.getName() == prefix;
115  });
116 }
117 
118 void
119 RibModule::listRoutesImpl(ExecuteContext& ctx, const RoutePredicate& filter)
120 {
121  ctx.controller.fetch<ndn::nfd::RibDataset>(
122  [&] (const std::vector<RibEntry>& dataset) {
123  bool hasRoute = false;
124  for (const RibEntry& entry : dataset) {
125  for (const Route& route : entry.getRoutes()) {
126  if (filter(entry, route)) {
127  hasRoute = true;
128  formatRouteText(ctx.out, entry, route, true);
129  ctx.out << '\n';
130  }
131  }
132  }
133 
134  if (!hasRoute) {
135  ctx.exitCode = 6;
136  ctx.err << "Route not found\n";
137  }
138  },
139  ctx.makeDatasetFailureHandler("RIB dataset"),
140  ctx.makeCommandOptions());
141 
142  ctx.face.processEvents();
143 }
144 
145 void
147 {
148  auto prefix = ctx.args.get<Name>("prefix");
149  auto nexthop = ctx.args.at("nexthop");
150  auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
151  auto cost = ctx.args.get<uint64_t>("cost", 0);
152  bool wantChildInherit = !ctx.args.get<bool>("no-inherit", false);
153  bool wantCapture = ctx.args.get<bool>("capture", false);
154  auto expiresMillis = ctx.args.getOptional<uint64_t>("expires");
155 
156  auto registerRoute = [&] (uint64_t faceId) {
157  ControlParameters registerParams;
158  registerParams
159  .setName(prefix)
160  .setFaceId(faceId)
161  .setOrigin(origin)
162  .setCost(cost)
163  .setFlags((wantChildInherit ? ndn::nfd::ROUTE_FLAG_CHILD_INHERIT : ndn::nfd::ROUTE_FLAGS_NONE) |
164  (wantCapture ? ndn::nfd::ROUTE_FLAG_CAPTURE : ndn::nfd::ROUTE_FLAGS_NONE));
165  if (expiresMillis) {
166  registerParams.setExpirationPeriod(time::milliseconds(*expiresMillis));
167  }
168 
169  ctx.controller.start<ndn::nfd::RibRegisterCommand>(
170  registerParams,
171  [&] (const ControlParameters& resp) {
172  ctx.exitCode = static_cast<int>(FindFace::Code::OK);
173  ctx.out << "route-add-accepted ";
175  ctx.out << ia("prefix") << resp.getName()
176  << ia("nexthop") << resp.getFaceId()
177  << ia("origin") << resp.getOrigin()
178  << ia("cost") << resp.getCost()
179  << ia("flags") << static_cast<ndn::nfd::RouteFlags>(resp.getFlags());
180  if (resp.hasExpirationPeriod()) {
181  ctx.out << ia("expires") << text::formatDuration<time::milliseconds>(resp.getExpirationPeriod()) << "\n";
182  }
183  else {
184  ctx.out<< ia("expires") << "never\n";
185  }
186  },
187  ctx.makeCommandFailureHandler("adding route"),
188  ctx.makeCommandOptions());
189  };
190 
191  auto handleFaceNotFound = [&] {
192  const FaceUri* faceUri = ndn::any_cast<FaceUri>(&nexthop);
193  if (faceUri == nullptr) {
194  ctx.err << "Face not found\n";
195  return;
196  }
197 
198  if (faceUri->getScheme() == "ether") {
199  // Unicast Ethernet faces require a LocalUri, which hasn't been provided
200  // Multicast Ethernet faces cannot be created via management (already exist on each interface)
201  ctx.err << "Unable to implicitly create Ethernet faces\n";
202  ctx.err << "Please create the face with 'nfdc face create' before adding the route\n";
203  return;
204  }
205 
206  optional<FaceUri> canonized;
207  std::string error;
208  std::tie(canonized, error) = canonize(ctx, *faceUri);
209  if (!canonized) {
210  // Canonization failed
211  auto canonizationError = canonizeErrorHelper(*faceUri, error);
212  ctx.exitCode = static_cast<int>(canonizationError.first);
213  ctx.err << canonizationError.second << '\n';
214  return;
215  }
216 
217  ControlParameters faceCreateParams;
218  faceCreateParams.setUri(canonized->toString());
219 
220  ctx.controller.start<ndn::nfd::FaceCreateCommand>(
221  faceCreateParams,
222  [&] (const ControlParameters& resp) {
223  FaceModule::printSuccess(ctx.out, "face-created", resp);
224  registerRoute(resp.getFaceId());
225  },
226  ctx.makeCommandFailureHandler("implicitly creating face"),
227  ctx.makeCommandOptions());
228  };
229 
230  FindFace findFace(ctx);
231  FindFace::Code res = findFace.execute(nexthop);
232 
233  ctx.exitCode = static_cast<int>(res);
234  switch (res) {
235  case FindFace::Code::OK:
236  registerRoute(findFace.getFaceId());
237  break;
240  ctx.err << findFace.getErrorReason() << '\n';
241  return;
243  // Attempt to create face if it doesn't exist
244  handleFaceNotFound();
245  break;
247  ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
249  ctx.err << '\n';
250  return;
251  default:
252  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
253  return;
254  }
255 
256  ctx.face.processEvents();
257 }
258 
259 void
261 {
262  auto prefix = ctx.args.get<Name>("prefix");
263  auto nexthop = ctx.args.at("nexthop");
264  auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
265 
266  FindFace findFace(ctx);
267  FindFace::Code res = findFace.execute(nexthop, true);
268 
269  ctx.exitCode = static_cast<int>(res);
270  switch (res) {
271  case FindFace::Code::OK:
272  break;
276  ctx.err << findFace.getErrorReason() << '\n';
277  return;
278  default:
279  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
280  return;
281  }
282 
283  for (uint64_t faceId : findFace.getFaceIds()) {
284  ControlParameters unregisterParams;
285  unregisterParams
286  .setName(prefix)
287  .setFaceId(faceId)
288  .setOrigin(origin);
289 
290  ctx.controller.start<ndn::nfd::RibUnregisterCommand>(
291  unregisterParams,
292  [&] (const ControlParameters& resp) {
293  ctx.out << "route-removed ";
295  ctx.out << ia("prefix") << resp.getName()
296  << ia("nexthop") << resp.getFaceId()
297  << ia("origin") << resp.getOrigin()
298  << '\n';
299  },
300  ctx.makeCommandFailureHandler("removing route"),
301  ctx.makeCommandOptions());
302  }
303 
304  ctx.face.processEvents();
305 }
306 
307 void
308 RibModule::fetchStatus(Controller& controller,
309  const std::function<void()>& onSuccess,
310  const Controller::DatasetFailCallback& onFailure,
311  const CommandOptions& options)
312 {
313  controller.fetch<ndn::nfd::RibDataset>(
314  [this, onSuccess] (const std::vector<RibEntry>& result) {
315  m_status = result;
316  onSuccess();
317  },
318  onFailure, options);
319 }
320 
321 void
322 RibModule::formatStatusXml(std::ostream& os) const
323 {
324  os << "<rib>";
325  for (const RibEntry& item : m_status) {
326  this->formatItemXml(os, item);
327  }
328  os << "</rib>";
329 }
330 
331 void
332 RibModule::formatItemXml(std::ostream& os, const RibEntry& item) const
333 {
334  os << "<ribEntry>";
335 
336  os << "<prefix>" << xml::Text{item.getName().toUri()} << "</prefix>";
337 
338  os << "<routes>";
339  for (const Route& route : item.getRoutes()) {
340  os << "<route>"
341  << "<faceId>" << route.getFaceId() << "</faceId>"
342  << "<origin>" << route.getOrigin() << "</origin>"
343  << "<cost>" << route.getCost() << "</cost>";
344  if (route.getFlags() == ndn::nfd::ROUTE_FLAGS_NONE) {
345  os << "<flags/>";
346  }
347  else {
348  os << "<flags>";
349  if (route.isChildInherit()) {
350  os << "<childInherit/>";
351  }
352  if (route.isRibCapture()) {
353  os << "<ribCapture/>";
354  }
355  os << "</flags>";
356  }
357  if (route.hasExpirationPeriod()) {
358  os << "<expirationPeriod>"
359  << xml::formatDuration(time::duration_cast<time::seconds>(route.getExpirationPeriod()))
360  << "</expirationPeriod>";
361  }
362  os << "</route>";
363  }
364  os << "</routes>";
365 
366  os << "</ribEntry>";
367 }
368 
369 void
370 RibModule::formatStatusText(std::ostream& os) const
371 {
372  os << "RIB:\n";
373  for (const RibEntry& item : m_status) {
374  os << " ";
375  formatEntryText(os, item);
376  os << '\n';
377  }
378 }
379 
380 void
381 RibModule::formatEntryText(std::ostream& os, const RibEntry& entry)
382 {
383  os << entry.getName() << " routes={";
384 
385  text::Separator sep(", ");
386  for (const Route& route : entry.getRoutes()) {
387  os << sep;
388  formatRouteText(os, entry, route, false);
389  }
390 
391  os << "}";
392 }
393 
394 void
395 RibModule::formatRouteText(std::ostream& os, const RibEntry& entry, const Route& route,
396  bool includePrefix)
397 {
399 
400  if (includePrefix) {
401  os << ia("prefix") << entry.getName();
402  }
403  os << ia("nexthop") << route.getFaceId();
404  os << ia("origin") << route.getOrigin();
405  os << ia("cost") << route.getCost();
406  os << ia("flags") << static_cast<ndn::nfd::RouteFlags>(route.getFlags());
407  if (route.hasExpirationPeriod()) {
408  os << ia("expires") << text::formatDuration<time::seconds>(route.getExpirationPeriod());
409  }
410  else {
411  os << ia("expires") << "never";
412  }
413 }
414 
415 } // namespace nfdc
416 } // namespace tools
417 } // namespace nfd
const CommandArguments & args
std::string formatDuration(time::nanoseconds d)
boolean argument without value
Controller::CommandFailCallback makeCommandFailureHandler(const std::string &commandName)
declares semantics of a command
std::ostream & out
output stream
context for command execution
static void list(ExecuteContext &ctx)
the &#39;route list&#39; command
Definition: rib-module.cpp:75
void formatStatusText(std::ostream &os) const override
format collected status as text
Definition: rib-module.cpp:370
found exactly one face, or found multiple faces when allowMulti is true
error during FaceUri canonization
ndn::nfd::CommandOptions makeCommandOptions() const
Controller::DatasetFailCallback makeDatasetFailureHandler(const std::string &datasetName)
CommandDefinition & setTitle(const std::string &title)
set one-line description
optional< T > getOptional(const std::string &key) const
found multiple faces and allowMulti is false
static void remove(ExecuteContext &ctx)
the &#39;route remove&#39; command
Definition: rib-module.cpp:260
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
procedure to find a face
Definition: find-face.hpp:40
void formatStatusXml(std::ostream &os) const override
format collected status as XML
Definition: rib-module.cpp:322
Code execute(const FaceUri &faceUri, bool allowMulti=false)
find face by FaceUri
Definition: find-face.cpp:44
uint64_t getFaceId() const
Definition: find-face.hpp:107
CommandDefinition & addArg(const std::string &name, ArgValueType valueType, Required isRequired=Required::NO, Positional allowPositional=Positional::NO, const std::string &metavar="")
declare an argument
std::pair< FindFace::Code, std::string > canonizeErrorHelper(const FaceUri &uri, const std::string &error, const std::string &field)
helper to generate exit code and error message for face canonization failures
Definition: canonizer.cpp:47
print attributes of an item
std::pair< optional< FaceUri >, std::string > canonize(ExecuteContext &ctx, const FaceUri &uri)
canonize FaceUri
Definition: canonizer.cpp:33
argument is required
std::ostream & err
error stream
CommandParser & addCommand(const CommandDefinition &def, const ExecuteCommand &execute, std::underlying_type< AvailableIn >::type modes=AVAILABLE_IN_ALL)
add an available command
void fetchStatus(Controller &controller, const std::function< void()> &onSuccess, const Controller::DatasetFailCallback &onFailure, const CommandOptions &options) override
collect status from NFD
Definition: rib-module.cpp:308
const std::string & getErrorReason() const
Definition: find-face.hpp:113
static void printSuccess(std::ostream &os, const std::string &actionSummary, const ControlParameters &resp)
print face action success message to specified ostream
argument is optional
static void add(ExecuteContext &ctx)
the &#39;route add&#39; command
Definition: rib-module.cpp:146
std::set< uint64_t > getFaceIds() const
Definition: find-face.cpp:156
T get(const std::string &key, const T &defaultValue=T()) const
CommandParser & addAlias(const std::string &noun, const std::string &verb, const std::string &verb2)
add an alias "noun verb2" to existing command "noun verb"
print different string on first and subsequent usage
static void registerCommands(CommandParser &parser)
register &#39;route list&#39;, &#39;route show&#39;, &#39;route add&#39;, &#39;route remove&#39; commands
Definition: rib-module.cpp:37
static void show(ExecuteContext &ctx)
the &#39;route show&#39; command
Definition: rib-module.cpp:109
void printDisambiguation(std::ostream &os, DisambiguationStyle style) const
print results for disambiguation
Definition: find-face.cpp:173