blob: 5b7442fa2e57982af6b7dcca441f36c55130a2ff [file] [log] [blame]
Andrew Brown2f1fdbf2015-01-21 10:52:29 -08001/*
2 * File name: NFD.java
3 *
4 * Purpose: Helper class for interacting with an NDN forwarder daemon;
5 * see http://redmine.named-data.net/projects/nfd/wiki/Management for
6 * explanations of the various protocols used.
7 *
8 * © Copyright Intel Corporation. All rights reserved.
9 * Intel Corporation, 2200 Mission College Boulevard,
10 * Santa Clara, CA 95052-8119, USA
11 */
12package com.intel.jndn.management;
13
Andrew Brownc46c1602015-02-18 10:45:56 -080014import com.intel.jndn.management.types.StatusDataset;
15import com.intel.jndn.management.types.ControlResponse;
16import com.intel.jndn.management.types.FaceStatus;
Andrew Brown63bed362015-02-18 11:28:50 -080017import com.intel.jndn.management.types.FibEntry;
Andrew Brownc46c1602015-02-18 10:45:56 -080018import com.intel.jndn.management.types.RibEntry;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080019import com.intel.jndn.utils.Client;
Andrew Brown07466442015-02-24 09:07:02 -080020import com.intel.jndn.utils.SegmentedClient;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080021import java.io.IOException;
22import java.util.List;
23import net.named_data.jndn.ControlParameters;
24import net.named_data.jndn.Data;
25import net.named_data.jndn.Face;
26import net.named_data.jndn.ForwardingFlags;
27import net.named_data.jndn.Interest;
28import net.named_data.jndn.Name;
29import net.named_data.jndn.encoding.EncodingException;
30import net.named_data.jndn.security.SecurityException;
Andrew Brownc46c1602015-02-18 10:45:56 -080031import java.util.logging.Logger;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080032
33/**
34 * Helper class for interacting with an NDN forwarder daemon; see
35 * http://redmine.named-data.net/projects/nfd/wiki/Management for explanations
36 * of the various protocols used.
37 *
38 * @author Andrew Brown <andrew.brown@intel.com>
39 */
40public class NFD {
41
Andrew Brown211d2b62015-02-18 11:12:02 -080042 public final static long DEFAULT_TIMEOUT = 2000;
43 static private final Logger logger = Logger.getLogger(NFD.class.getName());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080044
Andrew Brown211d2b62015-02-18 11:12:02 -080045 /**
46 * Ping a forwarder on an existing face to verify that the forwarder is
47 * working and responding to requests; this version sends a discovery packet
48 * to /localhost/nfd which should always respond if the requestor is on the
49 * same machine as the NDN forwarding daemon.
50 *
51 * @param face
52 * @return true if successful, false otherwise
53 */
54 public static boolean pingLocal(Face face) {
55 return ping(face, new Name("/localhost/nfd"));
56 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080057
Andrew Brown211d2b62015-02-18 11:12:02 -080058 /**
59 * Request a name on an existing face to verify the forwarder is working and
60 * responding to requests. Note that the name must be served or cached on the
61 * forwarder for this to return true.
62 *
63 * @param face
64 * @param name
65 * @return true if successful, false otherwise
66 */
67 public static boolean ping(Face face, Name name) {
68 // build interest
69 Interest interest = new Interest(name);
70 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
71 interest.setMustBeFresh(true);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080072
Andrew Brown211d2b62015-02-18 11:12:02 -080073 // send packet
74 Data data = Client.getDefault().getSync(face, interest);
75 return data != null;
76 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080077
Andrew Brown211d2b62015-02-18 11:12:02 -080078 /**
79 * Retrieve a list of faces and their status from the given forwarder; calls
80 * /localhost/nfd/faces/list which requires a local Face (all non-local
81 * packets are dropped)
82 *
83 * @param forwarder Only a localhost Face
84 * @return
85 * @throws Exception
86 */
87 public static List<FaceStatus> getFaceList(Face forwarder) throws Exception {
88 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
89 Interest interest = new Interest(new Name("/localhost/nfd/faces/list"));
90 interest.setMustBeFresh(true);
91 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
92 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080093
Andrew Brown211d2b62015-02-18 11:12:02 -080094 // send packet
Andrew Brown07466442015-02-24 09:07:02 -080095 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown211d2b62015-02-18 11:12:02 -080096 if (data == null) {
97 throw new Exception("Failed to retrieve list of faces from the forwarder.");
98 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080099
Andrew Brown211d2b62015-02-18 11:12:02 -0800100 // parse packet
101 return StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
102 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800103
Andrew Brown211d2b62015-02-18 11:12:02 -0800104 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800105 * Retrieve a list of FIB entries and their NextHopRecords from the given
106 * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
107 * non-local packets are dropped).
108 *
109 * @param forwarder Only a localhost Face
110 * @return
111 * @throws Exception
112 */
113 public static List<FibEntry> getFibList(Face forwarder) throws Exception {
114 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
115 Interest interest = new Interest(new Name("/localhost/nfd/fib/list"));
116 interest.setMustBeFresh(true);
117 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
118 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
119
120 // TODO verify that all faces are being returned; right now they don't
121 // match up with the results from nfd-status-http-server but no
122 // additional segments are present;
123 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
124 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800125 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown63bed362015-02-18 11:28:50 -0800126 if (data == null) {
127 throw new Exception("Failed to retrieve list of fib entries from the forwarder.");
128 }
129
130 // parse packet
131 return StatusDataset.wireDecode(data.getContent(), FibEntry.class);
132 }
133
134 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800135 * Retrieve a list of routing entries from the RIB; calls
136 * /localhost/nfd/rib/list which requires a local Face (all non-local packets
137 * are dropped)
138 *
139 * @param forwarder Only a localhost Face
140 * @return
141 * @throws Exception
142 */
143 public static List<RibEntry> getRouteList(Face forwarder) throws Exception {
144 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
145 Interest interest = new Interest(new Name("/localhost/nfd/rib/list"));
146 interest.setMustBeFresh(true);
147 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
148 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brownc46c1602015-02-18 10:45:56 -0800149
Andrew Brown211d2b62015-02-18 11:12:02 -0800150 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800151 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown211d2b62015-02-18 11:12:02 -0800152 if (data == null) {
153 throw new Exception("Failed to retrieve list of faces from the forwarder.");
154 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800155
Andrew Brown211d2b62015-02-18 11:12:02 -0800156 // parse packet
157 return StatusDataset.wireDecode(data.getContent(), RibEntry.class);
158 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800159
Andrew Brown211d2b62015-02-18 11:12:02 -0800160 /**
161 * Helper method to register a new face on the forwarder; as mentioned at
162 * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more for
163 * debugging; use 'register' instead
164 *
165 * @param forwarder Only a localhost Face
166 * @param faceId
167 * @param prefix
168 * @return
169 * @throws Exception
170 */
171 public static boolean addNextHop(Face forwarder, int faceId, Name prefix) throws Exception {
172 // build command name
173 Name command = new Name("/localhost/nfd/fib/add-nexthop");
174 ControlParameters parameters = new ControlParameters();
175 parameters.setName(prefix);
176 parameters.setFaceId(faceId);
177 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800178
Andrew Brown211d2b62015-02-18 11:12:02 -0800179 // send the interest
180 return sendCommandAndErrorCheck(forwarder, new Interest(command));
181 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800182
Andrew Brown211d2b62015-02-18 11:12:02 -0800183 /**
184 * Create a new face on the given forwarder. Ensure the forwarding face is on
185 * the local machine (management requests are to /localhost/...) and that
186 * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
187 *
188 * @param forwarder Only a localhost Face
189 * @param uri
190 * @return
191 * @throws java.lang.Exception
192 */
193 public static int createFace(Face forwarder, String uri) throws Exception {
194 Name command = new Name("/localhost/nfd/faces/create");
195 ControlParameters parameters = new ControlParameters();
196 parameters.setUri(uri);
197 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800198
Andrew Brown211d2b62015-02-18 11:12:02 -0800199 // send the interest
200 ControlResponse response = sendCommand(forwarder, new Interest(command));
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800201
Andrew Brown211d2b62015-02-18 11:12:02 -0800202 // check for body and that status code is OK (TODO: 200 should be replaced with a CONSTANT like ControlResponse.STATUS_OK)
203 if (response.getBody().isEmpty() || response.getStatusCode() != 200) {
204 throw new Exception("Failed to create face: " + uri + " " + response.getStatusText());
205 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800206
Andrew Brown211d2b62015-02-18 11:12:02 -0800207 // return
208 return response.getBody().get(0).getFaceId();
209 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800210
Andrew Brown211d2b62015-02-18 11:12:02 -0800211 /**
212 * Register a route on the forwarder; see
213 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
214 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
215 * protocol documentation. Ensure the forwarding face is on the local machine
216 * (management requests are to /localhost/...) and that command signing has
217 * been set up (e.g. forwarder.setCommandSigningInfo()).
218 *
219 * @param forwarder Only a localhost Face
220 * @param controlParameters
221 * @return
222 * @throws Exception
223 */
224 public static boolean register(Face forwarder, ControlParameters controlParameters) throws Exception {
225 // build command name
226 Name command = new Name("/localhost/nfd/rib/register");
227 command.append(controlParameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800228
Andrew Brown211d2b62015-02-18 11:12:02 -0800229 // send the interest
230 return sendCommandAndErrorCheck(forwarder, new Interest(command));
231 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800232
Andrew Brown211d2b62015-02-18 11:12:02 -0800233 /**
234 * Register a route on a forwarder; this will create a new face on the
235 * forwarder to the given URI/route pair. See register(Face,
236 * ControlParameters) for more details documentation.
237 *
238 * @param forwarder Only a localhost Face
239 * @param uri
240 * @param cost
241 * @param route
242 * @return true for successful registration
243 * @throws java.lang.Exception
244 */
245 public static boolean register(Face forwarder, String uri, Name route, int cost) throws Exception {
246 // create the new face
247 int faceId = createFace(forwarder, uri);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800248
Andrew Brown211d2b62015-02-18 11:12:02 -0800249 // run base method
250 return register(forwarder, faceId, route, cost);
251 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800252
Andrew Brown211d2b62015-02-18 11:12:02 -0800253 /**
254 * Register a route on a forwarder; this will not create a new face since it
255 * is provided a faceId. See register(Face, ControlParameters) for full
256 * documentation
257 *
258 * @param forwarder Only a localhost Face
259 * @param faceId
260 * @param route
261 * @param cost
262 * @return true for successful registration
263 * @throws java.lang.Exception
264 */
265 public static boolean register(Face forwarder, int faceId, Name route, int cost) throws Exception {
266 // build command name
267 ControlParameters parameters = new ControlParameters();
268 parameters.setName(route);
269 parameters.setFaceId(faceId);
270 parameters.setCost(cost);
271 ForwardingFlags flags = new ForwardingFlags();
272 flags.setCapture(true);
273 flags.setChildInherit(true);
274 parameters.setForwardingFlags(flags);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800275
Andrew Brown211d2b62015-02-18 11:12:02 -0800276 // run base method
277 return register(forwarder, parameters);
278 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800279
Andrew Brown211d2b62015-02-18 11:12:02 -0800280 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800281 * Unregister a route on a forwarder; see
282 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
283 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
284 * protocol documentation. Ensure the forwarding face is on the local machine
285 * (management requests are to /localhost/...) and that command signing has
286 * been set up (e.g. forwarder.setCommandSigningInfo()
287 *
288 * @param forwarder
Andrew Brown07466442015-02-24 09:07:02 -0800289 * @param controlParameters
Andrew Brown63bed362015-02-18 11:28:50 -0800290 * @return
291 */
Andrew Brown07466442015-02-24 09:07:02 -0800292 public static boolean unregister(Face forwarder, ControlParameters controlParameters) throws Exception {
Andrew Brown63bed362015-02-18 11:28:50 -0800293 // build command name
294 Name command = new Name("/localhost/nfd/rib/unregister");
295 command.append(controlParameters.wireEncode());
296
297 // send the interest
298 return sendCommandAndErrorCheck(forwarder, new Interest(command));
299 }
300
301 /**
Andrew Brown07466442015-02-24 09:07:02 -0800302 * Unregister a route on a forwarder; see
303 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
304 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
305 * protocol documentation. Ensure the forwarding face is on the local machine
306 * (management requests are to /localhost/...) and that command signing has
307 * been set up (e.g. forwarder.setCommandSigningInfo()
308 *
309 * @param forwarder
310 * @param route
311 * @return
312 */
313 public static boolean unregister(Face forwarder, Name route) throws Exception {
314 // build command name
315 ControlParameters controlParameters = new ControlParameters();
316 controlParameters.setName(route);
317
318 // send the interest
319 return unregister(forwarder, controlParameters);
320 }
321
322 /**
323 * Unregister a route on a forwarder; see
324 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
325 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
326 * protocol documentation. Ensure the forwarding face is on the local machine
327 * (management requests are to /localhost/...) and that command signing has
328 * been set up (e.g. forwarder.setCommandSigningInfo()
329 *
330 * @param forwarder
331 * @param route
332 * @param faceId
333 * @return
334 */
335 public static boolean unregister(Face forwarder, Name route, int faceId) throws Exception {
336 // build command name
337 ControlParameters controlParameters = new ControlParameters();
338 controlParameters.setName(route);
339 controlParameters.setFaceId(faceId);
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 uri
356 * @return
357 */
358 public static boolean unregister(Face forwarder, Name route, String uri) throws Exception {
359 int faceId = -1;
360 for(FaceStatus face : getFaceList(forwarder)){
361 if(face.getUri().matches(uri)){
362 faceId = face.getFaceId();
363 break;
364 }
365 }
366
367 if(faceId == -1){
368 throw new Exception("Face not found: " + uri);
369 }
370
371 // send the interest
372 return unregister(forwarder, route, faceId);
373 }
374
375 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800376 * Set a strategy on the forwarder; see
377 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
378 * usage and http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
379 * for protocol documentation. Ensure the forwarding face is on the local
380 * machine (management requests are to /localhost/...) and that command
381 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
382 *
383 * @param forwarder Only a localhost Face
384 * @param prefix
385 * @param strategy
386 * @return true for successful command
387 * @throws Exception
388 */
389 public static boolean setStrategy(Face forwarder, Name prefix, Name strategy) throws Exception {
390 // build command name
391 Name command = new Name("/localhost/nfd/strategy-choice/set");
392 ControlParameters parameters = new ControlParameters();
393 parameters.setName(prefix);
394 parameters.setStrategy(strategy);
395 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800396
Andrew Brown211d2b62015-02-18 11:12:02 -0800397 // send the interest
398 return sendCommandAndErrorCheck(forwarder, new Interest(command));
399 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800400
Andrew Brown211d2b62015-02-18 11:12:02 -0800401 /**
402 * Send an interest as a command to the forwarder; this method will convert
403 * the interest to a command interest and block until a response is received
404 * from the forwarder. Ensure the forwarding face is on the local machine
405 * (management requests are to /localhost/...) and that command signing has
406 * been set up (e.g. forwarder.setCommandSigningInfo()).
407 *
408 * @param forwarder Only a localhost Face
409 * @param interest As described at
410 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
411 * requested interest must have encoded ControlParameters appended to the
412 * interest name
413 * @return
414 * @throws net.named_data.jndn.security.SecurityException
415 * @throws java.io.IOException
416 * @throws net.named_data.jndn.encoding.EncodingException
417 */
418 public static ControlResponse sendCommand(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
419 forwarder.makeCommandInterest(interest);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800420
Andrew Brown211d2b62015-02-18 11:12:02 -0800421 // send command packet
422 Data data = Client.getDefault().getSync(forwarder, interest);
423 if (data == null) {
424 throw new IOException("Failed to receive command response.");
425 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800426
Andrew Brown211d2b62015-02-18 11:12:02 -0800427 // return response
428 ControlResponse response = new ControlResponse();
429 response.wireDecode(data.getContent().buf());
430 return response;
431 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800432
Andrew Brown211d2b62015-02-18 11:12:02 -0800433 /**
434 * Send an interest as a command to the forwarder; this method will convert
435 * the interest to a command interest and block until a response is received
436 * from the forwarder.
437 *
438 * @param forwarder Only a localhost Face
439 * @param interest As described at
440 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
441 * requested interest must have encoded ControlParameters appended to the
442 * interest name
443 * @return
444 * @throws net.named_data.jndn.security.SecurityException
445 * @throws java.io.IOException
446 * @throws net.named_data.jndn.encoding.EncodingException
447 */
448 public static boolean sendCommandAndErrorCheck(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
449 ControlResponse response = sendCommand(forwarder, interest);
450 if (response.getStatusCode() < 400) {
451 return true;
452 } else {
453 logger.warning("Command sent but failed: " + response.getStatusCode() + " " + response.getStatusText());
454 return false;
455 }
456 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800457}