face-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2018, 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 "face-manager.hpp"
29 #include "fw/face-table.hpp"
30 
31 #include <boost/logic/tribool.hpp>
32 
33 #include <ndn-cxx/lp/tags.hpp>
34 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
35 
36 namespace nfd {
37 
38 NFD_LOG_INIT("FaceManager");
39 
40 FaceManager::FaceManager(FaceSystem& faceSystem,
41  Dispatcher& dispatcher, CommandAuthenticator& authenticator)
42  : NfdManagerBase(dispatcher, authenticator, "faces")
43  , m_faceSystem(faceSystem)
44  , m_faceTable(faceSystem.getFaceTable())
45 {
46  // register handlers for ControlCommand
47  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
48  bind(&FaceManager::createFace, this, _2, _3, _4, _5));
49 
50  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
51  bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
52 
53  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
54  bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
55 
56  // register handlers for StatusDataset
57  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
58  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
59  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
60 
61  // register notification stream
62  m_postNotification = registerNotificationStream("events");
63  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
64  connectFaceStateChangeSignal(face);
65  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
66  });
67  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
68  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
69  });
70 }
71 
72 void
74 {
75  m_faceSystem.setConfigFile(configFile);
76 }
77 
78 void
79 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
80  const ControlParameters& parameters,
81  const ndn::mgmt::CommandContinuation& done)
82 {
83  FaceUri remoteUri;
84  if (!remoteUri.parse(parameters.getUri())) {
85  NFD_LOG_TRACE("failed to parse remote URI: " << parameters.getUri());
86  done(ControlResponse(400, "Malformed command"));
87  return;
88  }
89 
90  if (!remoteUri.isCanonical()) {
91  NFD_LOG_TRACE("received non-canonical remote URI: " << remoteUri.toString());
92  done(ControlResponse(400, "Non-canonical remote URI"));
93  return;
94  }
95 
96  ndn::optional<FaceUri> localUri;
97  if (parameters.hasLocalUri()) {
98  localUri = FaceUri{};
99 
100  if (!localUri->parse(parameters.getLocalUri())) {
101  NFD_LOG_TRACE("failed to parse local URI: " << parameters.getLocalUri());
102  done(ControlResponse(400, "Malformed command"));
103  return;
104  }
105 
106  if (!localUri->isCanonical()) {
107  NFD_LOG_TRACE("received non-canonical local URI: " << localUri->toString());
108  done(ControlResponse(400, "Non-canonical local URI"));
109  return;
110  }
111  }
112 
113  face::ProtocolFactory* factory = m_faceSystem.getFactoryByScheme(remoteUri.getScheme());
114  if (factory == nullptr) {
115  NFD_LOG_TRACE("received create request for unsupported protocol: " << remoteUri.getScheme());
116  done(ControlResponse(406, "Unsupported protocol"));
117  return;
118  }
119 
120  face::FaceParams faceParams;
121  faceParams.persistency = parameters.getFacePersistency();
122  if (parameters.hasBaseCongestionMarkingInterval()) {
123  faceParams.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
124  }
125  if (parameters.hasDefaultCongestionThreshold()) {
126  faceParams.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
127  }
128  faceParams.wantLocalFields = parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
129  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
130  faceParams.wantLpReliability = parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED) &&
131  parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
132  if (parameters.hasFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
133  faceParams.wantCongestionMarking = parameters.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED);
134  }
135  try {
136  factory->createFace({remoteUri, localUri, faceParams},
137  bind(&FaceManager::afterCreateFaceSuccess, this, parameters, _1, done),
138  bind(&FaceManager::afterCreateFaceFailure, this, _1, _2, done));
139  }
140  catch (const std::runtime_error& error) {
141  NFD_LOG_ERROR("Face creation failed: " << error.what());
142  done(ControlResponse(500, "Face creation failed due to internal error"));
143  return;
144  }
145  catch (const std::logic_error& error) {
146  NFD_LOG_ERROR("Face creation failed: " << error.what());
147  done(ControlResponse(500, "Face creation failed due to internal error"));
148  return;
149  }
150 }
151 
152 void
153 FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
154  const shared_ptr<Face>& face,
155  const ndn::mgmt::CommandContinuation& done)
156 {
157  if (face->getId() != face::INVALID_FACEID) {// Face already exists
158  NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
159 
160  ControlParameters response = collectFaceProperties(*face, true);
161  done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
162  return;
163  }
164 
165  // If scope non-local and flags set to enable local fields, request shouldn't
166  // have made it this far
167  BOOST_ASSERT(face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL ||
168  !parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) ||
169  (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
170  !parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)));
171 
172  m_faceTable.add(face);
173 
174  ControlParameters response = collectFaceProperties(*face, true);
175  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
176 }
177 
178 void
179 FaceManager::afterCreateFaceFailure(uint32_t status,
180  const std::string& reason,
181  const ndn::mgmt::CommandContinuation& done)
182 {
183  NFD_LOG_DEBUG("Face creation failed: " << reason);
184 
185  done(ControlResponse(status, reason));
186 }
187 
188 void
189 FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
190  const ControlParameters& parameters,
191  const ndn::mgmt::CommandContinuation& done)
192 {
193  FaceId faceId = parameters.getFaceId();
194  if (faceId == 0) {
195  // Self-updating
196  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
197  if (incomingFaceIdTag == nullptr) {
198  NFD_LOG_TRACE("unable to determine face for self-update");
199  done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
200  return;
201  }
202  faceId = *incomingFaceIdTag;
203  }
204 
205  Face* face = m_faceTable.get(faceId);
206 
207  if (face == nullptr) {
208  NFD_LOG_TRACE("invalid face specified");
209  done(ControlResponse(404, "Specified face does not exist"));
210  return;
211  }
212 
213  // Verify validity of requested changes
214  ControlParameters response;
215  bool areParamsValid = true;
216 
217  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
218  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
219  face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
220  NFD_LOG_TRACE("received request to enable local fields on non-local face");
221  areParamsValid = false;
222  response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
223  parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
224  }
225 
226  // check whether the requested FacePersistency change is valid if it's present
227  if (parameters.hasFacePersistency()) {
228  auto persistency = parameters.getFacePersistency();
229  if (!face->getTransport()->canChangePersistencyTo(persistency)) {
230  NFD_LOG_TRACE("cannot change face persistency to " << persistency);
231  areParamsValid = false;
232  response.setFacePersistency(persistency);
233  }
234  }
235 
236  if (!areParamsValid) {
237  done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
238  return;
239  }
240 
241  // All specified properties are valid, so make changes
242  if (parameters.hasFacePersistency()) {
243  face->setPersistency(parameters.getFacePersistency());
244  }
245  setLinkServiceOptions(*face, parameters);
246 
247  // Set ControlResponse fields
248  response = collectFaceProperties(*face, false);
249 
250  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
251 }
252 
253 void
254 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
255  const ControlParameters& parameters,
256  const ndn::mgmt::CommandContinuation& done)
257 {
258  Face* face = m_faceTable.get(parameters.getFaceId());
259  if (face != nullptr) {
260  face->close();
261  }
262 
263  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
264 }
265 
266 void
267 FaceManager::setLinkServiceOptions(Face& face,
268  const ControlParameters& parameters)
269 {
270  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
271  BOOST_ASSERT(linkService != nullptr);
272 
273  auto options = linkService->getOptions();
274  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
275  face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
276  options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
277  }
278  if (parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
279  options.reliabilityOptions.isEnabled = parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
280  }
281  if (parameters.hasFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
282  options.allowCongestionMarking = parameters.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED);
283  }
284  if (parameters.hasBaseCongestionMarkingInterval()) {
285  options.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
286  }
287  if (parameters.hasDefaultCongestionThreshold()) {
288  options.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
289  }
290  linkService->setOptions(options);
291 }
292 
293 ControlParameters
294 FaceManager::collectFaceProperties(const Face& face, bool wantUris)
295 {
296  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
297  BOOST_ASSERT(linkService != nullptr);
298  auto options = linkService->getOptions();
299 
300  ControlParameters params;
301  params.setFaceId(face.getId())
302  .setFacePersistency(face.getPersistency())
303  .setBaseCongestionMarkingInterval(options.baseCongestionMarkingInterval)
304  .setDefaultCongestionThreshold(options.defaultCongestionThreshold)
305  .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false)
306  .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled, false)
307  .setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, options.allowCongestionMarking, false);
308  if (wantUris) {
309  params.setUri(face.getRemoteUri().toString())
310  .setLocalUri(face.getLocalUri().toString());
311  }
312  return params;
313 }
314 
315 void
316 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
317  ndn::mgmt::StatusDatasetContext& context)
318 {
319  auto now = time::steady_clock::now();
320  for (const Face& face : m_faceTable) {
321  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
322  context.append(status.wireEncode());
323  }
324  context.end();
325 }
326 
327 void
328 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
329  ndn::mgmt::StatusDatasetContext& context)
330 {
331  std::set<const face::ProtocolFactory*> factories = m_faceSystem.listProtocolFactories();
332  for (const auto* factory : factories) {
333  for (const auto& channel : factory->getChannels()) {
334  ndn::nfd::ChannelStatus entry;
335  entry.setLocalUri(channel->getUri().toString());
336  context.append(entry.wireEncode());
337  }
338  }
339  context.end();
340 }
341 
342 void
343 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
344  ndn::mgmt::StatusDatasetContext& context)
345 {
346  ndn::nfd::FaceQueryFilter faceFilter;
347  const Name& query = interest.getName();
348  try {
349  faceFilter.wireDecode(query[-1].blockFromValue());
350  }
351  catch (const tlv::Error& e) {
352  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
353  return context.reject(ControlResponse(400, "Malformed filter"));
354  }
355 
356  auto now = time::steady_clock::now();
357  for (const Face& face : m_faceTable) {
358  if (!matchFilter(faceFilter, face)) {
359  continue;
360  }
361  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
362  context.append(status.wireEncode());
363  }
364 
365  context.end();
366 }
367 
368 bool
369 FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
370 {
371  if (filter.hasFaceId() &&
372  filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
373  return false;
374  }
375 
376  if (filter.hasUriScheme() &&
377  filter.getUriScheme() != face.getRemoteUri().getScheme() &&
378  filter.getUriScheme() != face.getLocalUri().getScheme()) {
379  return false;
380  }
381 
382  if (filter.hasRemoteUri() &&
383  filter.getRemoteUri() != face.getRemoteUri().toString()) {
384  return false;
385  }
386 
387  if (filter.hasLocalUri() &&
388  filter.getLocalUri() != face.getLocalUri().toString()) {
389  return false;
390  }
391 
392  if (filter.hasFaceScope() &&
393  filter.getFaceScope() != face.getScope()) {
394  return false;
395  }
396 
397  if (filter.hasFacePersistency() &&
398  filter.getFacePersistency() != face.getPersistency()) {
399  return false;
400  }
401 
402  if (filter.hasLinkType() &&
403  filter.getLinkType() != face.getLinkType()) {
404  return false;
405  }
406 
407  return true;
408 }
409 
410 ndn::nfd::FaceStatus
411 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
412 {
413  ndn::nfd::FaceStatus status;
414 
415  collectFaceProperties(face, status);
416 
417  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
418  if (expirationTime != time::steady_clock::TimePoint::max()) {
419  status.setExpirationPeriod(std::max(0_ms,
420  time::duration_cast<time::milliseconds>(expirationTime - now)));
421  }
422 
423  // Get LinkService options
424  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
425  if (linkService != nullptr) {
426  auto linkServiceOptions = linkService->getOptions();
427  status.setBaseCongestionMarkingInterval(linkServiceOptions.baseCongestionMarkingInterval);
428  status.setDefaultCongestionThreshold(linkServiceOptions.defaultCongestionThreshold);
429  }
430 
431  const face::FaceCounters& counters = face.getCounters();
432  status.setNInInterests(counters.nInInterests)
433  .setNOutInterests(counters.nOutInterests)
434  .setNInData(counters.nInData)
435  .setNOutData(counters.nOutData)
436  .setNInNacks(counters.nInNacks)
437  .setNOutNacks(counters.nOutNacks)
438  .setNInBytes(counters.nInBytes)
439  .setNOutBytes(counters.nOutBytes);
440 
441  return status;
442 }
443 
444 template<typename FaceTraits>
445 void
446 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
447 {
448  traits.setFaceId(face.getId())
449  .setRemoteUri(face.getRemoteUri().toString())
450  .setLocalUri(face.getLocalUri().toString())
451  .setFaceScope(face.getScope())
452  .setFacePersistency(face.getPersistency())
453  .setLinkType(face.getLinkType());
454 
455  // Set Flag bits
456  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
457  if (linkService != nullptr) {
458  auto linkServiceOptions = linkService->getOptions();
459  traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
460  traits.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED,
461  linkServiceOptions.reliabilityOptions.isEnabled);
462  traits.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED,
463  linkServiceOptions.allowCongestionMarking);
464  }
465 }
466 
467 void
468 FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
469 {
470  ndn::nfd::FaceEventNotification notification;
471  notification.setKind(kind);
472  collectFaceProperties(face, notification);
473 
474  m_postNotification(notification.wireEncode());
475 }
476 
477 void
478 FaceManager::connectFaceStateChangeSignal(const Face& face)
479 {
480  FaceId faceId = face.getId();
481  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
482  [this, faceId] (face::FaceState oldState, face::FaceState newState) {
483  const Face& face = *m_faceTable.get(faceId);
484 
485  if (newState == face::FaceState::UP) {
486  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
487  }
488  else if (newState == face::FaceState::DOWN) {
489  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
490  }
491  else if (newState == face::FaceState::CLOSED) {
492  m_faceStateChangeConn.erase(faceId);
493  }
494  });
495 }
496 
497 } // namespace nfd
Parameters used to set Transport properties or LinkService options on a newly created face...
Definition: channel.hpp:87
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
const PacketCounter & nOutInterests
configuration file parsing utility
Definition: config-file.hpp:58
TransportState
indicates the state of a transport
Definition: transport.hpp:42
const PacketCounter & nOutData
ndn::nfd::FacePersistency persistency
Definition: channel.hpp:100
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:44
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:164
FaceManager(FaceSystem &faceSystem, Dispatcher &dispatcher, CommandAuthenticator &authenticator)
provides ControlCommand authorization according to NFD configuration file
const ByteCounter & nInBytes
void add(shared_ptr< Face > face)
add a face
Definition: face-table.cpp:57
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:90
the transport is closed, and can be safely deallocated
virtual void createFace(const CreateFaceRequest &req, const FaceCreatedCallback &onCreated, const FaceCreationFailedCallback &onFailure)=0
Try to create a unicast face using the supplied parameters.
ndn::mgmt::PostNotification registerNotificationStream(const std::string &verb)
ndn::optional< time::nanoseconds > baseCongestionMarkingInterval
Definition: channel.hpp:101
a collection of common functions shared by all NFD managers, such as communicating with the dispatche...
signal::Signal< FaceTable, Face & > afterAdd
fires after a face is added
Definition: face-table.hpp:84
const PacketCounter & nOutNacks
gives access to counters provided by Face
const PacketCounter & nInInterests
void setConfigFile(ConfigFile &configFile)
Subscribe to face_system section for the config file.
ndn::optional< uint64_t > defaultCongestionThreshold
Definition: channel.hpp:102
const ByteCounter & nOutBytes
Provides support for an underlying protocol.
boost::logic::tribool wantCongestionMarking
Definition: channel.hpp:105
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
the transport is up and can transmit packets
uint64_t FaceId
identifies a face
Definition: face.hpp:39
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
const PacketCounter & nInData
const PacketCounter & nInNacks
the transport is temporarily down, and is being recovered