blob: 58d5d70474fbab51463bb206d186e12cd2230197 [file] [log] [blame]
Andrew Brown2f1fdbf2015-01-21 10:52:29 -08001/*
andrewsbrown7e6b9e82015-03-03 16:11:11 -08002 * jndn-management
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 3, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
12 * more details.
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080013 */
14package com.intel.jndn.management;
15
Andrew Brownc46c1602015-02-18 10:45:56 -080016import com.intel.jndn.management.types.StatusDataset;
17import com.intel.jndn.management.types.ControlResponse;
18import com.intel.jndn.management.types.FaceStatus;
Andrew Brown63bed362015-02-18 11:28:50 -080019import com.intel.jndn.management.types.FibEntry;
Andrew Brownc46c1602015-02-18 10:45:56 -080020import com.intel.jndn.management.types.RibEntry;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080021import com.intel.jndn.utils.Client;
Andrew Brown07466442015-02-24 09:07:02 -080022import com.intel.jndn.utils.SegmentedClient;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080023import java.io.IOException;
24import java.util.List;
25import net.named_data.jndn.ControlParameters;
26import net.named_data.jndn.Data;
27import net.named_data.jndn.Face;
28import net.named_data.jndn.ForwardingFlags;
29import net.named_data.jndn.Interest;
30import net.named_data.jndn.Name;
31import net.named_data.jndn.encoding.EncodingException;
32import net.named_data.jndn.security.SecurityException;
Andrew Brownc46c1602015-02-18 10:45:56 -080033import java.util.logging.Logger;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080034
35/**
36 * Helper class for interacting with an NDN forwarder daemon; see
37 * http://redmine.named-data.net/projects/nfd/wiki/Management for explanations
38 * of the various protocols used.
39 *
40 * @author Andrew Brown <andrew.brown@intel.com>
41 */
42public class NFD {
43
Andrew Brown211d2b62015-02-18 11:12:02 -080044 public final static long DEFAULT_TIMEOUT = 2000;
45 static private final Logger logger = Logger.getLogger(NFD.class.getName());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080046
Andrew Brown211d2b62015-02-18 11:12:02 -080047 /**
48 * Ping a forwarder on an existing face to verify that the forwarder is
49 * working and responding to requests; this version sends a discovery packet
50 * to /localhost/nfd which should always respond if the requestor is on the
51 * same machine as the NDN forwarding daemon.
52 *
53 * @param face
54 * @return true if successful, false otherwise
55 */
56 public static boolean pingLocal(Face face) {
57 return ping(face, new Name("/localhost/nfd"));
58 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080059
Andrew Brown211d2b62015-02-18 11:12:02 -080060 /**
61 * Request a name on an existing face to verify the forwarder is working and
62 * responding to requests. Note that the name must be served or cached on the
63 * forwarder for this to return true.
64 *
65 * @param face
66 * @param name
67 * @return true if successful, false otherwise
68 */
69 public static boolean ping(Face face, Name name) {
70 // build interest
71 Interest interest = new Interest(name);
72 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
73 interest.setMustBeFresh(true);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080074
Andrew Brown211d2b62015-02-18 11:12:02 -080075 // send packet
76 Data data = Client.getDefault().getSync(face, interest);
77 return data != null;
78 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080079
Andrew Brown211d2b62015-02-18 11:12:02 -080080 /**
81 * Retrieve a list of faces and their status from the given forwarder; calls
82 * /localhost/nfd/faces/list which requires a local Face (all non-local
83 * packets are dropped)
84 *
85 * @param forwarder Only a localhost Face
86 * @return
87 * @throws Exception
88 */
89 public static List<FaceStatus> getFaceList(Face forwarder) throws Exception {
90 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
91 Interest interest = new Interest(new Name("/localhost/nfd/faces/list"));
92 interest.setMustBeFresh(true);
93 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
94 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080095
Andrew Brown211d2b62015-02-18 11:12:02 -080096 // send packet
Andrew Brown07466442015-02-24 09:07:02 -080097 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown211d2b62015-02-18 11:12:02 -080098 if (data == null) {
99 throw new Exception("Failed to retrieve list of faces from the forwarder.");
100 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800101
andrewsbrown4c21ea22015-03-09 12:05:03 -0700102 // check for failed request
103 if (data.getContent().buf().get(0) == ControlResponse.TLV_CONTROL_RESPONSE) {
104 ControlResponse response = new ControlResponse();
105 response.wireDecode(data.getContent().buf());
106 throw new Exception("Failed to retrieve list of faces, forwarder returned: " + response.getStatusCode() + " " + response.getStatusText());
107 }
108
Andrew Brown211d2b62015-02-18 11:12:02 -0800109 // parse packet
110 return StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
111 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800112
Andrew Brown211d2b62015-02-18 11:12:02 -0800113 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800114 * Retrieve a list of FIB entries and their NextHopRecords from the given
115 * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
116 * non-local packets are dropped).
117 *
118 * @param forwarder Only a localhost Face
119 * @return
120 * @throws Exception
121 */
122 public static List<FibEntry> getFibList(Face forwarder) throws Exception {
123 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
124 Interest interest = new Interest(new Name("/localhost/nfd/fib/list"));
125 interest.setMustBeFresh(true);
126 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
127 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
128
129 // TODO verify that all faces are being returned; right now they don't
130 // match up with the results from nfd-status-http-server but no
131 // additional segments are present;
132 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
133 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800134 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown63bed362015-02-18 11:28:50 -0800135 if (data == null) {
andrewsbrown4c21ea22015-03-09 12:05:03 -0700136 throw new Exception("Failed to retrieve list of FIB entries from the forwarder.");
137 }
138
139 // check for failed request
140 if (data.getContent().buf().get(0) == ControlResponse.TLV_CONTROL_RESPONSE) {
141 ControlResponse response = new ControlResponse();
142 response.wireDecode(data.getContent().buf());
143 throw new Exception("Failed to retrieve list of FIB entries, forwarder returned: " + response.getStatusCode() + " " + response.getStatusText());
Andrew Brown63bed362015-02-18 11:28:50 -0800144 }
145
146 // parse packet
147 return StatusDataset.wireDecode(data.getContent(), FibEntry.class);
148 }
149
150 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800151 * Retrieve a list of routing entries from the RIB; calls
152 * /localhost/nfd/rib/list which requires a local Face (all non-local packets
153 * are dropped)
154 *
155 * @param forwarder Only a localhost Face
156 * @return
157 * @throws Exception
158 */
159 public static List<RibEntry> getRouteList(Face forwarder) throws Exception {
160 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
161 Interest interest = new Interest(new Name("/localhost/nfd/rib/list"));
162 interest.setMustBeFresh(true);
163 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
164 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brownc46c1602015-02-18 10:45:56 -0800165
Andrew Brown211d2b62015-02-18 11:12:02 -0800166 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800167 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown211d2b62015-02-18 11:12:02 -0800168 if (data == null) {
andrewsbrown4c21ea22015-03-09 12:05:03 -0700169 throw new Exception("Failed to retrieve list of routes from the forwarder.");
170 }
171
172 // check for failed request
173 if (data.getContent().buf().get(0) == ControlResponse.TLV_CONTROL_RESPONSE) {
174 ControlResponse response = new ControlResponse();
175 response.wireDecode(data.getContent().buf());
176 throw new Exception("Failed to retrieve list of routes, forwarder returned: " + response.getStatusCode() + " " + response.getStatusText());
Andrew Brown211d2b62015-02-18 11:12:02 -0800177 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800178
Andrew Brown211d2b62015-02-18 11:12:02 -0800179 // parse packet
180 return StatusDataset.wireDecode(data.getContent(), RibEntry.class);
181 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800182
Andrew Brown211d2b62015-02-18 11:12:02 -0800183 /**
184 * Helper method to register a new face on the forwarder; as mentioned at
185 * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more for
186 * debugging; use 'register' instead
187 *
188 * @param forwarder Only a localhost Face
189 * @param faceId
190 * @param prefix
191 * @return
192 * @throws Exception
193 */
194 public static boolean addNextHop(Face forwarder, int faceId, Name prefix) throws Exception {
195 // build command name
196 Name command = new Name("/localhost/nfd/fib/add-nexthop");
197 ControlParameters parameters = new ControlParameters();
198 parameters.setName(prefix);
199 parameters.setFaceId(faceId);
200 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800201
Andrew Brown211d2b62015-02-18 11:12:02 -0800202 // send the interest
203 return sendCommandAndErrorCheck(forwarder, new Interest(command));
204 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800205
Andrew Brown211d2b62015-02-18 11:12:02 -0800206 /**
207 * Create a new face on the given forwarder. Ensure the forwarding face is on
208 * the local machine (management requests are to /localhost/...) and that
209 * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
210 *
211 * @param forwarder Only a localhost Face
212 * @param uri
213 * @return
214 * @throws java.lang.Exception
215 */
216 public static int createFace(Face forwarder, String uri) throws Exception {
217 Name command = new Name("/localhost/nfd/faces/create");
218 ControlParameters parameters = new ControlParameters();
219 parameters.setUri(uri);
220 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800221
Andrew Brown211d2b62015-02-18 11:12:02 -0800222 // send the interest
223 ControlResponse response = sendCommand(forwarder, new Interest(command));
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800224
Andrew Brown211d2b62015-02-18 11:12:02 -0800225 // check for body and that status code is OK (TODO: 200 should be replaced with a CONSTANT like ControlResponse.STATUS_OK)
226 if (response.getBody().isEmpty() || response.getStatusCode() != 200) {
227 throw new Exception("Failed to create face: " + uri + " " + response.getStatusText());
228 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800229
Andrew Brown211d2b62015-02-18 11:12:02 -0800230 // return
231 return response.getBody().get(0).getFaceId();
232 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800233
Andrew Brown211d2b62015-02-18 11:12:02 -0800234 /**
235 * Register a route on the forwarder; see
236 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
237 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
238 * protocol documentation. Ensure the forwarding face is on the local machine
239 * (management requests are to /localhost/...) and that command signing has
240 * been set up (e.g. forwarder.setCommandSigningInfo()).
241 *
242 * @param forwarder Only a localhost Face
243 * @param controlParameters
244 * @return
245 * @throws Exception
246 */
247 public static boolean register(Face forwarder, ControlParameters controlParameters) throws Exception {
248 // build command name
249 Name command = new Name("/localhost/nfd/rib/register");
250 command.append(controlParameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800251
Andrew Brown211d2b62015-02-18 11:12:02 -0800252 // send the interest
253 return sendCommandAndErrorCheck(forwarder, new Interest(command));
254 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800255
Andrew Brown211d2b62015-02-18 11:12:02 -0800256 /**
257 * Register a route on a forwarder; this will create a new face on the
258 * forwarder to the given URI/route pair. See register(Face,
259 * ControlParameters) for more details documentation.
260 *
261 * @param forwarder Only a localhost Face
262 * @param uri
263 * @param cost
264 * @param route
265 * @return true for successful registration
266 * @throws java.lang.Exception
267 */
268 public static boolean register(Face forwarder, String uri, Name route, int cost) throws Exception {
269 // create the new face
270 int faceId = createFace(forwarder, uri);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800271
Andrew Brown211d2b62015-02-18 11:12:02 -0800272 // run base method
273 return register(forwarder, faceId, route, cost);
274 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800275
Andrew Brown211d2b62015-02-18 11:12:02 -0800276 /**
277 * Register a route on a forwarder; this will not create a new face since it
278 * is provided a faceId. See register(Face, ControlParameters) for full
279 * documentation
280 *
281 * @param forwarder Only a localhost Face
282 * @param faceId
283 * @param route
284 * @param cost
285 * @return true for successful registration
286 * @throws java.lang.Exception
287 */
288 public static boolean register(Face forwarder, int faceId, Name route, int cost) throws Exception {
289 // build command name
290 ControlParameters parameters = new ControlParameters();
291 parameters.setName(route);
292 parameters.setFaceId(faceId);
293 parameters.setCost(cost);
294 ForwardingFlags flags = new ForwardingFlags();
295 flags.setCapture(true);
296 flags.setChildInherit(true);
297 parameters.setForwardingFlags(flags);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800298
Andrew Brown211d2b62015-02-18 11:12:02 -0800299 // run base method
300 return register(forwarder, parameters);
301 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800302
Andrew Brown211d2b62015-02-18 11:12:02 -0800303 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800304 * Unregister a route on a forwarder; see
305 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
306 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
307 * protocol documentation. Ensure the forwarding face is on the local machine
308 * (management requests are to /localhost/...) and that command signing has
309 * been set up (e.g. forwarder.setCommandSigningInfo()
310 *
311 * @param forwarder
Andrew Brown07466442015-02-24 09:07:02 -0800312 * @param controlParameters
Andrew Brown63bed362015-02-18 11:28:50 -0800313 * @return
314 */
Andrew Brown07466442015-02-24 09:07:02 -0800315 public static boolean unregister(Face forwarder, ControlParameters controlParameters) throws Exception {
Andrew Brown63bed362015-02-18 11:28:50 -0800316 // build command name
317 Name command = new Name("/localhost/nfd/rib/unregister");
318 command.append(controlParameters.wireEncode());
319
320 // send the interest
321 return sendCommandAndErrorCheck(forwarder, new Interest(command));
322 }
323
324 /**
Andrew Brown07466442015-02-24 09:07:02 -0800325 * Unregister a route on a forwarder; see
326 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
327 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
328 * protocol documentation. Ensure the forwarding face is on the local machine
329 * (management requests are to /localhost/...) and that command signing has
330 * been set up (e.g. forwarder.setCommandSigningInfo()
331 *
332 * @param forwarder
333 * @param route
334 * @return
335 */
336 public static boolean unregister(Face forwarder, Name route) throws Exception {
337 // build command name
338 ControlParameters controlParameters = new ControlParameters();
339 controlParameters.setName(route);
340
341 // send the interest
342 return unregister(forwarder, controlParameters);
343 }
344
345 /**
346 * Unregister a route on a forwarder; see
347 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
348 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
349 * protocol documentation. Ensure the forwarding face is on the local machine
350 * (management requests are to /localhost/...) and that command signing has
351 * been set up (e.g. forwarder.setCommandSigningInfo()
352 *
353 * @param forwarder
354 * @param route
355 * @param faceId
356 * @return
357 */
358 public static boolean unregister(Face forwarder, Name route, int faceId) throws Exception {
359 // build command name
360 ControlParameters controlParameters = new ControlParameters();
361 controlParameters.setName(route);
362 controlParameters.setFaceId(faceId);
363
364 // send the interest
365 return unregister(forwarder, controlParameters);
366 }
367
368 /**
369 * Unregister a route on a forwarder; see
370 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
371 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
372 * protocol documentation. Ensure the forwarding face is on the local machine
373 * (management requests are to /localhost/...) and that command signing has
374 * been set up (e.g. forwarder.setCommandSigningInfo()
375 *
376 * @param forwarder
377 * @param route
378 * @param uri
379 * @return
380 */
381 public static boolean unregister(Face forwarder, Name route, String uri) throws Exception {
382 int faceId = -1;
andrewsbrown4c21ea22015-03-09 12:05:03 -0700383 for (FaceStatus face : getFaceList(forwarder)) {
384 if (face.getUri().matches(uri)) {
Andrew Brown07466442015-02-24 09:07:02 -0800385 faceId = face.getFaceId();
386 break;
387 }
388 }
andrewsbrown4c21ea22015-03-09 12:05:03 -0700389
390 if (faceId == -1) {
Andrew Brown07466442015-02-24 09:07:02 -0800391 throw new Exception("Face not found: " + uri);
392 }
393
394 // send the interest
395 return unregister(forwarder, route, faceId);
396 }
397
398 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800399 * Set a strategy on the forwarder; see
400 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
401 * usage and http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
402 * for protocol documentation. Ensure the forwarding face is on the local
403 * machine (management requests are to /localhost/...) and that command
404 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
405 *
406 * @param forwarder Only a localhost Face
407 * @param prefix
408 * @param strategy
409 * @return true for successful command
410 * @throws Exception
411 */
412 public static boolean setStrategy(Face forwarder, Name prefix, Name strategy) throws Exception {
413 // build command name
414 Name command = new Name("/localhost/nfd/strategy-choice/set");
415 ControlParameters parameters = new ControlParameters();
416 parameters.setName(prefix);
417 parameters.setStrategy(strategy);
418 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800419
Andrew Brown211d2b62015-02-18 11:12:02 -0800420 // send the interest
421 return sendCommandAndErrorCheck(forwarder, new Interest(command));
422 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800423
Andrew Brown211d2b62015-02-18 11:12:02 -0800424 /**
425 * Send an interest as a command to the forwarder; this method will convert
426 * the interest to a command interest and block until a response is received
427 * from the forwarder. Ensure the forwarding face is on the local machine
428 * (management requests are to /localhost/...) and that command signing has
429 * been set up (e.g. forwarder.setCommandSigningInfo()).
430 *
431 * @param forwarder Only a localhost Face
432 * @param interest As described at
433 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
434 * requested interest must have encoded ControlParameters appended to the
435 * interest name
436 * @return
437 * @throws net.named_data.jndn.security.SecurityException
438 * @throws java.io.IOException
439 * @throws net.named_data.jndn.encoding.EncodingException
440 */
441 public static ControlResponse sendCommand(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
442 forwarder.makeCommandInterest(interest);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800443
Andrew Brown211d2b62015-02-18 11:12:02 -0800444 // send command packet
445 Data data = Client.getDefault().getSync(forwarder, interest);
446 if (data == null) {
447 throw new IOException("Failed to receive command response.");
448 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800449
Andrew Brown211d2b62015-02-18 11:12:02 -0800450 // return response
451 ControlResponse response = new ControlResponse();
452 response.wireDecode(data.getContent().buf());
453 return response;
454 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800455
Andrew Brown211d2b62015-02-18 11:12:02 -0800456 /**
457 * Send an interest as a command to the forwarder; this method will convert
458 * the interest to a command interest and block until a response is received
459 * from the forwarder.
460 *
461 * @param forwarder Only a localhost Face
462 * @param interest As described at
463 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
464 * requested interest must have encoded ControlParameters appended to the
465 * interest name
466 * @return
467 * @throws net.named_data.jndn.security.SecurityException
468 * @throws java.io.IOException
469 * @throws net.named_data.jndn.encoding.EncodingException
470 */
471 public static boolean sendCommandAndErrorCheck(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
472 ControlResponse response = sendCommand(forwarder, interest);
473 if (response.getStatusCode() < 400) {
474 return true;
475 } else {
476 logger.warning("Command sent but failed: " + response.getStatusCode() + " " + response.getStatusText());
477 return false;
478 }
479 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800480}