blob: 8d080139ca587b4ca1c784a6ec2686cebeeb7ade [file] [log] [blame]
Junxiao Shi5ec80222014-03-25 20:08:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * See COPYING for copyright and distribution information.
5 */
6
7#ifndef NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
8#define NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
9
10#include "nfd-control-parameters.hpp"
11#include "../util/command-interest-generator.hpp"
12
13namespace ndn {
14namespace nfd {
15
16/** \brief base class of NFD ControlCommand
17 * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
18 */
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070019class ControlCommand : noncopyable
Junxiao Shi5ec80222014-03-25 20:08:05 -070020{
21public:
22 /** \brief represents an error in ControlParameters
23 */
24 class ArgumentError : public std::invalid_argument
25 {
26 public:
27 explicit
28 ArgumentError(const std::string& what)
29 : std::invalid_argument(what)
30 {
31 }
32 };
33
34 /** \return Name prefix of this ControlCommand
35 */
36 const Name&
37 getPrefix() const
38 {
39 return m_prefix;
40 }
41
42 /** \brief make a Command Interest from parameters
43 */
44 Interest
45 makeCommandInterest(const ControlParameters& parameters,
46 CommandInterestGenerator& commandInterestGenerator) const
47 {
48 this->validateRequest(parameters);
49
50 Name name = m_prefix;
51 name.append(parameters.wireEncode());
52 Interest commandInterest(name);
53 commandInterestGenerator.generate(commandInterest);
54 return commandInterest;
55 }
56
57 /** \brief validate request parameters
58 * \throw ArgumentError
59 */
60 virtual void
61 validateRequest(const ControlParameters& parameters) const
62 {
63 m_requestValidator.validate(parameters);
64 }
65
66 /** \brief apply default values to missing fields in request
67 */
68 virtual void
69 applyDefaultsToRequest(ControlParameters& parameters) const
70 {
71 }
72
73 /** \brief validate response parameters
74 * \throw ArgumentError
75 */
76 virtual void
77 validateResponse(const ControlParameters& parameters) const
78 {
79 m_responseValidator.validate(parameters);
80 }
81
82 /** \brief apply default values to missing fields in response
83 */
84 virtual void
85 applyDefaultsToResponse(ControlParameters& parameters) const
86 {
87 }
88
89protected:
90 ControlCommand(const std::string& module, const std::string& verb)
91 : m_prefix("ndn:/localhost/nfd")
92 {
93 m_prefix.append(module).append(verb);
94 }
95
96 class FieldValidator
97 {
98 public:
99 FieldValidator()
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700100 : m_required(CONTROL_PARAMETER_UBOUND)
101 , m_optional(CONTROL_PARAMETER_UBOUND)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700102 {
Junxiao Shi5ec80222014-03-25 20:08:05 -0700103 }
104
105 /** \brief declare a required field
106 */
107 FieldValidator&
108 required(ControlParameterField field)
109 {
110 m_required[field] = true;
111 return *this;
112 }
113
114 /** \brief declare an optional field
115 */
116 FieldValidator&
117 optional(ControlParameterField field)
118 {
119 m_optional[field] = true;
120 return *this;
121 }
122
123 /** \brief verify that all required fields are present,
124 * and all present fields are either required or optional
125 * \throw ArgumentError
126 */
127 void
128 validate(const ControlParameters& parameters) const
129 {
130 const std::vector<bool>& presentFields = parameters.getPresentFields();
131
132 for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
133 bool isPresent = presentFields[i];
134 if (m_required[i]) {
135 if (!isPresent) {
136 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
137 }
138 }
139 else if (isPresent && !m_optional[i]) {
140 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
141 }
142 }
143 }
144
145 private:
146 std::vector<bool> m_required;
147 std::vector<bool> m_optional;
148 };
149
150protected:
151 /** \brief FieldValidator for request ControlParameters
152 *
153 * Constructor of subclass should populate this validator.
154 */
155 FieldValidator m_requestValidator;
156 /** \brief FieldValidator for response ControlParameters
157 *
158 * Constructor of subclass should populate this validator.
159 */
160 FieldValidator m_responseValidator;
161
162private:
163 Name m_prefix;
164};
165
166
167/** \brief represents a faces/create command
168 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face
169 */
170class FaceCreateCommand : public ControlCommand
171{
172public:
173 FaceCreateCommand()
174 : ControlCommand("faces", "create")
175 {
176 m_requestValidator
177 .required(CONTROL_PARAMETER_URI);
178 m_responseValidator
179 .required(CONTROL_PARAMETER_URI)
180 .required(CONTROL_PARAMETER_FACE_ID);
181 }
182
183 virtual void
184 validateResponse(const ControlParameters& parameters) const
185 {
186 this->ControlCommand::validateResponse(parameters);
187
188 if (parameters.getFaceId() == 0) {
189 throw ArgumentError("FaceId must not be zero");
190 }
191 }
192};
193
194
195/** \brief represents a faces/destroy command
196 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face
197 */
198class FaceDestroyCommand : public ControlCommand
199{
200public:
201 FaceDestroyCommand()
202 : ControlCommand("faces", "destroy")
203 {
204 m_requestValidator
205 .required(CONTROL_PARAMETER_FACE_ID);
206 m_responseValidator = m_requestValidator;
207 }
208
209 virtual void
210 validateRequest(const ControlParameters& parameters) const
211 {
212 this->ControlCommand::validateRequest(parameters);
213
214 if (parameters.getFaceId() == 0) {
215 throw ArgumentError("FaceId must not be zero");
216 }
217 }
218
219 virtual void
220 validateResponse(const ControlParameters& parameters) const
221 {
222 this->validateRequest(parameters);
223 }
224};
225
226
227class FaceLocalControlCommand : public ControlCommand
228{
Junxiao Shi6888bc12014-03-29 23:01:41 -0700229public:
230 virtual void
231 validateRequest(const ControlParameters& parameters) const
232 {
233 this->ControlCommand::validateRequest(parameters);
234
235 switch (parameters.getLocalControlFeature()) {
236 case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
237 case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
238 break;
239 default:
240 throw ArgumentError("LocalControlFeature is invalid");
241 }
242 }
243
244 virtual void
245 validateResponse(const ControlParameters& parameters) const
246 {
247 this->validateRequest(parameters);
248 }
249
Junxiao Shi5ec80222014-03-25 20:08:05 -0700250protected:
251 explicit
252 FaceLocalControlCommand(const std::string& verb)
253 : ControlCommand("faces", verb)
254 {
255 m_requestValidator
256 .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
257 m_responseValidator = m_requestValidator;
258 }
259};
260
261
262/** \brief represents a faces/enable-local-control command
263 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature
264 */
265class FaceEnableLocalControlCommand : public FaceLocalControlCommand
266{
267public:
268 FaceEnableLocalControlCommand()
269 : FaceLocalControlCommand("enable-local-control")
270 {
271 }
272};
273
274
275/** \brief represents a faces/disable-local-control command
276 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature
277 */
278class FaceDisableLocalControlCommand : public FaceLocalControlCommand
279{
280public:
281 FaceDisableLocalControlCommand()
282 : FaceLocalControlCommand("disable-local-control")
283 {
284 }
285};
286
287
288/** \brief represents a fib/add-nexthop command
289 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop
290 */
291class FibAddNextHopCommand : public ControlCommand
292{
293public:
294 FibAddNextHopCommand()
295 : ControlCommand("fib", "add-nexthop")
296 {
297 m_requestValidator
298 .required(CONTROL_PARAMETER_NAME)
299 .required(CONTROL_PARAMETER_FACE_ID)
300 .optional(CONTROL_PARAMETER_COST);
301 m_responseValidator
302 .required(CONTROL_PARAMETER_NAME)
303 .required(CONTROL_PARAMETER_FACE_ID)
304 .required(CONTROL_PARAMETER_COST);
305 }
306
307 virtual void
308 applyDefaultsToRequest(ControlParameters& parameters) const
309 {
310 if (!parameters.hasCost()) {
311 parameters.setCost(0);
312 }
313 }
314
315 virtual void
316 validateResponse(const ControlParameters& parameters) const
317 {
318 this->ControlCommand::validateResponse(parameters);
319
320 if (parameters.getFaceId() == 0) {
321 throw ArgumentError("FaceId must not be zero");
322 }
323 }
324};
325
326
327/** \brief represents a fib/remove-nexthop command
328 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop
329 */
330class FibRemoveNextHopCommand : public ControlCommand
331{
332public:
333 FibRemoveNextHopCommand()
334 : ControlCommand("fib", "remove-nexthop")
335 {
336 m_requestValidator
337 .required(CONTROL_PARAMETER_NAME)
338 .required(CONTROL_PARAMETER_FACE_ID);
339 m_responseValidator
340 .required(CONTROL_PARAMETER_NAME)
341 .required(CONTROL_PARAMETER_FACE_ID);
342 }
343
344 virtual void
345 validateResponse(const ControlParameters& parameters) const
346 {
347 this->ControlCommand::validateResponse(parameters);
348
349 if (parameters.getFaceId() == 0) {
350 throw ArgumentError("FaceId must not be zero");
351 }
352 }
353};
354
355
356/** \brief represents a strategy-choice/set command
357 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace
358 */
359class StrategyChoiceSetCommand : public ControlCommand
360{
361public:
362 StrategyChoiceSetCommand()
363 : ControlCommand("strategy-choice", "set")
364 {
365 m_requestValidator
366 .required(CONTROL_PARAMETER_NAME)
367 .required(CONTROL_PARAMETER_STRATEGY);
368 m_responseValidator = m_requestValidator;
369 }
370};
371
372
373/** \brief represents a strategy-choice/set command
374 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace
375 */
376class StrategyChoiceUnsetCommand : public ControlCommand
377{
378public:
379 StrategyChoiceUnsetCommand()
380 : ControlCommand("strategy-choice", "unset")
381 {
382 m_requestValidator
383 .required(CONTROL_PARAMETER_NAME);
384 m_responseValidator = m_requestValidator;
385 }
386
387 virtual void
388 validateRequest(const ControlParameters& parameters) const
389 {
390 this->ControlCommand::validateRequest(parameters);
391
392 if (parameters.getName().size() == 0) {
393 throw ArgumentError("Name must not be ndn:/");
394 }
395 }
396
397 virtual void
398 validateResponse(const ControlParameters& parameters) const
399 {
400 this->validateRequest(parameters);
401 }
402};
403
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700404
405enum {
406 // route origin
407 ROUTE_ORIGIN_APP = 0,
408 ROUTE_ORIGIN_NLSR = 128,
409 ROUTE_ORIGIN_STATIC = 255,
410
411 // route inheritance flags
412 ROUTE_FLAG_CHILD_INHERIT = 1,
413 ROUTE_FLAG_CAPTURE = 2
414};
415
416
417/** \brief represents a rib/register command
418 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route
419 */
420class RibRegisterCommand : public ControlCommand
421{
422public:
423 RibRegisterCommand()
424 : ControlCommand("rib", "register")
425 {
426 m_requestValidator
427 .required(CONTROL_PARAMETER_NAME)
428 .optional(CONTROL_PARAMETER_FACE_ID)
429 .optional(CONTROL_PARAMETER_ORIGIN)
430 .optional(CONTROL_PARAMETER_COST)
431 .optional(CONTROL_PARAMETER_FLAGS)
432 .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
433 m_responseValidator
434 .required(CONTROL_PARAMETER_NAME)
435 .required(CONTROL_PARAMETER_FACE_ID)
436 .required(CONTROL_PARAMETER_ORIGIN)
437 .required(CONTROL_PARAMETER_COST)
438 .required(CONTROL_PARAMETER_FLAGS)
439 .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
440 }
441
442 virtual void
443 applyDefaultsToRequest(ControlParameters& parameters) const
444 {
445 if (!parameters.hasFaceId()) {
446 parameters.setFaceId(0);
447 }
448 if (!parameters.hasOrigin()) {
449 parameters.setOrigin(ROUTE_ORIGIN_APP);
450 }
451 if (!parameters.hasCost()) {
452 parameters.setCost(0);
453 }
454 if (!parameters.hasFlags()) {
455 parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
456 }
457 if (!parameters.hasExpirationPeriod()) {
458 if (parameters.getFaceId() == 0) {
459 parameters.setExpirationPeriod(time::milliseconds::max());
460 }
461 else {
462 parameters.setExpirationPeriod(time::hours(1));
463 }
464 }
465 }
466
467 virtual void
468 validateResponse(const ControlParameters& parameters) const
469 {
470 this->ControlCommand::validateResponse(parameters);
471
472 if (parameters.getFaceId() == 0) {
473 throw ArgumentError("FaceId must not be zero");
474 }
475 }
476};
477
478
479/** \brief represents a rib/unregister command
480 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route
481 */
482class RibUnregisterCommand : public ControlCommand
483{
484public:
485 RibUnregisterCommand()
486 : ControlCommand("rib", "unregister")
487 {
488 m_requestValidator
489 .required(CONTROL_PARAMETER_NAME)
490 .optional(CONTROL_PARAMETER_FACE_ID)
491 .optional(CONTROL_PARAMETER_ORIGIN);
492 m_responseValidator
493 .required(CONTROL_PARAMETER_NAME)
494 .required(CONTROL_PARAMETER_FACE_ID)
495 .required(CONTROL_PARAMETER_ORIGIN);
496 }
497
498 virtual void
499 applyDefaultsToRequest(ControlParameters& parameters) const
500 {
501 if (!parameters.hasFaceId()) {
502 parameters.setFaceId(0);
503 }
504 if (!parameters.hasOrigin()) {
505 parameters.setOrigin(ROUTE_ORIGIN_APP);
506 }
507 }
508
509 virtual void
510 validateResponse(const ControlParameters& parameters) const
511 {
512 this->ControlCommand::validateResponse(parameters);
513
514 if (parameters.getFaceId() == 0) {
515 throw ArgumentError("FaceId must not be zero");
516 }
517 }
518};
519
520
Junxiao Shi5ec80222014-03-25 20:08:05 -0700521} // namespace nfd
522} // namespace ndn
523
524#endif // NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP