blob: 544da6e42f2fb93fd152a7c24a84612c966c6830 [file] [log] [blame]
Junxiao Shi38f4ce92016-08-04 10:01:52 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberryde332452018-01-30 11:45:32 -07002/*
Eric Newberryd656aff2020-04-03 00:30:38 -07003 * Copyright (c) 2014-2020, Regents of the University of California,
Junxiao Shi38f4ce92016-08-04 10:01:52 +00004 * 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"
Eric Newberryd656aff2020-04-03 00:30:38 -070027#include "canonizer.hpp"
28#include "face-module.hpp"
Junxiao Shi918e5d42017-02-25 03:58:21 +000029#include "find-face.hpp"
Junxiao Shi38f4ce92016-08-04 10:01:52 +000030#include "format-helpers.hpp"
31
32namespace nfd {
33namespace tools {
Junxiao Shi331ade72016-08-19 14:07:19 +000034namespace nfdc {
Junxiao Shi38f4ce92016-08-04 10:01:52 +000035
36void
Junxiao Shi918e5d42017-02-25 03:58:21 +000037RibModule::registerCommands(CommandParser& parser)
38{
Junxiao Shi1d62e622017-03-08 22:39:28 +000039 CommandDefinition defRouteList("route", "list");
40 defRouteList
41 .setTitle("print RIB routes")
42 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::NO, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000043 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO);
Junxiao Shi1d62e622017-03-08 22:39:28 +000044 parser.addCommand(defRouteList, &RibModule::list);
Davide Pesaventod2147442018-02-19 23:58:17 -050045 parser.addAlias("route", "list", "");
Junxiao Shi1d62e622017-03-08 22:39:28 +000046
47 CommandDefinition defRouteShow("route", "show");
48 defRouteShow
49 .setTitle("show routes toward a prefix")
50 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES);
51 parser.addCommand(defRouteShow, &RibModule::show);
52
Junxiao Shi918e5d42017-02-25 03:58:21 +000053 CommandDefinition defRouteAdd("route", "add");
54 defRouteAdd
55 .setTitle("add a route")
56 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
57 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000058 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO)
Junxiao Shi918e5d42017-02-25 03:58:21 +000059 .addArg("cost", ArgValueType::UNSIGNED, Required::NO, Positional::NO)
60 .addArg("no-inherit", ArgValueType::NONE, Required::NO, Positional::NO)
61 .addArg("capture", ArgValueType::NONE, Required::NO, Positional::NO)
62 .addArg("expires", ArgValueType::UNSIGNED, Required::NO, Positional::NO);
63 parser.addCommand(defRouteAdd, &RibModule::add);
Junxiao Shi084b7952017-02-26 22:00:53 +000064
65 CommandDefinition defRouteRemove("route", "remove");
66 defRouteRemove
67 .setTitle("remove a route")
68 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
69 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000070 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO);
Junxiao Shi084b7952017-02-26 22:00:53 +000071 parser.addCommand(defRouteRemove, &RibModule::remove);
Junxiao Shi918e5d42017-02-25 03:58:21 +000072}
73
74void
Junxiao Shi1d62e622017-03-08 22:39:28 +000075RibModule::list(ExecuteContext& ctx)
76{
77 auto nexthopIt = ctx.args.find("nexthop");
78 std::set<uint64_t> nexthops;
Junxiao Shi8eda6822017-04-12 02:53:14 +000079 auto origin = ctx.args.getOptional<RouteOrigin>("origin");
Junxiao Shi1d62e622017-03-08 22:39:28 +000080
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;
89 case FindFace::Code::ERROR:
90 case FindFace::Code::CANONIZE_ERROR:
91 case FindFace::Code::NOT_FOUND:
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
108void
109RibModule::show(ExecuteContext& ctx)
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
118void
119RibModule::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
145void
Junxiao Shi918e5d42017-02-25 03:58:21 +0000146RibModule::add(ExecuteContext& ctx)
147{
148 auto prefix = ctx.args.get<Name>("prefix");
Davide Pesavento8b663a92018-11-21 22:57:20 -0500149 auto nexthop = ctx.args.at("nexthop");
Junxiao Shi8eda6822017-04-12 02:53:14 +0000150 auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
Junxiao Shi918e5d42017-02-25 03:58:21 +0000151 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
Eric Newberryd656aff2020-04-03 00:30:38 -0700156 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 ";
174 text::ItemAttributes ia;
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
Junxiao Shi918e5d42017-02-25 03:58:21 +0000230 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:
Eric Newberryd656aff2020-04-03 00:30:38 -0700236 registerRoute(findFace.getFaceId());
Junxiao Shi918e5d42017-02-25 03:58:21 +0000237 break;
238 case FindFace::Code::ERROR:
239 case FindFace::Code::CANONIZE_ERROR:
Junxiao Shi918e5d42017-02-25 03:58:21 +0000240 ctx.err << findFace.getErrorReason() << '\n';
241 return;
Eric Newberryd656aff2020-04-03 00:30:38 -0700242 case FindFace::Code::NOT_FOUND:
243 // Attempt to create face if it doesn't exist
244 handleFaceNotFound();
245 break;
Junxiao Shi918e5d42017-02-25 03:58:21 +0000246 case FindFace::Code::AMBIGUOUS:
247 ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
248 findFace.printDisambiguation(ctx.err, FindFace::DisambiguationStyle::LOCAL_URI);
249 ctx.err << '\n';
250 return;
251 default:
252 BOOST_ASSERT_MSG(false, "unexpected FindFace result");
253 return;
254 }
255
Junxiao Shi918e5d42017-02-25 03:58:21 +0000256 ctx.face.processEvents();
257}
258
259void
Junxiao Shi084b7952017-02-26 22:00:53 +0000260RibModule::remove(ExecuteContext& ctx)
261{
262 auto prefix = ctx.args.get<Name>("prefix");
Davide Pesavento8b663a92018-11-21 22:57:20 -0500263 auto nexthop = ctx.args.at("nexthop");
Junxiao Shi8eda6822017-04-12 02:53:14 +0000264 auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
Junxiao Shi084b7952017-02-26 22:00:53 +0000265
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;
273 case FindFace::Code::ERROR:
274 case FindFace::Code::CANONIZE_ERROR:
275 case FindFace::Code::NOT_FOUND:
276 ctx.err << findFace.getErrorReason() << '\n';
277 return;
278 default:
279 BOOST_ASSERT_MSG(false, "unexpected FindFace result");
280 return;
281 }
282
Junxiao Shi1d62e622017-03-08 22:39:28 +0000283 for (uint64_t faceId : findFace.getFaceIds()) {
Junxiao Shi084b7952017-02-26 22:00:53 +0000284 ControlParameters unregisterParams;
285 unregisterParams
286 .setName(prefix)
Junxiao Shi1d62e622017-03-08 22:39:28 +0000287 .setFaceId(faceId)
Junxiao Shi084b7952017-02-26 22:00:53 +0000288 .setOrigin(origin);
289
290 ctx.controller.start<ndn::nfd::RibUnregisterCommand>(
291 unregisterParams,
292 [&] (const ControlParameters& resp) {
293 ctx.out << "route-removed ";
294 text::ItemAttributes ia;
295 ctx.out << ia("prefix") << resp.getName()
296 << ia("nexthop") << resp.getFaceId()
Davide Pesavento22db5392017-04-14 00:56:43 -0400297 << ia("origin") << resp.getOrigin()
Junxiao Shi084b7952017-02-26 22:00:53 +0000298 << '\n';
299 },
300 ctx.makeCommandFailureHandler("removing route"),
301 ctx.makeCommandOptions());
302 }
303
304 ctx.face.processEvents();
305}
306
307void
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000308RibModule::fetchStatus(Controller& controller,
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400309 const std::function<void()>& onSuccess,
Junxiao Shi29b41282016-08-22 03:47:02 +0000310 const Controller::DatasetFailCallback& onFailure,
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000311 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
321void
322RibModule::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
331void
332RibModule::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>"
Davide Pesavento22db5392017-04-14 00:56:43 -0400342 << "<origin>" << route.getOrigin() << "</origin>"
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000343 << "<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 }
Davide Pesavento26cbdbd2017-02-19 21:37:43 -0500357 if (route.hasExpirationPeriod()) {
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000358 os << "<expirationPeriod>"
Eric Newberryde332452018-01-30 11:45:32 -0700359 << xml::formatDuration(time::duration_cast<time::seconds>(route.getExpirationPeriod()))
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000360 << "</expirationPeriod>";
361 }
362 os << "</route>";
363 }
364 os << "</routes>";
365
366 os << "</ribEntry>";
367}
368
369void
370RibModule::formatStatusText(std::ostream& os) const
371{
372 os << "RIB:\n";
373 for (const RibEntry& item : m_status) {
Junxiao Shi1d62e622017-03-08 22:39:28 +0000374 os << " ";
375 formatEntryText(os, item);
376 os << '\n';
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000377 }
378}
379
380void
Junxiao Shi1d62e622017-03-08 22:39:28 +0000381RibModule::formatEntryText(std::ostream& os, const RibEntry& entry)
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000382{
Junxiao Shi1d62e622017-03-08 22:39:28 +0000383 os << entry.getName() << " routes={";
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000384
385 text::Separator sep(", ");
Junxiao Shi1d62e622017-03-08 22:39:28 +0000386 for (const Route& route : entry.getRoutes()) {
387 os << sep;
388 formatRouteText(os, entry, route, false);
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000389 }
390
391 os << "}";
Junxiao Shi1d62e622017-03-08 22:39:28 +0000392}
393
394void
395RibModule::formatRouteText(std::ostream& os, const RibEntry& entry, const Route& route,
396 bool includePrefix)
397{
398 text::ItemAttributes ia;
399
400 if (includePrefix) {
401 os << ia("prefix") << entry.getName();
402 }
403 os << ia("nexthop") << route.getFaceId();
Davide Pesavento22db5392017-04-14 00:56:43 -0400404 os << ia("origin") << route.getOrigin();
Junxiao Shi1d62e622017-03-08 22:39:28 +0000405 os << ia("cost") << route.getCost();
406 os << ia("flags") << static_cast<ndn::nfd::RouteFlags>(route.getFlags());
Junxiao Shi1d62e622017-03-08 22:39:28 +0000407 if (route.hasExpirationPeriod()) {
Eric Newberryde332452018-01-30 11:45:32 -0700408 os << ia("expires") << text::formatDuration<time::seconds>(route.getExpirationPeriod());
Junxiao Shi1d62e622017-03-08 22:39:28 +0000409 }
410 else {
411 os << ia("expires") << "never";
412 }
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000413}
414
Junxiao Shi331ade72016-08-19 14:07:19 +0000415} // namespace nfdc
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000416} // namespace tools
417} // namespace nfd