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