blob: b41d33a79ea5c2320af655995f82974024256722 [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/*
3 * Copyright (c) 2014-2018, 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"
Junxiao Shi918e5d42017-02-25 03:58:21 +000027#include "find-face.hpp"
Junxiao Shi38f4ce92016-08-04 10:01:52 +000028#include "format-helpers.hpp"
29
30namespace nfd {
31namespace tools {
Junxiao Shi331ade72016-08-19 14:07:19 +000032namespace nfdc {
Junxiao Shi38f4ce92016-08-04 10:01:52 +000033
34void
Junxiao Shi918e5d42017-02-25 03:58:21 +000035RibModule::registerCommands(CommandParser& parser)
36{
Junxiao Shi1d62e622017-03-08 22:39:28 +000037 CommandDefinition defRouteList("route", "list");
38 defRouteList
39 .setTitle("print RIB routes")
40 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::NO, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000041 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO);
Junxiao Shi1d62e622017-03-08 22:39:28 +000042 parser.addCommand(defRouteList, &RibModule::list);
Davide Pesaventod2147442018-02-19 23:58:17 -050043 parser.addAlias("route", "list", "");
Junxiao Shi1d62e622017-03-08 22:39:28 +000044
45 CommandDefinition defRouteShow("route", "show");
46 defRouteShow
47 .setTitle("show routes toward a prefix")
48 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES);
49 parser.addCommand(defRouteShow, &RibModule::show);
50
Junxiao Shi918e5d42017-02-25 03:58:21 +000051 CommandDefinition defRouteAdd("route", "add");
52 defRouteAdd
53 .setTitle("add a route")
54 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
55 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000056 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO)
Junxiao Shi918e5d42017-02-25 03:58:21 +000057 .addArg("cost", ArgValueType::UNSIGNED, Required::NO, Positional::NO)
58 .addArg("no-inherit", ArgValueType::NONE, Required::NO, Positional::NO)
59 .addArg("capture", ArgValueType::NONE, Required::NO, Positional::NO)
60 .addArg("expires", ArgValueType::UNSIGNED, Required::NO, Positional::NO);
61 parser.addCommand(defRouteAdd, &RibModule::add);
Junxiao Shi084b7952017-02-26 22:00:53 +000062
63 CommandDefinition defRouteRemove("route", "remove");
64 defRouteRemove
65 .setTitle("remove a route")
66 .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
67 .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES)
Junxiao Shi8eda6822017-04-12 02:53:14 +000068 .addArg("origin", ArgValueType::ROUTE_ORIGIN, Required::NO, Positional::NO);
Junxiao Shi084b7952017-02-26 22:00:53 +000069 parser.addCommand(defRouteRemove, &RibModule::remove);
Junxiao Shi918e5d42017-02-25 03:58:21 +000070}
71
72void
Junxiao Shi1d62e622017-03-08 22:39:28 +000073RibModule::list(ExecuteContext& ctx)
74{
75 auto nexthopIt = ctx.args.find("nexthop");
76 std::set<uint64_t> nexthops;
Junxiao Shi8eda6822017-04-12 02:53:14 +000077 auto origin = ctx.args.getOptional<RouteOrigin>("origin");
Junxiao Shi1d62e622017-03-08 22:39:28 +000078
79 if (nexthopIt != ctx.args.end()) {
80 FindFace findFace(ctx);
81 FindFace::Code res = findFace.execute(nexthopIt->second, true);
82
83 ctx.exitCode = static_cast<int>(res);
84 switch (res) {
85 case FindFace::Code::OK:
86 break;
87 case FindFace::Code::ERROR:
88 case FindFace::Code::CANONIZE_ERROR:
89 case FindFace::Code::NOT_FOUND:
90 ctx.err << findFace.getErrorReason() << '\n';
91 return;
92 default:
93 BOOST_ASSERT_MSG(false, "unexpected FindFace result");
94 return;
95 }
96
97 nexthops = findFace.getFaceIds();
98 }
99
100 listRoutesImpl(ctx, [&] (const RibEntry& entry, const Route& route) {
101 return (nexthops.empty() || nexthops.count(route.getFaceId()) > 0) &&
102 (!origin || route.getOrigin() == *origin);
103 });
104}
105
106void
107RibModule::show(ExecuteContext& ctx)
108{
109 auto prefix = ctx.args.get<Name>("prefix");
110
111 listRoutesImpl(ctx, [&] (const RibEntry& entry, const Route& route) {
112 return entry.getName() == prefix;
113 });
114}
115
116void
117RibModule::listRoutesImpl(ExecuteContext& ctx, const RoutePredicate& filter)
118{
119 ctx.controller.fetch<ndn::nfd::RibDataset>(
120 [&] (const std::vector<RibEntry>& dataset) {
121 bool hasRoute = false;
122 for (const RibEntry& entry : dataset) {
123 for (const Route& route : entry.getRoutes()) {
124 if (filter(entry, route)) {
125 hasRoute = true;
126 formatRouteText(ctx.out, entry, route, true);
127 ctx.out << '\n';
128 }
129 }
130 }
131
132 if (!hasRoute) {
133 ctx.exitCode = 6;
134 ctx.err << "Route not found\n";
135 }
136 },
137 ctx.makeDatasetFailureHandler("RIB dataset"),
138 ctx.makeCommandOptions());
139
140 ctx.face.processEvents();
141}
142
143void
Junxiao Shi918e5d42017-02-25 03:58:21 +0000144RibModule::add(ExecuteContext& ctx)
145{
146 auto prefix = ctx.args.get<Name>("prefix");
Davide Pesavento8b663a92018-11-21 22:57:20 -0500147 auto nexthop = ctx.args.at("nexthop");
Junxiao Shi8eda6822017-04-12 02:53:14 +0000148 auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
Junxiao Shi918e5d42017-02-25 03:58:21 +0000149 auto cost = ctx.args.get<uint64_t>("cost", 0);
150 bool wantChildInherit = !ctx.args.get<bool>("no-inherit", false);
151 bool wantCapture = ctx.args.get<bool>("capture", false);
152 auto expiresMillis = ctx.args.getOptional<uint64_t>("expires");
153
154 FindFace findFace(ctx);
155 FindFace::Code res = findFace.execute(nexthop);
156
157 ctx.exitCode = static_cast<int>(res);
158 switch (res) {
159 case FindFace::Code::OK:
160 break;
161 case FindFace::Code::ERROR:
162 case FindFace::Code::CANONIZE_ERROR:
163 case FindFace::Code::NOT_FOUND:
164 ctx.err << findFace.getErrorReason() << '\n';
165 return;
166 case FindFace::Code::AMBIGUOUS:
167 ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
168 findFace.printDisambiguation(ctx.err, FindFace::DisambiguationStyle::LOCAL_URI);
169 ctx.err << '\n';
170 return;
171 default:
172 BOOST_ASSERT_MSG(false, "unexpected FindFace result");
173 return;
174 }
175
176 ControlParameters registerParams;
177 registerParams
178 .setName(prefix)
179 .setFaceId(findFace.getFaceId())
180 .setOrigin(origin)
181 .setCost(cost)
Ashlesh Gawandef7bf4092017-03-04 03:06:26 +0000182 .setFlags((wantChildInherit ? ndn::nfd::ROUTE_FLAG_CHILD_INHERIT : ndn::nfd::ROUTE_FLAGS_NONE) |
183 (wantCapture ? ndn::nfd::ROUTE_FLAG_CAPTURE : ndn::nfd::ROUTE_FLAGS_NONE));
Junxiao Shi918e5d42017-02-25 03:58:21 +0000184 if (expiresMillis) {
185 registerParams.setExpirationPeriod(time::milliseconds(*expiresMillis));
186 }
187
188 ctx.controller.start<ndn::nfd::RibRegisterCommand>(
189 registerParams,
190 [&] (const ControlParameters& resp) {
191 ctx.out << "route-add-accepted ";
192 text::ItemAttributes ia;
193 ctx.out << ia("prefix") << resp.getName()
194 << ia("nexthop") << resp.getFaceId()
Davide Pesavento22db5392017-04-14 00:56:43 -0400195 << ia("origin") << resp.getOrigin()
Junxiao Shi918e5d42017-02-25 03:58:21 +0000196 << ia("cost") << resp.getCost()
197 << ia("flags") << static_cast<ndn::nfd::RouteFlags>(resp.getFlags());
198 if (resp.hasExpirationPeriod()) {
Eric Newberryde332452018-01-30 11:45:32 -0700199 ctx.out << ia("expires") << text::formatDuration<time::milliseconds>(resp.getExpirationPeriod()) << "\n";
Junxiao Shi918e5d42017-02-25 03:58:21 +0000200 }
201 else {
202 ctx.out<< ia("expires") << "never\n";
203 }
204 },
205 ctx.makeCommandFailureHandler("adding route"),
206 ctx.makeCommandOptions());
207
208 ctx.face.processEvents();
209}
210
211void
Junxiao Shi084b7952017-02-26 22:00:53 +0000212RibModule::remove(ExecuteContext& ctx)
213{
214 auto prefix = ctx.args.get<Name>("prefix");
Davide Pesavento8b663a92018-11-21 22:57:20 -0500215 auto nexthop = ctx.args.at("nexthop");
Junxiao Shi8eda6822017-04-12 02:53:14 +0000216 auto origin = ctx.args.get<RouteOrigin>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
Junxiao Shi084b7952017-02-26 22:00:53 +0000217
218 FindFace findFace(ctx);
219 FindFace::Code res = findFace.execute(nexthop, true);
220
221 ctx.exitCode = static_cast<int>(res);
222 switch (res) {
223 case FindFace::Code::OK:
224 break;
225 case FindFace::Code::ERROR:
226 case FindFace::Code::CANONIZE_ERROR:
227 case FindFace::Code::NOT_FOUND:
228 ctx.err << findFace.getErrorReason() << '\n';
229 return;
230 default:
231 BOOST_ASSERT_MSG(false, "unexpected FindFace result");
232 return;
233 }
234
Junxiao Shi1d62e622017-03-08 22:39:28 +0000235 for (uint64_t faceId : findFace.getFaceIds()) {
Junxiao Shi084b7952017-02-26 22:00:53 +0000236 ControlParameters unregisterParams;
237 unregisterParams
238 .setName(prefix)
Junxiao Shi1d62e622017-03-08 22:39:28 +0000239 .setFaceId(faceId)
Junxiao Shi084b7952017-02-26 22:00:53 +0000240 .setOrigin(origin);
241
242 ctx.controller.start<ndn::nfd::RibUnregisterCommand>(
243 unregisterParams,
244 [&] (const ControlParameters& resp) {
245 ctx.out << "route-removed ";
246 text::ItemAttributes ia;
247 ctx.out << ia("prefix") << resp.getName()
248 << ia("nexthop") << resp.getFaceId()
Davide Pesavento22db5392017-04-14 00:56:43 -0400249 << ia("origin") << resp.getOrigin()
Junxiao Shi084b7952017-02-26 22:00:53 +0000250 << '\n';
251 },
252 ctx.makeCommandFailureHandler("removing route"),
253 ctx.makeCommandOptions());
254 }
255
256 ctx.face.processEvents();
257}
258
259void
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000260RibModule::fetchStatus(Controller& controller,
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400261 const std::function<void()>& onSuccess,
Junxiao Shi29b41282016-08-22 03:47:02 +0000262 const Controller::DatasetFailCallback& onFailure,
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000263 const CommandOptions& options)
264{
265 controller.fetch<ndn::nfd::RibDataset>(
266 [this, onSuccess] (const std::vector<RibEntry>& result) {
267 m_status = result;
268 onSuccess();
269 },
270 onFailure, options);
271}
272
273void
274RibModule::formatStatusXml(std::ostream& os) const
275{
276 os << "<rib>";
277 for (const RibEntry& item : m_status) {
278 this->formatItemXml(os, item);
279 }
280 os << "</rib>";
281}
282
283void
284RibModule::formatItemXml(std::ostream& os, const RibEntry& item) const
285{
286 os << "<ribEntry>";
287
288 os << "<prefix>" << xml::Text{item.getName().toUri()} << "</prefix>";
289
290 os << "<routes>";
291 for (const Route& route : item.getRoutes()) {
292 os << "<route>"
293 << "<faceId>" << route.getFaceId() << "</faceId>"
Davide Pesavento22db5392017-04-14 00:56:43 -0400294 << "<origin>" << route.getOrigin() << "</origin>"
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000295 << "<cost>" << route.getCost() << "</cost>";
296 if (route.getFlags() == ndn::nfd::ROUTE_FLAGS_NONE) {
297 os << "<flags/>";
298 }
299 else {
300 os << "<flags>";
301 if (route.isChildInherit()) {
302 os << "<childInherit/>";
303 }
304 if (route.isRibCapture()) {
305 os << "<ribCapture/>";
306 }
307 os << "</flags>";
308 }
Davide Pesavento26cbdbd2017-02-19 21:37:43 -0500309 if (route.hasExpirationPeriod()) {
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000310 os << "<expirationPeriod>"
Eric Newberryde332452018-01-30 11:45:32 -0700311 << xml::formatDuration(time::duration_cast<time::seconds>(route.getExpirationPeriod()))
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000312 << "</expirationPeriod>";
313 }
314 os << "</route>";
315 }
316 os << "</routes>";
317
318 os << "</ribEntry>";
319}
320
321void
322RibModule::formatStatusText(std::ostream& os) const
323{
324 os << "RIB:\n";
325 for (const RibEntry& item : m_status) {
Junxiao Shi1d62e622017-03-08 22:39:28 +0000326 os << " ";
327 formatEntryText(os, item);
328 os << '\n';
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000329 }
330}
331
332void
Junxiao Shi1d62e622017-03-08 22:39:28 +0000333RibModule::formatEntryText(std::ostream& os, const RibEntry& entry)
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000334{
Junxiao Shi1d62e622017-03-08 22:39:28 +0000335 os << entry.getName() << " routes={";
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000336
337 text::Separator sep(", ");
Junxiao Shi1d62e622017-03-08 22:39:28 +0000338 for (const Route& route : entry.getRoutes()) {
339 os << sep;
340 formatRouteText(os, entry, route, false);
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000341 }
342
343 os << "}";
Junxiao Shi1d62e622017-03-08 22:39:28 +0000344}
345
346void
347RibModule::formatRouteText(std::ostream& os, const RibEntry& entry, const Route& route,
348 bool includePrefix)
349{
350 text::ItemAttributes ia;
351
352 if (includePrefix) {
353 os << ia("prefix") << entry.getName();
354 }
355 os << ia("nexthop") << route.getFaceId();
Davide Pesavento22db5392017-04-14 00:56:43 -0400356 os << ia("origin") << route.getOrigin();
Junxiao Shi1d62e622017-03-08 22:39:28 +0000357 os << ia("cost") << route.getCost();
358 os << ia("flags") << static_cast<ndn::nfd::RouteFlags>(route.getFlags());
Junxiao Shi1d62e622017-03-08 22:39:28 +0000359 if (route.hasExpirationPeriod()) {
Eric Newberryde332452018-01-30 11:45:32 -0700360 os << ia("expires") << text::formatDuration<time::seconds>(route.getExpirationPeriod());
Junxiao Shi1d62e622017-03-08 22:39:28 +0000361 }
362 else {
363 os << ia("expires") << "never";
364 }
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000365}
366
Junxiao Shi331ade72016-08-19 14:07:19 +0000367} // namespace nfdc
Junxiao Shi38f4ce92016-08-04 10:01:52 +0000368} // namespace tools
369} // namespace nfd