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"
27 
28 #include "core/logger.hpp"
31 #include "fw/face-table.hpp"
32 
33 #include <boost/logic/tribool.hpp>
34 
35 #include <ndn-cxx/lp/tags.hpp>
36 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
37 
38 namespace nfd {
39 
40 NFD_LOG_INIT(FaceManager);
41 
42 FaceManager::FaceManager(FaceSystem& faceSystem,
43  Dispatcher& dispatcher,
44  CommandAuthenticator& authenticator)
45  : NfdManagerBase(dispatcher, authenticator, "faces")
46  , m_faceSystem(faceSystem)
47  , m_faceTable(faceSystem.getFaceTable())
48 {
49  // register handlers for ControlCommand
50  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
51  bind(&FaceManager::createFace, this, _2, _3, _4, _5));
52 
53  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
54  bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
55 
56  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
57  bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
58 
59  // register handlers for StatusDataset
60  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
61  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
62  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
63 
64  // register notification stream
65  m_postNotification = registerNotificationStream("events");
66  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
67  connectFaceStateChangeSignal(face);
68  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
69  });
70  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
71  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
72  });
73 }
74 
75 void
76 FaceManager::createFace(const Name& topPrefix, const Interest& interest,
77  const ControlParameters& parameters,
78  const ndn::mgmt::CommandContinuation& done)
79 {
80  FaceUri remoteUri;
81  if (!remoteUri.parse(parameters.getUri())) {
82  NFD_LOG_TRACE("failed to parse remote URI: " << parameters.getUri());
83  done(ControlResponse(400, "Malformed command"));
84  return;
85  }
86 
87  if (!remoteUri.isCanonical()) {
88  NFD_LOG_TRACE("received non-canonical remote URI: " << remoteUri.toString());
89  done(ControlResponse(400, "Non-canonical remote URI"));
90  return;
91  }
92 
93  optional<FaceUri> localUri;
94  if (parameters.hasLocalUri()) {
95  localUri = FaceUri{};
96 
97  if (!localUri->parse(parameters.getLocalUri())) {
98  NFD_LOG_TRACE("failed to parse local URI: " << parameters.getLocalUri());
99  done(ControlResponse(400, "Malformed command"));
100  return;
101  }
102 
103  if (!localUri->isCanonical()) {
104  NFD_LOG_TRACE("received non-canonical local URI: " << localUri->toString());
105  done(ControlResponse(400, "Non-canonical local URI"));
106  return;
107  }
108  }
109 
110  face::ProtocolFactory* factory = m_faceSystem.getFactoryByScheme(remoteUri.getScheme());
111  if (factory == nullptr) {
112  NFD_LOG_TRACE("received create request for unsupported protocol: " << remoteUri.getScheme());
113  done(ControlResponse(406, "Unsupported protocol"));
114  return;
115  }
116 
117  face::FaceParams faceParams;
118  faceParams.persistency = parameters.getFacePersistency();
119  if (parameters.hasBaseCongestionMarkingInterval()) {
120  faceParams.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
121  }
122  if (parameters.hasDefaultCongestionThreshold()) {
123  faceParams.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
124  }
125  if (parameters.hasMtu()) {
126  faceParams.mtu = parameters.getMtu();
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  response.unsetMtu(); // This parameter is only included with the response to faces/create and FaceStatus
250 
251  done(ControlResponse(200, "OK").setBody(response.wireEncode()));
252 }
253 
254 void
255 FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
256  const ControlParameters& parameters,
257  const ndn::mgmt::CommandContinuation& done)
258 {
259  Face* face = m_faceTable.get(parameters.getFaceId());
260  if (face != nullptr) {
261  face->close();
262  }
263 
264  done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
265 }
266 
267 void
268 FaceManager::setLinkServiceOptions(Face& face,
269  const ControlParameters& parameters)
270 {
271  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
272  BOOST_ASSERT(linkService != nullptr);
273 
274  auto options = linkService->getOptions();
275  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
276  face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
277  options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
278  }
279  if (parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
280  options.reliabilityOptions.isEnabled = parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
281  }
282  if (parameters.hasFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
283  options.allowCongestionMarking = parameters.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED);
284  }
285  if (parameters.hasBaseCongestionMarkingInterval()) {
286  options.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
287  }
288  if (parameters.hasDefaultCongestionThreshold()) {
289  options.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
290  }
291  linkService->setOptions(options);
292 }
293 
294 ControlParameters
295 FaceManager::collectFaceProperties(const Face& face, bool wantUris)
296 {
297  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
298  BOOST_ASSERT(linkService != nullptr);
299  auto options = linkService->getOptions();
300 
301  auto transport = face.getTransport();
302  BOOST_ASSERT(transport != nullptr);
303 
304  ControlParameters params;
305  params.setFaceId(face.getId())
306  .setFacePersistency(face.getPersistency())
307  .setBaseCongestionMarkingInterval(options.baseCongestionMarkingInterval)
308  .setDefaultCongestionThreshold(options.defaultCongestionThreshold)
309  .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false)
310  .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled, false)
311  .setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, options.allowCongestionMarking, false);
312 
313  if (transport->getMtu() > 0) {
314  params.setMtu(std::min<uint64_t>(transport->getMtu(), ndn::MAX_NDN_PACKET_SIZE));
315  }
316  else if (transport->getMtu() == face::MTU_UNLIMITED) {
317  params.setMtu(ndn::MAX_NDN_PACKET_SIZE);
318  }
319 
320  if (wantUris) {
321  params.setUri(face.getRemoteUri().toString())
322  .setLocalUri(face.getLocalUri().toString());
323  }
324  return params;
325 }
326 
327 void
328 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
329  ndn::mgmt::StatusDatasetContext& context)
330 {
331  auto now = time::steady_clock::now();
332  for (const Face& face : m_faceTable) {
333  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
334  context.append(status.wireEncode());
335  }
336  context.end();
337 }
338 
339 void
340 FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
341  ndn::mgmt::StatusDatasetContext& context)
342 {
343  std::set<const face::ProtocolFactory*> factories = m_faceSystem.listProtocolFactories();
344  for (const auto* factory : factories) {
345  for (const auto& channel : factory->getChannels()) {
346  ndn::nfd::ChannelStatus entry;
347  entry.setLocalUri(channel->getUri().toString());
348  context.append(entry.wireEncode());
349  }
350  }
351  context.end();
352 }
353 
354 void
355 FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
356  ndn::mgmt::StatusDatasetContext& context)
357 {
358  ndn::nfd::FaceQueryFilter faceFilter;
359  const Name& query = interest.getName();
360  try {
361  faceFilter.wireDecode(query[-1].blockFromValue());
362  }
363  catch (const tlv::Error& e) {
364  NFD_LOG_DEBUG("Malformed query filter: " << e.what());
365  return context.reject(ControlResponse(400, "Malformed filter"));
366  }
367 
368  auto now = time::steady_clock::now();
369  for (const Face& face : m_faceTable) {
370  if (!matchFilter(faceFilter, face)) {
371  continue;
372  }
373  ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
374  context.append(status.wireEncode());
375  }
376 
377  context.end();
378 }
379 
380 bool
381 FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
382 {
383  if (filter.hasFaceId() &&
384  filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
385  return false;
386  }
387 
388  if (filter.hasUriScheme() &&
389  filter.getUriScheme() != face.getRemoteUri().getScheme() &&
390  filter.getUriScheme() != face.getLocalUri().getScheme()) {
391  return false;
392  }
393 
394  if (filter.hasRemoteUri() &&
395  filter.getRemoteUri() != face.getRemoteUri().toString()) {
396  return false;
397  }
398 
399  if (filter.hasLocalUri() &&
400  filter.getLocalUri() != face.getLocalUri().toString()) {
401  return false;
402  }
403 
404  if (filter.hasFaceScope() &&
405  filter.getFaceScope() != face.getScope()) {
406  return false;
407  }
408 
409  if (filter.hasFacePersistency() &&
410  filter.getFacePersistency() != face.getPersistency()) {
411  return false;
412  }
413 
414  if (filter.hasLinkType() &&
415  filter.getLinkType() != face.getLinkType()) {
416  return false;
417  }
418 
419  return true;
420 }
421 
422 ndn::nfd::FaceStatus
423 FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
424 {
425  ndn::nfd::FaceStatus status;
426 
427  collectFaceProperties(face, status);
428 
429  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
430  if (expirationTime != time::steady_clock::TimePoint::max()) {
431  status.setExpirationPeriod(std::max(0_ms,
432  time::duration_cast<time::milliseconds>(expirationTime - now)));
433  }
434 
435  // Get LinkService options
436  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
437  if (linkService != nullptr) {
438  auto linkServiceOptions = linkService->getOptions();
439  status.setBaseCongestionMarkingInterval(linkServiceOptions.baseCongestionMarkingInterval);
440  status.setDefaultCongestionThreshold(linkServiceOptions.defaultCongestionThreshold);
441  }
442 
443  const face::FaceCounters& counters = face.getCounters();
444  status.setNInInterests(counters.nInInterests)
445  .setNOutInterests(counters.nOutInterests)
446  .setNInData(counters.nInData)
447  .setNOutData(counters.nOutData)
448  .setNInNacks(counters.nInNacks)
449  .setNOutNacks(counters.nOutNacks)
450  .setNInBytes(counters.nInBytes)
451  .setNOutBytes(counters.nOutBytes);
452 
453  return status;
454 }
455 
456 template<typename FaceTraits>
457 void
458 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
459 {
460  traits.setFaceId(face.getId())
461  .setRemoteUri(face.getRemoteUri().toString())
462  .setLocalUri(face.getLocalUri().toString())
463  .setFaceScope(face.getScope())
464  .setFacePersistency(face.getPersistency())
465  .setLinkType(face.getLinkType());
466 
467  // Set Flag bits
468  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
469  if (linkService != nullptr) {
470  auto linkServiceOptions = linkService->getOptions();
471  traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
472  traits.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED,
473  linkServiceOptions.reliabilityOptions.isEnabled);
474  traits.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED,
475  linkServiceOptions.allowCongestionMarking);
476  }
477 }
478 
479 void
480 FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
481 {
482  ndn::nfd::FaceEventNotification notification;
483  notification.setKind(kind);
484  collectFaceProperties(face, notification);
485 
486  m_postNotification(notification.wireEncode());
487 }
488 
489 void
490 FaceManager::connectFaceStateChangeSignal(const Face& face)
491 {
492  using face::FaceState;
493 
494  FaceId faceId = face.getId();
495  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
496  [this, faceId, &face] (FaceState oldState, FaceState newState) {
497  if (newState == FaceState::UP) {
498  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
499  }
500  else if (newState == FaceState::DOWN) {
501  notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
502  }
503  else if (newState == FaceState::CLOSED) {
504  // cannot use face.getId() because it may already be reset to INVALID_FACEID
505  m_faceStateChangeConn.erase(faceId);
506  }
507  });
508 }
509 
510 } // namespace nfd
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
const PacketCounter & nOutInterests
const ssize_t MTU_UNLIMITED
indicates the transport has no limit on payload size
Definition: transport.hpp:96
#define NFD_LOG_ERROR
Definition: logger.hpp:41
#define NFD_LOG_TRACE
Definition: logger.hpp:37
const PacketCounter & nOutData
boost::logic::tribool wantCongestionMarking
Definition: channel.hpp:95
optional< uint64_t > defaultCongestionThreshold
Definition: channel.hpp:91
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:45
FaceManager(FaceSystem &faceSystem, Dispatcher &dispatcher, CommandAuthenticator &authenticator)
Parameters used to set Transport properties or LinkService options on a newly created face...
Definition: channel.hpp:87
Provides ControlCommand authorization according to NFD configuration file.
const ByteCounter & nInBytes
optional< time::nanoseconds > baseCongestionMarkingInterval
Definition: channel.hpp:90
void add(shared_ptr< Face > face)
add a face
Definition: face-table.cpp:58
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
TransportState FaceState
indicates the state of a face
Definition: face.hpp:54
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:90
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)
a collection of common functions shared by all NFD managers, such as communicating with the dispatche...
optional< ssize_t > mtu
Definition: channel.hpp:92
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
ndn::nfd::FacePersistency persistency
Definition: channel.hpp:89
const ByteCounter & nOutBytes
Provides support for an underlying protocol.
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
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